1 /*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: [email protected]
14 *
15 */
16
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21
22 #define IN_LIBXML
23 #include "libxml.h"
24
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <math.h>
29 #include <float.h>
30 #include <ctype.h>
31
32 #include <libxml/xmlmemory.h>
33 #include <libxml/tree.h>
34 #include <libxml/xpath.h>
35 #include <libxml/xpathInternals.h>
36 #include <libxml/parserInternals.h>
37 #include <libxml/hash.h>
38 #ifdef LIBXML_DEBUG_ENABLED
39 #include <libxml/debugXML.h>
40 #endif
41 #include <libxml/xmlerror.h>
42 #include <libxml/threads.h>
43 #ifdef LIBXML_PATTERN_ENABLED
44 #include <libxml/pattern.h>
45 #endif
46
47 #include "private/buf.h"
48 #include "private/error.h"
49 #include "private/xpath.h"
50
51 /* Disabled for now */
52 #if 0
53 #ifdef LIBXML_PATTERN_ENABLED
54 #define XPATH_STREAMING
55 #endif
56 #endif
57
58 /**
59 * WITH_TIM_SORT:
60 *
61 * Use the Timsort algorithm provided in timsort.h to sort
62 * nodeset as this is a great improvement over the old Shell sort
63 * used in xmlXPathNodeSetSort()
64 */
65 #define WITH_TIM_SORT
66
67 /*
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
75 */
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78 /*
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
82 */
83 #define XP_OPTIMIZED_FILTER_FIRST
84
85 /*
86 * XPATH_MAX_STEPS:
87 * when compiling an XPath expression we arbitrary limit the maximum
88 * number of step operation in the compiled expression. 1000000 is
89 * an insanely large value which should never be reached under normal
90 * circumstances
91 */
92 #define XPATH_MAX_STEPS 1000000
93
94 /*
95 * XPATH_MAX_STACK_DEPTH:
96 * when evaluating an XPath expression we arbitrary limit the maximum
97 * number of object allowed to be pushed on the stack. 1000000 is
98 * an insanely large value which should never be reached under normal
99 * circumstances
100 */
101 #define XPATH_MAX_STACK_DEPTH 1000000
102
103 /*
104 * XPATH_MAX_NODESET_LENGTH:
105 * when evaluating an XPath expression nodesets are created and we
106 * arbitrary limit the maximum length of those node set. 10000000 is
107 * an insanely large value which should never be reached under normal
108 * circumstances, one would first need to construct an in memory tree
109 * with more than 10 millions nodes.
110 */
111 #define XPATH_MAX_NODESET_LENGTH 10000000
112
113 /*
114 * XPATH_MAX_RECRUSION_DEPTH:
115 * Maximum amount of nested functions calls when parsing or evaluating
116 * expressions
117 */
118 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
119 #define XPATH_MAX_RECURSION_DEPTH 500
120 #elif defined(_WIN32)
121 /* Windows typically limits stack size to 1MB. */
122 #define XPATH_MAX_RECURSION_DEPTH 1000
123 #else
124 #define XPATH_MAX_RECURSION_DEPTH 5000
125 #endif
126
127 /*
128 * TODO:
129 * There are a few spots where some tests are done which depend upon ascii
130 * data. These should be enhanced for full UTF8 support (see particularly
131 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
132 */
133
134 #if defined(LIBXML_XPATH_ENABLED)
135
136 /************************************************************************
137 * *
138 * Floating point stuff *
139 * *
140 ************************************************************************/
141
142 double xmlXPathNAN = 0.0;
143 double xmlXPathPINF = 0.0;
144 double xmlXPathNINF = 0.0;
145
146 /**
147 * xmlXPathInit:
148 *
149 * DEPRECATED: Alias for xmlInitParser.
150 */
151 void
xmlXPathInit(void)152 xmlXPathInit(void) {
153 xmlInitParser();
154 }
155
156 /**
157 * xmlInitXPathInternal:
158 *
159 * Initialize the XPath environment
160 */
161 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
162 void
xmlInitXPathInternal(void)163 xmlInitXPathInternal(void) {
164 #if defined(NAN) && defined(INFINITY)
165 xmlXPathNAN = NAN;
166 xmlXPathPINF = INFINITY;
167 xmlXPathNINF = -INFINITY;
168 #else
169 /* MSVC doesn't allow division by zero in constant expressions. */
170 double zero = 0.0;
171 xmlXPathNAN = 0.0 / zero;
172 xmlXPathPINF = 1.0 / zero;
173 xmlXPathNINF = -xmlXPathPINF;
174 #endif
175 }
176
177 /**
178 * xmlXPathIsNaN:
179 * @val: a double value
180 *
181 * Checks whether a double is a NaN.
182 *
183 * Returns 1 if the value is a NaN, 0 otherwise
184 */
185 int
xmlXPathIsNaN(double val)186 xmlXPathIsNaN(double val) {
187 #ifdef isnan
188 return isnan(val);
189 #else
190 return !(val == val);
191 #endif
192 }
193
194 /**
195 * xmlXPathIsInf:
196 * @val: a double value
197 *
198 * Checks whether a double is an infinity.
199 *
200 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
201 */
202 int
xmlXPathIsInf(double val)203 xmlXPathIsInf(double val) {
204 #ifdef isinf
205 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
206 #else
207 if (val >= xmlXPathPINF)
208 return 1;
209 if (val <= -xmlXPathPINF)
210 return -1;
211 return 0;
212 #endif
213 }
214
215 /*
216 * TODO: when compatibility allows remove all "fake node libxslt" strings
217 * the test should just be name[0] = ' '
218 */
219
220 static const xmlNs xmlXPathXMLNamespaceStruct = {
221 NULL,
222 XML_NAMESPACE_DECL,
223 XML_XML_NAMESPACE,
224 BAD_CAST "xml",
225 NULL,
226 NULL
227 };
228 static const xmlNs *const xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
229
230 static void
231 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
232
233 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
234 /**
235 * xmlXPathCmpNodesExt:
236 * @node1: the first node
237 * @node2: the second node
238 *
239 * Compare two nodes w.r.t document order.
240 * This one is optimized for handling of non-element nodes.
241 *
242 * Returns -2 in case of error 1 if first point < second point, 0 if
243 * it's the same node, -1 otherwise
244 */
245 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)246 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
247 int depth1, depth2;
248 int misc = 0, precedence1 = 0, precedence2 = 0;
249 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
250 xmlNodePtr cur, root;
251 ptrdiff_t l1, l2;
252
253 if ((node1 == NULL) || (node2 == NULL))
254 return(-2);
255
256 if (node1 == node2)
257 return(0);
258
259 /*
260 * a couple of optimizations which will avoid computations in most cases
261 */
262 switch (node1->type) {
263 case XML_ELEMENT_NODE:
264 if (node2->type == XML_ELEMENT_NODE) {
265 if ((0 > (ptrdiff_t) node1->content) &&
266 (0 > (ptrdiff_t) node2->content) &&
267 (node1->doc == node2->doc))
268 {
269 l1 = -((ptrdiff_t) node1->content);
270 l2 = -((ptrdiff_t) node2->content);
271 if (l1 < l2)
272 return(1);
273 if (l1 > l2)
274 return(-1);
275 } else
276 goto turtle_comparison;
277 }
278 break;
279 case XML_ATTRIBUTE_NODE:
280 precedence1 = 1; /* element is owner */
281 miscNode1 = node1;
282 node1 = node1->parent;
283 misc = 1;
284 break;
285 case XML_TEXT_NODE:
286 case XML_CDATA_SECTION_NODE:
287 case XML_COMMENT_NODE:
288 case XML_PI_NODE: {
289 miscNode1 = node1;
290 /*
291 * Find nearest element node.
292 */
293 if (node1->prev != NULL) {
294 do {
295 node1 = node1->prev;
296 if (node1->type == XML_ELEMENT_NODE) {
297 precedence1 = 3; /* element in prev-sibl axis */
298 break;
299 }
300 if (node1->prev == NULL) {
301 precedence1 = 2; /* element is parent */
302 /*
303 * URGENT TODO: Are there any cases, where the
304 * parent of such a node is not an element node?
305 */
306 node1 = node1->parent;
307 break;
308 }
309 } while (1);
310 } else {
311 precedence1 = 2; /* element is parent */
312 node1 = node1->parent;
313 }
314 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
315 (0 <= (ptrdiff_t) node1->content)) {
316 /*
317 * Fallback for whatever case.
318 */
319 node1 = miscNode1;
320 precedence1 = 0;
321 } else
322 misc = 1;
323 }
324 break;
325 case XML_NAMESPACE_DECL:
326 /*
327 * TODO: why do we return 1 for namespace nodes?
328 */
329 return(1);
330 default:
331 break;
332 }
333 switch (node2->type) {
334 case XML_ELEMENT_NODE:
335 break;
336 case XML_ATTRIBUTE_NODE:
337 precedence2 = 1; /* element is owner */
338 miscNode2 = node2;
339 node2 = node2->parent;
340 misc = 1;
341 break;
342 case XML_TEXT_NODE:
343 case XML_CDATA_SECTION_NODE:
344 case XML_COMMENT_NODE:
345 case XML_PI_NODE: {
346 miscNode2 = node2;
347 if (node2->prev != NULL) {
348 do {
349 node2 = node2->prev;
350 if (node2->type == XML_ELEMENT_NODE) {
351 precedence2 = 3; /* element in prev-sibl axis */
352 break;
353 }
354 if (node2->prev == NULL) {
355 precedence2 = 2; /* element is parent */
356 node2 = node2->parent;
357 break;
358 }
359 } while (1);
360 } else {
361 precedence2 = 2; /* element is parent */
362 node2 = node2->parent;
363 }
364 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
365 (0 <= (ptrdiff_t) node2->content))
366 {
367 node2 = miscNode2;
368 precedence2 = 0;
369 } else
370 misc = 1;
371 }
372 break;
373 case XML_NAMESPACE_DECL:
374 return(1);
375 default:
376 break;
377 }
378 if (misc) {
379 if (node1 == node2) {
380 if (precedence1 == precedence2) {
381 /*
382 * The ugly case; but normally there aren't many
383 * adjacent non-element nodes around.
384 */
385 cur = miscNode2->prev;
386 while (cur != NULL) {
387 if (cur == miscNode1)
388 return(1);
389 if (cur->type == XML_ELEMENT_NODE)
390 return(-1);
391 cur = cur->prev;
392 }
393 return (-1);
394 } else {
395 /*
396 * Evaluate based on higher precedence wrt to the element.
397 * TODO: This assumes attributes are sorted before content.
398 * Is this 100% correct?
399 */
400 if (precedence1 < precedence2)
401 return(1);
402 else
403 return(-1);
404 }
405 }
406 /*
407 * Special case: One of the helper-elements is contained by the other.
408 * <foo>
409 * <node2>
410 * <node1>Text-1(precedence1 == 2)</node1>
411 * </node2>
412 * Text-6(precedence2 == 3)
413 * </foo>
414 */
415 if ((precedence2 == 3) && (precedence1 > 1)) {
416 cur = node1->parent;
417 while (cur) {
418 if (cur == node2)
419 return(1);
420 cur = cur->parent;
421 }
422 }
423 if ((precedence1 == 3) && (precedence2 > 1)) {
424 cur = node2->parent;
425 while (cur) {
426 if (cur == node1)
427 return(-1);
428 cur = cur->parent;
429 }
430 }
431 }
432
433 /*
434 * Speedup using document order if available.
435 */
436 if ((node1->type == XML_ELEMENT_NODE) &&
437 (node2->type == XML_ELEMENT_NODE) &&
438 (0 > (ptrdiff_t) node1->content) &&
439 (0 > (ptrdiff_t) node2->content) &&
440 (node1->doc == node2->doc)) {
441
442 l1 = -((ptrdiff_t) node1->content);
443 l2 = -((ptrdiff_t) node2->content);
444 if (l1 < l2)
445 return(1);
446 if (l1 > l2)
447 return(-1);
448 }
449
450 turtle_comparison:
451
452 if (node1 == node2->prev)
453 return(1);
454 if (node1 == node2->next)
455 return(-1);
456 /*
457 * compute depth to root
458 */
459 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
460 if (cur->parent == node1)
461 return(1);
462 depth2++;
463 }
464 root = cur;
465 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
466 if (cur->parent == node2)
467 return(-1);
468 depth1++;
469 }
470 /*
471 * Distinct document (or distinct entities :-( ) case.
472 */
473 if (root != cur) {
474 return(-2);
475 }
476 /*
477 * get the nearest common ancestor.
478 */
479 while (depth1 > depth2) {
480 depth1--;
481 node1 = node1->parent;
482 }
483 while (depth2 > depth1) {
484 depth2--;
485 node2 = node2->parent;
486 }
487 while (node1->parent != node2->parent) {
488 node1 = node1->parent;
489 node2 = node2->parent;
490 /* should not happen but just in case ... */
491 if ((node1 == NULL) || (node2 == NULL))
492 return(-2);
493 }
494 /*
495 * Find who's first.
496 */
497 if (node1 == node2->prev)
498 return(1);
499 if (node1 == node2->next)
500 return(-1);
501 /*
502 * Speedup using document order if available.
503 */
504 if ((node1->type == XML_ELEMENT_NODE) &&
505 (node2->type == XML_ELEMENT_NODE) &&
506 (0 > (ptrdiff_t) node1->content) &&
507 (0 > (ptrdiff_t) node2->content) &&
508 (node1->doc == node2->doc)) {
509
510 l1 = -((ptrdiff_t) node1->content);
511 l2 = -((ptrdiff_t) node2->content);
512 if (l1 < l2)
513 return(1);
514 if (l1 > l2)
515 return(-1);
516 }
517
518 for (cur = node1->next;cur != NULL;cur = cur->next)
519 if (cur == node2)
520 return(1);
521 return(-1); /* assume there is no sibling list corruption */
522 }
523 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
524
525 /*
526 * Wrapper for the Timsort algorithm from timsort.h
527 */
528 #ifdef WITH_TIM_SORT
529 #define SORT_NAME libxml_domnode
530 #define SORT_TYPE xmlNodePtr
531 /**
532 * wrap_cmp:
533 * @x: a node
534 * @y: another node
535 *
536 * Comparison function for the Timsort implementation
537 *
538 * Returns -2 in case of error -1 if first point < second point, 0 if
539 * it's the same node, +1 otherwise
540 */
541 static
542 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
543 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)544 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
545 {
546 int res = xmlXPathCmpNodesExt(x, y);
547 return res == -2 ? res : -res;
548 }
549 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)550 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
551 {
552 int res = xmlXPathCmpNodes(x, y);
553 return res == -2 ? res : -res;
554 }
555 #endif
556 #define SORT_CMP(x, y) (wrap_cmp(x, y))
557 #include "timsort.h"
558 #endif /* WITH_TIM_SORT */
559
560 /************************************************************************
561 * *
562 * Error handling routines *
563 * *
564 ************************************************************************/
565
566 /**
567 * XP_ERRORNULL:
568 * @X: the error code
569 *
570 * Macro to raise an XPath error and return NULL.
571 */
572 #define XP_ERRORNULL(X) \
573 { xmlXPathErr(ctxt, X); return(NULL); }
574
575 /*
576 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
577 */
578 static const char* const xmlXPathErrorMessages[] = {
579 "Ok\n",
580 "Number encoding\n",
581 "Unfinished literal\n",
582 "Start of literal\n",
583 "Expected $ for variable reference\n",
584 "Undefined variable\n",
585 "Invalid predicate\n",
586 "Invalid expression\n",
587 "Missing closing curly brace\n",
588 "Unregistered function\n",
589 "Invalid operand\n",
590 "Invalid type\n",
591 "Invalid number of arguments\n",
592 "Invalid context size\n",
593 "Invalid context position\n",
594 "Memory allocation error\n",
595 "Syntax error\n",
596 "Resource error\n",
597 "Sub resource error\n",
598 "Undefined namespace prefix\n",
599 "Encoding error\n",
600 "Char out of XML range\n",
601 "Invalid or incomplete context\n",
602 "Stack usage error\n",
603 "Forbidden variable\n",
604 "Operation limit exceeded\n",
605 "Recursion limit exceeded\n",
606 "?? Unknown error ??\n" /* Must be last in the list! */
607 };
608 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
609 sizeof(xmlXPathErrorMessages[0])) - 1)
610 /**
611 * xmlXPathErrMemory:
612 * @ctxt: an XPath context
613 *
614 * Handle a memory allocation failure.
615 */
616 void
xmlXPathErrMemory(xmlXPathContextPtr ctxt)617 xmlXPathErrMemory(xmlXPathContextPtr ctxt)
618 {
619 if (ctxt == NULL)
620 return;
621 xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
622 &ctxt->lastError);
623 }
624
625 /**
626 * xmlXPathPErrMemory:
627 * @ctxt: an XPath parser context
628 *
629 * Handle a memory allocation failure.
630 */
631 void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)632 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
633 {
634 if (ctxt == NULL)
635 return;
636 ctxt->error = XPATH_MEMORY_ERROR;
637 xmlXPathErrMemory(ctxt->context);
638 }
639
640 /**
641 * xmlXPathErr:
642 * @ctxt: a XPath parser context
643 * @code: the error code
644 *
645 * Handle an XPath error
646 */
647 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int code)648 xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
649 {
650 xmlStructuredErrorFunc schannel = NULL;
651 xmlGenericErrorFunc channel = NULL;
652 void *data = NULL;
653 xmlNodePtr node = NULL;
654 int res;
655
656 if (ctxt == NULL)
657 return;
658 if ((code < 0) || (code > MAXERRNO))
659 code = MAXERRNO;
660 /* Only report the first error */
661 if (ctxt->error != 0)
662 return;
663
664 ctxt->error = code;
665
666 if (ctxt->context != NULL) {
667 xmlErrorPtr err = &ctxt->context->lastError;
668
669 /* Don't overwrite memory error. */
670 if (err->code == XML_ERR_NO_MEMORY)
671 return;
672
673 /* cleanup current last error */
674 xmlResetError(err);
675
676 err->domain = XML_FROM_XPATH;
677 err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
678 err->level = XML_ERR_ERROR;
679 if (ctxt->base != NULL) {
680 err->str1 = (char *) xmlStrdup(ctxt->base);
681 if (err->str1 == NULL) {
682 xmlXPathPErrMemory(ctxt);
683 return;
684 }
685 }
686 err->int1 = ctxt->cur - ctxt->base;
687 err->node = ctxt->context->debugNode;
688
689 schannel = ctxt->context->error;
690 data = ctxt->context->userData;
691 node = ctxt->context->debugNode;
692 }
693
694 if (schannel == NULL) {
695 channel = xmlGenericError;
696 data = xmlGenericErrorContext;
697 }
698
699 res = xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
700 code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
701 XML_ERR_ERROR, NULL, 0,
702 (const char *) ctxt->base, NULL, NULL,
703 ctxt->cur - ctxt->base, 0,
704 "%s", xmlXPathErrorMessages[code]);
705 if (res < 0)
706 xmlXPathPErrMemory(ctxt);
707 }
708
709 /**
710 * xmlXPatherror:
711 * @ctxt: the XPath Parser context
712 * @file: the file name
713 * @line: the line number
714 * @no: the error number
715 *
716 * Formats an error message.
717 */
718 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)719 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
720 int line ATTRIBUTE_UNUSED, int no) {
721 xmlXPathErr(ctxt, no);
722 }
723
724 /**
725 * xmlXPathCheckOpLimit:
726 * @ctxt: the XPath Parser context
727 * @opCount: the number of operations to be added
728 *
729 * Adds opCount to the running total of operations and returns -1 if the
730 * operation limit is exceeded. Returns 0 otherwise.
731 */
732 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)733 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
734 xmlXPathContextPtr xpctxt = ctxt->context;
735
736 if ((opCount > xpctxt->opLimit) ||
737 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
738 xpctxt->opCount = xpctxt->opLimit;
739 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
740 return(-1);
741 }
742
743 xpctxt->opCount += opCount;
744 return(0);
745 }
746
747 #define OP_LIMIT_EXCEEDED(ctxt, n) \
748 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
749
750 /************************************************************************
751 * *
752 * Parser Types *
753 * *
754 ************************************************************************/
755
756 /*
757 * Types are private:
758 */
759
760 typedef enum {
761 XPATH_OP_END=0,
762 XPATH_OP_AND,
763 XPATH_OP_OR,
764 XPATH_OP_EQUAL,
765 XPATH_OP_CMP,
766 XPATH_OP_PLUS,
767 XPATH_OP_MULT,
768 XPATH_OP_UNION,
769 XPATH_OP_ROOT,
770 XPATH_OP_NODE,
771 XPATH_OP_COLLECT,
772 XPATH_OP_VALUE, /* 11 */
773 XPATH_OP_VARIABLE,
774 XPATH_OP_FUNCTION,
775 XPATH_OP_ARG,
776 XPATH_OP_PREDICATE,
777 XPATH_OP_FILTER, /* 16 */
778 XPATH_OP_SORT /* 17 */
779 } xmlXPathOp;
780
781 typedef enum {
782 AXIS_ANCESTOR = 1,
783 AXIS_ANCESTOR_OR_SELF,
784 AXIS_ATTRIBUTE,
785 AXIS_CHILD,
786 AXIS_DESCENDANT,
787 AXIS_DESCENDANT_OR_SELF,
788 AXIS_FOLLOWING,
789 AXIS_FOLLOWING_SIBLING,
790 AXIS_NAMESPACE,
791 AXIS_PARENT,
792 AXIS_PRECEDING,
793 AXIS_PRECEDING_SIBLING,
794 AXIS_SELF
795 } xmlXPathAxisVal;
796
797 typedef enum {
798 NODE_TEST_NONE = 0,
799 NODE_TEST_TYPE = 1,
800 NODE_TEST_PI = 2,
801 NODE_TEST_ALL = 3,
802 NODE_TEST_NS = 4,
803 NODE_TEST_NAME = 5
804 } xmlXPathTestVal;
805
806 typedef enum {
807 NODE_TYPE_NODE = 0,
808 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
809 NODE_TYPE_TEXT = XML_TEXT_NODE,
810 NODE_TYPE_PI = XML_PI_NODE
811 } xmlXPathTypeVal;
812
813 typedef struct _xmlXPathStepOp xmlXPathStepOp;
814 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
815 struct _xmlXPathStepOp {
816 xmlXPathOp op; /* The identifier of the operation */
817 int ch1; /* First child */
818 int ch2; /* Second child */
819 int value;
820 int value2;
821 int value3;
822 void *value4;
823 void *value5;
824 xmlXPathFunction cache;
825 void *cacheURI;
826 };
827
828 struct _xmlXPathCompExpr {
829 int nbStep; /* Number of steps in this expression */
830 int maxStep; /* Maximum number of steps allocated */
831 xmlXPathStepOp *steps; /* ops for computation of this expression */
832 int last; /* index of last step in expression */
833 xmlChar *expr; /* the expression being computed */
834 xmlDictPtr dict; /* the dictionary to use if any */
835 #ifdef XPATH_STREAMING
836 xmlPatternPtr stream;
837 #endif
838 };
839
840 /************************************************************************
841 * *
842 * Forward declarations *
843 * *
844 ************************************************************************/
845
846 static void
847 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
848 static int
849 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
850 xmlXPathStepOpPtr op, xmlNodePtr *first);
851 static int
852 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
853 xmlXPathStepOpPtr op,
854 int isPredicate);
855 static void
856 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
857
858 /************************************************************************
859 * *
860 * Parser Type functions *
861 * *
862 ************************************************************************/
863
864 /**
865 * xmlXPathNewCompExpr:
866 *
867 * Create a new Xpath component
868 *
869 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
870 */
871 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)872 xmlXPathNewCompExpr(void) {
873 xmlXPathCompExprPtr cur;
874
875 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
876 if (cur == NULL)
877 return(NULL);
878 memset(cur, 0, sizeof(xmlXPathCompExpr));
879 cur->maxStep = 10;
880 cur->nbStep = 0;
881 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
882 sizeof(xmlXPathStepOp));
883 if (cur->steps == NULL) {
884 xmlFree(cur);
885 return(NULL);
886 }
887 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
888 cur->last = -1;
889 return(cur);
890 }
891
892 /**
893 * xmlXPathFreeCompExpr:
894 * @comp: an XPATH comp
895 *
896 * Free up the memory allocated by @comp
897 */
898 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)899 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
900 {
901 xmlXPathStepOpPtr op;
902 int i;
903
904 if (comp == NULL)
905 return;
906 if (comp->dict == NULL) {
907 for (i = 0; i < comp->nbStep; i++) {
908 op = &comp->steps[i];
909 if (op->value4 != NULL) {
910 if (op->op == XPATH_OP_VALUE)
911 xmlXPathFreeObject(op->value4);
912 else
913 xmlFree(op->value4);
914 }
915 if (op->value5 != NULL)
916 xmlFree(op->value5);
917 }
918 } else {
919 for (i = 0; i < comp->nbStep; i++) {
920 op = &comp->steps[i];
921 if (op->value4 != NULL) {
922 if (op->op == XPATH_OP_VALUE)
923 xmlXPathFreeObject(op->value4);
924 }
925 }
926 xmlDictFree(comp->dict);
927 }
928 if (comp->steps != NULL) {
929 xmlFree(comp->steps);
930 }
931 #ifdef XPATH_STREAMING
932 if (comp->stream != NULL) {
933 xmlFreePatternList(comp->stream);
934 }
935 #endif
936 if (comp->expr != NULL) {
937 xmlFree(comp->expr);
938 }
939
940 xmlFree(comp);
941 }
942
943 /**
944 * xmlXPathCompExprAdd:
945 * @comp: the compiled expression
946 * @ch1: first child index
947 * @ch2: second child index
948 * @op: an op
949 * @value: the first int value
950 * @value2: the second int value
951 * @value3: the third int value
952 * @value4: the first string value
953 * @value5: the second string value
954 *
955 * Add a step to an XPath Compiled Expression
956 *
957 * Returns -1 in case of failure, the index otherwise
958 */
959 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)960 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
961 xmlXPathOp op, int value,
962 int value2, int value3, void *value4, void *value5) {
963 xmlXPathCompExprPtr comp = ctxt->comp;
964 if (comp->nbStep >= comp->maxStep) {
965 xmlXPathStepOp *real;
966
967 if (comp->maxStep >= XPATH_MAX_STEPS) {
968 xmlXPathPErrMemory(ctxt);
969 return(-1);
970 }
971 comp->maxStep *= 2;
972 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
973 comp->maxStep * sizeof(xmlXPathStepOp));
974 if (real == NULL) {
975 comp->maxStep /= 2;
976 xmlXPathPErrMemory(ctxt);
977 return(-1);
978 }
979 comp->steps = real;
980 }
981 comp->last = comp->nbStep;
982 comp->steps[comp->nbStep].ch1 = ch1;
983 comp->steps[comp->nbStep].ch2 = ch2;
984 comp->steps[comp->nbStep].op = op;
985 comp->steps[comp->nbStep].value = value;
986 comp->steps[comp->nbStep].value2 = value2;
987 comp->steps[comp->nbStep].value3 = value3;
988 if ((comp->dict != NULL) &&
989 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
990 (op == XPATH_OP_COLLECT))) {
991 if (value4 != NULL) {
992 comp->steps[comp->nbStep].value4 = (xmlChar *)
993 (void *)xmlDictLookup(comp->dict, value4, -1);
994 xmlFree(value4);
995 } else
996 comp->steps[comp->nbStep].value4 = NULL;
997 if (value5 != NULL) {
998 comp->steps[comp->nbStep].value5 = (xmlChar *)
999 (void *)xmlDictLookup(comp->dict, value5, -1);
1000 xmlFree(value5);
1001 } else
1002 comp->steps[comp->nbStep].value5 = NULL;
1003 } else {
1004 comp->steps[comp->nbStep].value4 = value4;
1005 comp->steps[comp->nbStep].value5 = value5;
1006 }
1007 comp->steps[comp->nbStep].cache = NULL;
1008 return(comp->nbStep++);
1009 }
1010
1011 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1012 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1013 (op), (val), (val2), (val3), (val4), (val5))
1014 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1015 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1016 (op), (val), (val2), (val3), (val4), (val5))
1017
1018 #define PUSH_LEAVE_EXPR(op, val, val2) \
1019 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1020
1021 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1022 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1023
1024 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1025 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1026 (val), (val2), 0 ,NULL ,NULL)
1027
1028 /************************************************************************
1029 * *
1030 * XPath object cache structures *
1031 * *
1032 ************************************************************************/
1033
1034 /* #define XP_DEFAULT_CACHE_ON */
1035
1036 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1037 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1038 struct _xmlXPathContextCache {
1039 xmlXPathObjectPtr nodesetObjs; /* stringval points to next */
1040 xmlXPathObjectPtr miscObjs; /* stringval points to next */
1041 int numNodeset;
1042 int maxNodeset;
1043 int numMisc;
1044 int maxMisc;
1045 };
1046
1047 /************************************************************************
1048 * *
1049 * Debugging related functions *
1050 * *
1051 ************************************************************************/
1052
1053 #ifdef LIBXML_DEBUG_ENABLED
1054 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1055 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1056 int i;
1057 char shift[100];
1058
1059 for (i = 0;((i < depth) && (i < 25));i++)
1060 shift[2 * i] = shift[2 * i + 1] = ' ';
1061 shift[2 * i] = shift[2 * i + 1] = 0;
1062 if (cur == NULL) {
1063 fprintf(output, "%s", shift);
1064 fprintf(output, "Node is NULL !\n");
1065 return;
1066
1067 }
1068
1069 if ((cur->type == XML_DOCUMENT_NODE) ||
1070 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1071 fprintf(output, "%s", shift);
1072 fprintf(output, " /\n");
1073 } else if (cur->type == XML_ATTRIBUTE_NODE)
1074 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1075 else
1076 xmlDebugDumpOneNode(output, cur, depth);
1077 }
1078 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1079 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1080 xmlNodePtr tmp;
1081 int i;
1082 char shift[100];
1083
1084 for (i = 0;((i < depth) && (i < 25));i++)
1085 shift[2 * i] = shift[2 * i + 1] = ' ';
1086 shift[2 * i] = shift[2 * i + 1] = 0;
1087 if (cur == NULL) {
1088 fprintf(output, "%s", shift);
1089 fprintf(output, "Node is NULL !\n");
1090 return;
1091
1092 }
1093
1094 while (cur != NULL) {
1095 tmp = cur;
1096 cur = cur->next;
1097 xmlDebugDumpOneNode(output, tmp, depth);
1098 }
1099 }
1100
1101 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1102 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1103 int i;
1104 char shift[100];
1105
1106 for (i = 0;((i < depth) && (i < 25));i++)
1107 shift[2 * i] = shift[2 * i + 1] = ' ';
1108 shift[2 * i] = shift[2 * i + 1] = 0;
1109
1110 if (cur == NULL) {
1111 fprintf(output, "%s", shift);
1112 fprintf(output, "NodeSet is NULL !\n");
1113 return;
1114
1115 }
1116
1117 if (cur != NULL) {
1118 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1119 for (i = 0;i < cur->nodeNr;i++) {
1120 fprintf(output, "%s", shift);
1121 fprintf(output, "%d", i + 1);
1122 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1123 }
1124 }
1125 }
1126
1127 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1128 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1129 int i;
1130 char shift[100];
1131
1132 for (i = 0;((i < depth) && (i < 25));i++)
1133 shift[2 * i] = shift[2 * i + 1] = ' ';
1134 shift[2 * i] = shift[2 * i + 1] = 0;
1135
1136 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1137 fprintf(output, "%s", shift);
1138 fprintf(output, "Value Tree is NULL !\n");
1139 return;
1140
1141 }
1142
1143 fprintf(output, "%s", shift);
1144 fprintf(output, "%d", i + 1);
1145 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1146 }
1147
1148 /**
1149 * xmlXPathDebugDumpObject:
1150 * @output: the FILE * to dump the output
1151 * @cur: the object to inspect
1152 * @depth: indentation level
1153 *
1154 * Dump the content of the object for debugging purposes
1155 */
1156 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1157 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1158 int i;
1159 char shift[100];
1160
1161 if (output == NULL) return;
1162
1163 for (i = 0;((i < depth) && (i < 25));i++)
1164 shift[2 * i] = shift[2 * i + 1] = ' ';
1165 shift[2 * i] = shift[2 * i + 1] = 0;
1166
1167
1168 fprintf(output, "%s", shift);
1169
1170 if (cur == NULL) {
1171 fprintf(output, "Object is empty (NULL)\n");
1172 return;
1173 }
1174 switch(cur->type) {
1175 case XPATH_UNDEFINED:
1176 fprintf(output, "Object is uninitialized\n");
1177 break;
1178 case XPATH_NODESET:
1179 fprintf(output, "Object is a Node Set :\n");
1180 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1181 break;
1182 case XPATH_XSLT_TREE:
1183 fprintf(output, "Object is an XSLT value tree :\n");
1184 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1185 break;
1186 case XPATH_BOOLEAN:
1187 fprintf(output, "Object is a Boolean : ");
1188 if (cur->boolval) fprintf(output, "true\n");
1189 else fprintf(output, "false\n");
1190 break;
1191 case XPATH_NUMBER:
1192 switch (xmlXPathIsInf(cur->floatval)) {
1193 case 1:
1194 fprintf(output, "Object is a number : Infinity\n");
1195 break;
1196 case -1:
1197 fprintf(output, "Object is a number : -Infinity\n");
1198 break;
1199 default:
1200 if (xmlXPathIsNaN(cur->floatval)) {
1201 fprintf(output, "Object is a number : NaN\n");
1202 } else if (cur->floatval == 0) {
1203 /* Omit sign for negative zero. */
1204 fprintf(output, "Object is a number : 0\n");
1205 } else {
1206 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1207 }
1208 }
1209 break;
1210 case XPATH_STRING:
1211 fprintf(output, "Object is a string : ");
1212 xmlDebugDumpString(output, cur->stringval);
1213 fprintf(output, "\n");
1214 break;
1215 case XPATH_USERS:
1216 fprintf(output, "Object is user defined\n");
1217 break;
1218 }
1219 }
1220
1221 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1222 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1223 xmlXPathStepOpPtr op, int depth) {
1224 int i;
1225 char shift[100];
1226
1227 for (i = 0;((i < depth) && (i < 25));i++)
1228 shift[2 * i] = shift[2 * i + 1] = ' ';
1229 shift[2 * i] = shift[2 * i + 1] = 0;
1230
1231 fprintf(output, "%s", shift);
1232 if (op == NULL) {
1233 fprintf(output, "Step is NULL\n");
1234 return;
1235 }
1236 switch (op->op) {
1237 case XPATH_OP_END:
1238 fprintf(output, "END"); break;
1239 case XPATH_OP_AND:
1240 fprintf(output, "AND"); break;
1241 case XPATH_OP_OR:
1242 fprintf(output, "OR"); break;
1243 case XPATH_OP_EQUAL:
1244 if (op->value)
1245 fprintf(output, "EQUAL =");
1246 else
1247 fprintf(output, "EQUAL !=");
1248 break;
1249 case XPATH_OP_CMP:
1250 if (op->value)
1251 fprintf(output, "CMP <");
1252 else
1253 fprintf(output, "CMP >");
1254 if (!op->value2)
1255 fprintf(output, "=");
1256 break;
1257 case XPATH_OP_PLUS:
1258 if (op->value == 0)
1259 fprintf(output, "PLUS -");
1260 else if (op->value == 1)
1261 fprintf(output, "PLUS +");
1262 else if (op->value == 2)
1263 fprintf(output, "PLUS unary -");
1264 else if (op->value == 3)
1265 fprintf(output, "PLUS unary - -");
1266 break;
1267 case XPATH_OP_MULT:
1268 if (op->value == 0)
1269 fprintf(output, "MULT *");
1270 else if (op->value == 1)
1271 fprintf(output, "MULT div");
1272 else
1273 fprintf(output, "MULT mod");
1274 break;
1275 case XPATH_OP_UNION:
1276 fprintf(output, "UNION"); break;
1277 case XPATH_OP_ROOT:
1278 fprintf(output, "ROOT"); break;
1279 case XPATH_OP_NODE:
1280 fprintf(output, "NODE"); break;
1281 case XPATH_OP_SORT:
1282 fprintf(output, "SORT"); break;
1283 case XPATH_OP_COLLECT: {
1284 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1285 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1286 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1287 const xmlChar *prefix = op->value4;
1288 const xmlChar *name = op->value5;
1289
1290 fprintf(output, "COLLECT ");
1291 switch (axis) {
1292 case AXIS_ANCESTOR:
1293 fprintf(output, " 'ancestors' "); break;
1294 case AXIS_ANCESTOR_OR_SELF:
1295 fprintf(output, " 'ancestors-or-self' "); break;
1296 case AXIS_ATTRIBUTE:
1297 fprintf(output, " 'attributes' "); break;
1298 case AXIS_CHILD:
1299 fprintf(output, " 'child' "); break;
1300 case AXIS_DESCENDANT:
1301 fprintf(output, " 'descendant' "); break;
1302 case AXIS_DESCENDANT_OR_SELF:
1303 fprintf(output, " 'descendant-or-self' "); break;
1304 case AXIS_FOLLOWING:
1305 fprintf(output, " 'following' "); break;
1306 case AXIS_FOLLOWING_SIBLING:
1307 fprintf(output, " 'following-siblings' "); break;
1308 case AXIS_NAMESPACE:
1309 fprintf(output, " 'namespace' "); break;
1310 case AXIS_PARENT:
1311 fprintf(output, " 'parent' "); break;
1312 case AXIS_PRECEDING:
1313 fprintf(output, " 'preceding' "); break;
1314 case AXIS_PRECEDING_SIBLING:
1315 fprintf(output, " 'preceding-sibling' "); break;
1316 case AXIS_SELF:
1317 fprintf(output, " 'self' "); break;
1318 }
1319 switch (test) {
1320 case NODE_TEST_NONE:
1321 fprintf(output, "'none' "); break;
1322 case NODE_TEST_TYPE:
1323 fprintf(output, "'type' "); break;
1324 case NODE_TEST_PI:
1325 fprintf(output, "'PI' "); break;
1326 case NODE_TEST_ALL:
1327 fprintf(output, "'all' "); break;
1328 case NODE_TEST_NS:
1329 fprintf(output, "'namespace' "); break;
1330 case NODE_TEST_NAME:
1331 fprintf(output, "'name' "); break;
1332 }
1333 switch (type) {
1334 case NODE_TYPE_NODE:
1335 fprintf(output, "'node' "); break;
1336 case NODE_TYPE_COMMENT:
1337 fprintf(output, "'comment' "); break;
1338 case NODE_TYPE_TEXT:
1339 fprintf(output, "'text' "); break;
1340 case NODE_TYPE_PI:
1341 fprintf(output, "'PI' "); break;
1342 }
1343 if (prefix != NULL)
1344 fprintf(output, "%s:", prefix);
1345 if (name != NULL)
1346 fprintf(output, "%s", (const char *) name);
1347 break;
1348
1349 }
1350 case XPATH_OP_VALUE: {
1351 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1352
1353 fprintf(output, "ELEM ");
1354 xmlXPathDebugDumpObject(output, object, 0);
1355 goto finish;
1356 }
1357 case XPATH_OP_VARIABLE: {
1358 const xmlChar *prefix = op->value5;
1359 const xmlChar *name = op->value4;
1360
1361 if (prefix != NULL)
1362 fprintf(output, "VARIABLE %s:%s", prefix, name);
1363 else
1364 fprintf(output, "VARIABLE %s", name);
1365 break;
1366 }
1367 case XPATH_OP_FUNCTION: {
1368 int nbargs = op->value;
1369 const xmlChar *prefix = op->value5;
1370 const xmlChar *name = op->value4;
1371
1372 if (prefix != NULL)
1373 fprintf(output, "FUNCTION %s:%s(%d args)",
1374 prefix, name, nbargs);
1375 else
1376 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1377 break;
1378 }
1379 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1380 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1381 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1382 default:
1383 fprintf(output, "UNKNOWN %d\n", op->op); return;
1384 }
1385 fprintf(output, "\n");
1386 finish:
1387 if (op->ch1 >= 0)
1388 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1389 if (op->ch2 >= 0)
1390 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1391 }
1392
1393 /**
1394 * xmlXPathDebugDumpCompExpr:
1395 * @output: the FILE * for the output
1396 * @comp: the precompiled XPath expression
1397 * @depth: the indentation level.
1398 *
1399 * Dumps the tree of the compiled XPath expression.
1400 */
1401 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1402 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1403 int depth) {
1404 int i;
1405 char shift[100];
1406
1407 if ((output == NULL) || (comp == NULL)) return;
1408
1409 for (i = 0;((i < depth) && (i < 25));i++)
1410 shift[2 * i] = shift[2 * i + 1] = ' ';
1411 shift[2 * i] = shift[2 * i + 1] = 0;
1412
1413 fprintf(output, "%s", shift);
1414
1415 #ifdef XPATH_STREAMING
1416 if (comp->stream) {
1417 fprintf(output, "Streaming Expression\n");
1418 } else
1419 #endif
1420 {
1421 fprintf(output, "Compiled Expression : %d elements\n",
1422 comp->nbStep);
1423 i = comp->last;
1424 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1425 }
1426 }
1427
1428 #endif /* LIBXML_DEBUG_ENABLED */
1429
1430 /************************************************************************
1431 * *
1432 * XPath object caching *
1433 * *
1434 ************************************************************************/
1435
1436 /**
1437 * xmlXPathNewCache:
1438 *
1439 * Create a new object cache
1440 *
1441 * Returns the xmlXPathCache just allocated.
1442 */
1443 static xmlXPathContextCachePtr
xmlXPathNewCache(void)1444 xmlXPathNewCache(void)
1445 {
1446 xmlXPathContextCachePtr ret;
1447
1448 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1449 if (ret == NULL)
1450 return(NULL);
1451 memset(ret, 0 , sizeof(xmlXPathContextCache));
1452 ret->maxNodeset = 100;
1453 ret->maxMisc = 100;
1454 return(ret);
1455 }
1456
1457 static void
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)1458 xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1459 {
1460 while (list != NULL) {
1461 xmlXPathObjectPtr next;
1462
1463 next = (void *) list->stringval;
1464
1465 if (list->nodesetval != NULL) {
1466 if (list->nodesetval->nodeTab != NULL)
1467 xmlFree(list->nodesetval->nodeTab);
1468 xmlFree(list->nodesetval);
1469 }
1470 xmlFree(list);
1471
1472 list = next;
1473 }
1474 }
1475
1476 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)1477 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1478 {
1479 if (cache == NULL)
1480 return;
1481 if (cache->nodesetObjs)
1482 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1483 if (cache->miscObjs)
1484 xmlXPathCacheFreeObjectList(cache->miscObjs);
1485 xmlFree(cache);
1486 }
1487
1488 /**
1489 * xmlXPathContextSetCache:
1490 *
1491 * @ctxt: the XPath context
1492 * @active: enables/disables (creates/frees) the cache
1493 * @value: a value with semantics dependent on @options
1494 * @options: options (currently only the value 0 is used)
1495 *
1496 * Creates/frees an object cache on the XPath context.
1497 * If activates XPath objects (xmlXPathObject) will be cached internally
1498 * to be reused.
1499 * @options:
1500 * 0: This will set the XPath object caching:
1501 * @value:
1502 * This will set the maximum number of XPath objects
1503 * to be cached per slot
1504 * There are two slots for node-set and misc objects.
1505 * Use <0 for the default number (100).
1506 * Other values for @options have currently no effect.
1507 *
1508 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1509 */
1510 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)1511 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1512 int active,
1513 int value,
1514 int options)
1515 {
1516 if (ctxt == NULL)
1517 return(-1);
1518 if (active) {
1519 xmlXPathContextCachePtr cache;
1520
1521 if (ctxt->cache == NULL) {
1522 ctxt->cache = xmlXPathNewCache();
1523 if (ctxt->cache == NULL) {
1524 xmlXPathErrMemory(ctxt);
1525 return(-1);
1526 }
1527 }
1528 cache = (xmlXPathContextCachePtr) ctxt->cache;
1529 if (options == 0) {
1530 if (value < 0)
1531 value = 100;
1532 cache->maxNodeset = value;
1533 cache->maxMisc = value;
1534 }
1535 } else if (ctxt->cache != NULL) {
1536 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1537 ctxt->cache = NULL;
1538 }
1539 return(0);
1540 }
1541
1542 /**
1543 * xmlXPathCacheWrapNodeSet:
1544 * @pctxt: the XPath context
1545 * @val: the NodePtr value
1546 *
1547 * This is the cached version of xmlXPathWrapNodeSet().
1548 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1549 *
1550 * Returns the created or reused object.
1551 *
1552 * In case of error the node set is destroyed and NULL is returned.
1553 */
1554 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt,xmlNodeSetPtr val)1555 xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1556 {
1557 xmlXPathObjectPtr ret;
1558 xmlXPathContextPtr ctxt = pctxt->context;
1559
1560 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1561 xmlXPathContextCachePtr cache =
1562 (xmlXPathContextCachePtr) ctxt->cache;
1563
1564 if (cache->miscObjs != NULL) {
1565 ret = cache->miscObjs;
1566 cache->miscObjs = (void *) ret->stringval;
1567 cache->numMisc -= 1;
1568 ret->stringval = NULL;
1569 ret->type = XPATH_NODESET;
1570 ret->nodesetval = val;
1571 return(ret);
1572 }
1573 }
1574
1575 ret = xmlXPathWrapNodeSet(val);
1576 if (ret == NULL)
1577 xmlXPathPErrMemory(pctxt);
1578 return(ret);
1579 }
1580
1581 /**
1582 * xmlXPathCacheWrapString:
1583 * @pctxt the XPath context
1584 * @val: the xmlChar * value
1585 *
1586 * This is the cached version of xmlXPathWrapString().
1587 * Wraps the @val string into an XPath object.
1588 *
1589 * Returns the created or reused object.
1590 */
1591 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt,xmlChar * val)1592 xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1593 {
1594 xmlXPathObjectPtr ret;
1595 xmlXPathContextPtr ctxt = pctxt->context;
1596
1597 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1598 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1599
1600 if (cache->miscObjs != NULL) {
1601 ret = cache->miscObjs;
1602 cache->miscObjs = (void *) ret->stringval;
1603 cache->numMisc -= 1;
1604 ret->type = XPATH_STRING;
1605 ret->stringval = val;
1606 return(ret);
1607 }
1608 }
1609
1610 ret = xmlXPathWrapString(val);
1611 if (ret == NULL)
1612 xmlXPathPErrMemory(pctxt);
1613 return(ret);
1614 }
1615
1616 /**
1617 * xmlXPathCacheNewNodeSet:
1618 * @pctxt the XPath context
1619 * @val: the NodePtr value
1620 *
1621 * This is the cached version of xmlXPathNewNodeSet().
1622 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1623 * it with the single Node @val
1624 *
1625 * Returns the created or reused object.
1626 */
1627 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt,xmlNodePtr val)1628 xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1629 {
1630 xmlXPathObjectPtr ret;
1631 xmlXPathContextPtr ctxt = pctxt->context;
1632
1633 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1634 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1635
1636 if (cache->nodesetObjs != NULL) {
1637 /*
1638 * Use the nodeset-cache.
1639 */
1640 ret = cache->nodesetObjs;
1641 cache->nodesetObjs = (void *) ret->stringval;
1642 cache->numNodeset -= 1;
1643 ret->stringval = NULL;
1644 ret->type = XPATH_NODESET;
1645 ret->boolval = 0;
1646 if (val) {
1647 if ((ret->nodesetval->nodeMax == 0) ||
1648 (val->type == XML_NAMESPACE_DECL))
1649 {
1650 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1651 xmlXPathPErrMemory(pctxt);
1652 } else {
1653 ret->nodesetval->nodeTab[0] = val;
1654 ret->nodesetval->nodeNr = 1;
1655 }
1656 }
1657 return(ret);
1658 } else if (cache->miscObjs != NULL) {
1659 xmlNodeSetPtr set;
1660 /*
1661 * Fallback to misc-cache.
1662 */
1663
1664 set = xmlXPathNodeSetCreate(val);
1665 if (set == NULL) {
1666 xmlXPathPErrMemory(pctxt);
1667 return(NULL);
1668 }
1669
1670 ret = cache->miscObjs;
1671 cache->miscObjs = (void *) ret->stringval;
1672 cache->numMisc -= 1;
1673 ret->stringval = NULL;
1674 ret->type = XPATH_NODESET;
1675 ret->boolval = 0;
1676 ret->nodesetval = set;
1677 return(ret);
1678 }
1679 }
1680 ret = xmlXPathNewNodeSet(val);
1681 if (ret == NULL)
1682 xmlXPathPErrMemory(pctxt);
1683 return(ret);
1684 }
1685
1686 /**
1687 * xmlXPathCacheNewString:
1688 * @pctxt the XPath context
1689 * @val: the xmlChar * value
1690 *
1691 * This is the cached version of xmlXPathNewString().
1692 * Acquire an xmlXPathObjectPtr of type string and of value @val
1693 *
1694 * Returns the created or reused object.
1695 */
1696 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt,const xmlChar * val)1697 xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1698 {
1699 xmlXPathObjectPtr ret;
1700 xmlXPathContextPtr ctxt = pctxt->context;
1701
1702 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1703 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1704
1705 if (cache->miscObjs != NULL) {
1706 xmlChar *copy;
1707
1708 if (val == NULL)
1709 val = BAD_CAST "";
1710 copy = xmlStrdup(val);
1711 if (copy == NULL) {
1712 xmlXPathPErrMemory(pctxt);
1713 return(NULL);
1714 }
1715
1716 ret = cache->miscObjs;
1717 cache->miscObjs = (void *) ret->stringval;
1718 cache->numMisc -= 1;
1719 ret->type = XPATH_STRING;
1720 ret->stringval = copy;
1721 return(ret);
1722 }
1723 }
1724
1725 ret = xmlXPathNewString(val);
1726 if (ret == NULL)
1727 xmlXPathPErrMemory(pctxt);
1728 return(ret);
1729 }
1730
1731 /**
1732 * xmlXPathCacheNewCString:
1733 * @pctxt the XPath context
1734 * @val: the char * value
1735 *
1736 * This is the cached version of xmlXPathNewCString().
1737 * Acquire an xmlXPathObjectPtr of type string and of value @val
1738 *
1739 * Returns the created or reused object.
1740 */
1741 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt,const char * val)1742 xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1743 {
1744 return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1745 }
1746
1747 /**
1748 * xmlXPathCacheNewBoolean:
1749 * @pctxt the XPath context
1750 * @val: the boolean value
1751 *
1752 * This is the cached version of xmlXPathNewBoolean().
1753 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1754 *
1755 * Returns the created or reused object.
1756 */
1757 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt,int val)1758 xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1759 {
1760 xmlXPathObjectPtr ret;
1761 xmlXPathContextPtr ctxt = pctxt->context;
1762
1763 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1764 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1765
1766 if (cache->miscObjs != NULL) {
1767 ret = cache->miscObjs;
1768 cache->miscObjs = (void *) ret->stringval;
1769 cache->numMisc -= 1;
1770 ret->stringval = NULL;
1771 ret->type = XPATH_BOOLEAN;
1772 ret->boolval = (val != 0);
1773 return(ret);
1774 }
1775 }
1776
1777 ret = xmlXPathNewBoolean(val);
1778 if (ret == NULL)
1779 xmlXPathPErrMemory(pctxt);
1780 return(ret);
1781 }
1782
1783 /**
1784 * xmlXPathCacheNewFloat:
1785 * @pctxt the XPath context
1786 * @val: the double value
1787 *
1788 * This is the cached version of xmlXPathNewFloat().
1789 * Acquires an xmlXPathObjectPtr of type double and of value @val
1790 *
1791 * Returns the created or reused object.
1792 */
1793 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt,double val)1794 xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1795 {
1796 xmlXPathObjectPtr ret;
1797 xmlXPathContextPtr ctxt = pctxt->context;
1798
1799 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1800 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1801
1802 if (cache->miscObjs != NULL) {
1803 ret = cache->miscObjs;
1804 cache->miscObjs = (void *) ret->stringval;
1805 cache->numMisc -= 1;
1806 ret->stringval = NULL;
1807 ret->type = XPATH_NUMBER;
1808 ret->floatval = val;
1809 return(ret);
1810 }
1811 }
1812
1813 ret = xmlXPathNewFloat(val);
1814 if (ret == NULL)
1815 xmlXPathPErrMemory(pctxt);
1816 return(ret);
1817 }
1818
1819 /**
1820 * xmlXPathCacheObjectCopy:
1821 * @pctxt the XPath context
1822 * @val: the original object
1823 *
1824 * This is the cached version of xmlXPathObjectCopy().
1825 * Acquire a copy of a given object
1826 *
1827 * Returns a created or reused created object.
1828 */
1829 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt,xmlXPathObjectPtr val)1830 xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1831 {
1832 xmlXPathObjectPtr ret;
1833 xmlXPathContextPtr ctxt = pctxt->context;
1834
1835 if (val == NULL)
1836 return(NULL);
1837
1838 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1839 switch (val->type) {
1840 case XPATH_NODESET: {
1841 xmlNodeSetPtr set;
1842
1843 set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1844 if (set == NULL) {
1845 xmlXPathPErrMemory(pctxt);
1846 return(NULL);
1847 }
1848 return(xmlXPathCacheWrapNodeSet(pctxt, set));
1849 }
1850 case XPATH_STRING:
1851 return(xmlXPathCacheNewString(pctxt, val->stringval));
1852 case XPATH_BOOLEAN:
1853 return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1854 case XPATH_NUMBER:
1855 return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1856 default:
1857 break;
1858 }
1859 }
1860 ret = xmlXPathObjectCopy(val);
1861 if (ret == NULL)
1862 xmlXPathPErrMemory(pctxt);
1863 return(ret);
1864 }
1865
1866 /************************************************************************
1867 * *
1868 * Parser stacks related functions and macros *
1869 * *
1870 ************************************************************************/
1871
1872 /**
1873 * xmlXPathCastToNumberInternal:
1874 * @ctxt: parser context
1875 * @val: an XPath object
1876 *
1877 * Converts an XPath object to its number value
1878 *
1879 * Returns the number value
1880 */
1881 static double
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr val)1882 xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1883 xmlXPathObjectPtr val) {
1884 double ret = 0.0;
1885
1886 if (val == NULL)
1887 return(xmlXPathNAN);
1888 switch (val->type) {
1889 case XPATH_UNDEFINED:
1890 ret = xmlXPathNAN;
1891 break;
1892 case XPATH_NODESET:
1893 case XPATH_XSLT_TREE: {
1894 xmlChar *str;
1895
1896 str = xmlXPathCastNodeSetToString(val->nodesetval);
1897 if (str == NULL) {
1898 xmlXPathPErrMemory(ctxt);
1899 ret = xmlXPathNAN;
1900 } else {
1901 ret = xmlXPathCastStringToNumber(str);
1902 xmlFree(str);
1903 }
1904 break;
1905 }
1906 case XPATH_STRING:
1907 ret = xmlXPathCastStringToNumber(val->stringval);
1908 break;
1909 case XPATH_NUMBER:
1910 ret = val->floatval;
1911 break;
1912 case XPATH_BOOLEAN:
1913 ret = xmlXPathCastBooleanToNumber(val->boolval);
1914 break;
1915 case XPATH_USERS:
1916 /* TODO */
1917 ret = xmlXPathNAN;
1918 break;
1919 }
1920 return(ret);
1921 }
1922
1923 /**
1924 * valuePop:
1925 * @ctxt: an XPath evaluation context
1926 *
1927 * Pops the top XPath object from the value stack
1928 *
1929 * Returns the XPath object just removed
1930 */
1931 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)1932 valuePop(xmlXPathParserContextPtr ctxt)
1933 {
1934 xmlXPathObjectPtr ret;
1935
1936 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1937 return (NULL);
1938
1939 ctxt->valueNr--;
1940 if (ctxt->valueNr > 0)
1941 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1942 else
1943 ctxt->value = NULL;
1944 ret = ctxt->valueTab[ctxt->valueNr];
1945 ctxt->valueTab[ctxt->valueNr] = NULL;
1946 return (ret);
1947 }
1948 /**
1949 * valuePush:
1950 * @ctxt: an XPath evaluation context
1951 * @value: the XPath object
1952 *
1953 * Pushes a new XPath object on top of the value stack. If value is NULL,
1954 * a memory error is recorded in the parser context.
1955 *
1956 * Returns the number of items on the value stack, or -1 in case of error.
1957 *
1958 * The object is destroyed in case of error.
1959 */
1960 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)1961 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1962 {
1963 if (ctxt == NULL) return(-1);
1964 if (value == NULL) {
1965 /*
1966 * A NULL value typically indicates that a memory allocation failed.
1967 */
1968 xmlXPathPErrMemory(ctxt);
1969 return(-1);
1970 }
1971 if (ctxt->valueNr >= ctxt->valueMax) {
1972 xmlXPathObjectPtr *tmp;
1973
1974 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
1975 xmlXPathPErrMemory(ctxt);
1976 xmlXPathFreeObject(value);
1977 return (-1);
1978 }
1979 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1980 2 * ctxt->valueMax *
1981 sizeof(ctxt->valueTab[0]));
1982 if (tmp == NULL) {
1983 xmlXPathPErrMemory(ctxt);
1984 xmlXPathFreeObject(value);
1985 return (-1);
1986 }
1987 ctxt->valueMax *= 2;
1988 ctxt->valueTab = tmp;
1989 }
1990 ctxt->valueTab[ctxt->valueNr] = value;
1991 ctxt->value = value;
1992 return (ctxt->valueNr++);
1993 }
1994
1995 /**
1996 * xmlXPathPopBoolean:
1997 * @ctxt: an XPath parser context
1998 *
1999 * Pops a boolean from the stack, handling conversion if needed.
2000 * Check error with #xmlXPathCheckError.
2001 *
2002 * Returns the boolean
2003 */
2004 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2005 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2006 xmlXPathObjectPtr obj;
2007 int ret;
2008
2009 obj = valuePop(ctxt);
2010 if (obj == NULL) {
2011 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2012 return(0);
2013 }
2014 if (obj->type != XPATH_BOOLEAN)
2015 ret = xmlXPathCastToBoolean(obj);
2016 else
2017 ret = obj->boolval;
2018 xmlXPathReleaseObject(ctxt->context, obj);
2019 return(ret);
2020 }
2021
2022 /**
2023 * xmlXPathPopNumber:
2024 * @ctxt: an XPath parser context
2025 *
2026 * Pops a number from the stack, handling conversion if needed.
2027 * Check error with #xmlXPathCheckError.
2028 *
2029 * Returns the number
2030 */
2031 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2032 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2033 xmlXPathObjectPtr obj;
2034 double ret;
2035
2036 obj = valuePop(ctxt);
2037 if (obj == NULL) {
2038 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2039 return(0);
2040 }
2041 if (obj->type != XPATH_NUMBER)
2042 ret = xmlXPathCastToNumberInternal(ctxt, obj);
2043 else
2044 ret = obj->floatval;
2045 xmlXPathReleaseObject(ctxt->context, obj);
2046 return(ret);
2047 }
2048
2049 /**
2050 * xmlXPathPopString:
2051 * @ctxt: an XPath parser context
2052 *
2053 * Pops a string from the stack, handling conversion if needed.
2054 * Check error with #xmlXPathCheckError.
2055 *
2056 * Returns the string
2057 */
2058 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2059 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2060 xmlXPathObjectPtr obj;
2061 xmlChar * ret;
2062
2063 obj = valuePop(ctxt);
2064 if (obj == NULL) {
2065 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2066 return(NULL);
2067 }
2068 ret = xmlXPathCastToString(obj);
2069 if (ret == NULL)
2070 xmlXPathPErrMemory(ctxt);
2071 xmlXPathReleaseObject(ctxt->context, obj);
2072 return(ret);
2073 }
2074
2075 /**
2076 * xmlXPathPopNodeSet:
2077 * @ctxt: an XPath parser context
2078 *
2079 * Pops a node-set from the stack, handling conversion if needed.
2080 * Check error with #xmlXPathCheckError.
2081 *
2082 * Returns the node-set
2083 */
2084 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2085 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2086 xmlXPathObjectPtr obj;
2087 xmlNodeSetPtr ret;
2088
2089 if (ctxt == NULL) return(NULL);
2090 if (ctxt->value == NULL) {
2091 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2092 return(NULL);
2093 }
2094 if (!xmlXPathStackIsNodeSet(ctxt)) {
2095 xmlXPathSetTypeError(ctxt);
2096 return(NULL);
2097 }
2098 obj = valuePop(ctxt);
2099 ret = obj->nodesetval;
2100 obj->nodesetval = NULL;
2101 xmlXPathReleaseObject(ctxt->context, obj);
2102 return(ret);
2103 }
2104
2105 /**
2106 * xmlXPathPopExternal:
2107 * @ctxt: an XPath parser context
2108 *
2109 * Pops an external object from the stack, handling conversion if needed.
2110 * Check error with #xmlXPathCheckError.
2111 *
2112 * Returns the object
2113 */
2114 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)2115 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2116 xmlXPathObjectPtr obj;
2117 void * ret;
2118
2119 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2120 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2121 return(NULL);
2122 }
2123 if (ctxt->value->type != XPATH_USERS) {
2124 xmlXPathSetTypeError(ctxt);
2125 return(NULL);
2126 }
2127 obj = valuePop(ctxt);
2128 ret = obj->user;
2129 obj->user = NULL;
2130 xmlXPathReleaseObject(ctxt->context, obj);
2131 return(ret);
2132 }
2133
2134 /*
2135 * Macros for accessing the content. Those should be used only by the parser,
2136 * and not exported.
2137 *
2138 * Dirty macros, i.e. one need to make assumption on the context to use them
2139 *
2140 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2141 * CUR returns the current xmlChar value, i.e. a 8 bit value
2142 * in ISO-Latin or UTF-8.
2143 * This should be used internally by the parser
2144 * only to compare to ASCII values otherwise it would break when
2145 * running with UTF-8 encoding.
2146 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2147 * to compare on ASCII based substring.
2148 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2149 * strings within the parser.
2150 * CURRENT Returns the current char value, with the full decoding of
2151 * UTF-8 if we are using this mode. It returns an int.
2152 * NEXT Skip to the next character, this does the proper decoding
2153 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2154 * It returns the pointer to the current xmlChar.
2155 */
2156
2157 #define CUR (*ctxt->cur)
2158 #define SKIP(val) ctxt->cur += (val)
2159 #define NXT(val) ctxt->cur[(val)]
2160 #define CUR_PTR ctxt->cur
2161 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2162
2163 #define COPY_BUF(b, i, v) \
2164 if (v < 0x80) b[i++] = v; \
2165 else i += xmlCopyCharMultiByte(&b[i],v)
2166
2167 #define NEXTL(l) ctxt->cur += l
2168
2169 #define SKIP_BLANKS \
2170 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2171
2172 #define CURRENT (*ctxt->cur)
2173 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2174
2175
2176 #ifndef DBL_DIG
2177 #define DBL_DIG 16
2178 #endif
2179 #ifndef DBL_EPSILON
2180 #define DBL_EPSILON 1E-9
2181 #endif
2182
2183 #define UPPER_DOUBLE 1E9
2184 #define LOWER_DOUBLE 1E-5
2185 #define LOWER_DOUBLE_EXP 5
2186
2187 #define INTEGER_DIGITS DBL_DIG
2188 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2189 #define EXPONENT_DIGITS (3 + 2)
2190
2191 /**
2192 * xmlXPathFormatNumber:
2193 * @number: number to format
2194 * @buffer: output buffer
2195 * @buffersize: size of output buffer
2196 *
2197 * Convert the number into a string representation.
2198 */
2199 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)2200 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2201 {
2202 switch (xmlXPathIsInf(number)) {
2203 case 1:
2204 if (buffersize > (int)sizeof("Infinity"))
2205 snprintf(buffer, buffersize, "Infinity");
2206 break;
2207 case -1:
2208 if (buffersize > (int)sizeof("-Infinity"))
2209 snprintf(buffer, buffersize, "-Infinity");
2210 break;
2211 default:
2212 if (xmlXPathIsNaN(number)) {
2213 if (buffersize > (int)sizeof("NaN"))
2214 snprintf(buffer, buffersize, "NaN");
2215 } else if (number == 0) {
2216 /* Omit sign for negative zero. */
2217 snprintf(buffer, buffersize, "0");
2218 } else if ((number > INT_MIN) && (number < INT_MAX) &&
2219 (number == (int) number)) {
2220 char work[30];
2221 char *ptr, *cur;
2222 int value = (int) number;
2223
2224 ptr = &buffer[0];
2225 if (value == 0) {
2226 *ptr++ = '0';
2227 } else {
2228 snprintf(work, 29, "%d", value);
2229 cur = &work[0];
2230 while ((*cur) && (ptr - buffer < buffersize)) {
2231 *ptr++ = *cur++;
2232 }
2233 }
2234 if (ptr - buffer < buffersize) {
2235 *ptr = 0;
2236 } else if (buffersize > 0) {
2237 ptr--;
2238 *ptr = 0;
2239 }
2240 } else {
2241 /*
2242 For the dimension of work,
2243 DBL_DIG is number of significant digits
2244 EXPONENT is only needed for "scientific notation"
2245 3 is sign, decimal point, and terminating zero
2246 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2247 Note that this dimension is slightly (a few characters)
2248 larger than actually necessary.
2249 */
2250 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2251 int integer_place, fraction_place;
2252 char *ptr;
2253 char *after_fraction;
2254 double absolute_value;
2255 int size;
2256
2257 absolute_value = fabs(number);
2258
2259 /*
2260 * First choose format - scientific or regular floating point.
2261 * In either case, result is in work, and after_fraction points
2262 * just past the fractional part.
2263 */
2264 if ( ((absolute_value > UPPER_DOUBLE) ||
2265 (absolute_value < LOWER_DOUBLE)) &&
2266 (absolute_value != 0.0) ) {
2267 /* Use scientific notation */
2268 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2269 fraction_place = DBL_DIG - 1;
2270 size = snprintf(work, sizeof(work),"%*.*e",
2271 integer_place, fraction_place, number);
2272 while ((size > 0) && (work[size] != 'e')) size--;
2273
2274 }
2275 else {
2276 /* Use regular notation */
2277 if (absolute_value > 0.0) {
2278 integer_place = (int)log10(absolute_value);
2279 if (integer_place > 0)
2280 fraction_place = DBL_DIG - integer_place - 1;
2281 else
2282 fraction_place = DBL_DIG - integer_place;
2283 } else {
2284 fraction_place = 1;
2285 }
2286 size = snprintf(work, sizeof(work), "%0.*f",
2287 fraction_place, number);
2288 }
2289
2290 /* Remove leading spaces sometimes inserted by snprintf */
2291 while (work[0] == ' ') {
2292 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2293 size--;
2294 }
2295
2296 /* Remove fractional trailing zeroes */
2297 after_fraction = work + size;
2298 ptr = after_fraction;
2299 while (*(--ptr) == '0')
2300 ;
2301 if (*ptr != '.')
2302 ptr++;
2303 while ((*ptr++ = *after_fraction++) != 0);
2304
2305 /* Finally copy result back to caller */
2306 size = strlen(work) + 1;
2307 if (size > buffersize) {
2308 work[buffersize - 1] = 0;
2309 size = buffersize;
2310 }
2311 memmove(buffer, work, size);
2312 }
2313 break;
2314 }
2315 }
2316
2317
2318 /************************************************************************
2319 * *
2320 * Routines to handle NodeSets *
2321 * *
2322 ************************************************************************/
2323
2324 /**
2325 * xmlXPathOrderDocElems:
2326 * @doc: an input document
2327 *
2328 * Call this routine to speed up XPath computation on static documents.
2329 * This stamps all the element nodes with the document order
2330 * Like for line information, the order is kept in the element->content
2331 * field, the value stored is actually - the node number (starting at -1)
2332 * to be able to differentiate from line numbers.
2333 *
2334 * Returns the number of elements found in the document or -1 in case
2335 * of error.
2336 */
2337 long
xmlXPathOrderDocElems(xmlDocPtr doc)2338 xmlXPathOrderDocElems(xmlDocPtr doc) {
2339 ptrdiff_t count = 0;
2340 xmlNodePtr cur;
2341
2342 if (doc == NULL)
2343 return(-1);
2344 cur = doc->children;
2345 while (cur != NULL) {
2346 if (cur->type == XML_ELEMENT_NODE) {
2347 cur->content = (void *) (-(++count));
2348 if (cur->children != NULL) {
2349 cur = cur->children;
2350 continue;
2351 }
2352 }
2353 if (cur->next != NULL) {
2354 cur = cur->next;
2355 continue;
2356 }
2357 do {
2358 cur = cur->parent;
2359 if (cur == NULL)
2360 break;
2361 if (cur == (xmlNodePtr) doc) {
2362 cur = NULL;
2363 break;
2364 }
2365 if (cur->next != NULL) {
2366 cur = cur->next;
2367 break;
2368 }
2369 } while (cur != NULL);
2370 }
2371 return(count);
2372 }
2373
2374 /**
2375 * xmlXPathCmpNodes:
2376 * @node1: the first node
2377 * @node2: the second node
2378 *
2379 * Compare two nodes w.r.t document order
2380 *
2381 * Returns -2 in case of error 1 if first point < second point, 0 if
2382 * it's the same node, -1 otherwise
2383 */
2384 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)2385 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2386 int depth1, depth2;
2387 int attr1 = 0, attr2 = 0;
2388 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2389 xmlNodePtr cur, root;
2390
2391 if ((node1 == NULL) || (node2 == NULL))
2392 return(-2);
2393 /*
2394 * a couple of optimizations which will avoid computations in most cases
2395 */
2396 if (node1 == node2) /* trivial case */
2397 return(0);
2398 if (node1->type == XML_ATTRIBUTE_NODE) {
2399 attr1 = 1;
2400 attrNode1 = node1;
2401 node1 = node1->parent;
2402 }
2403 if (node2->type == XML_ATTRIBUTE_NODE) {
2404 attr2 = 1;
2405 attrNode2 = node2;
2406 node2 = node2->parent;
2407 }
2408 if (node1 == node2) {
2409 if (attr1 == attr2) {
2410 /* not required, but we keep attributes in order */
2411 if (attr1 != 0) {
2412 cur = attrNode2->prev;
2413 while (cur != NULL) {
2414 if (cur == attrNode1)
2415 return (1);
2416 cur = cur->prev;
2417 }
2418 return (-1);
2419 }
2420 return(0);
2421 }
2422 if (attr2 == 1)
2423 return(1);
2424 return(-1);
2425 }
2426 if ((node1->type == XML_NAMESPACE_DECL) ||
2427 (node2->type == XML_NAMESPACE_DECL))
2428 return(1);
2429 if (node1 == node2->prev)
2430 return(1);
2431 if (node1 == node2->next)
2432 return(-1);
2433
2434 /*
2435 * Speedup using document order if available.
2436 */
2437 if ((node1->type == XML_ELEMENT_NODE) &&
2438 (node2->type == XML_ELEMENT_NODE) &&
2439 (0 > (ptrdiff_t) node1->content) &&
2440 (0 > (ptrdiff_t) node2->content) &&
2441 (node1->doc == node2->doc)) {
2442 ptrdiff_t l1, l2;
2443
2444 l1 = -((ptrdiff_t) node1->content);
2445 l2 = -((ptrdiff_t) node2->content);
2446 if (l1 < l2)
2447 return(1);
2448 if (l1 > l2)
2449 return(-1);
2450 }
2451
2452 /*
2453 * compute depth to root
2454 */
2455 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2456 if (cur->parent == node1)
2457 return(1);
2458 depth2++;
2459 }
2460 root = cur;
2461 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2462 if (cur->parent == node2)
2463 return(-1);
2464 depth1++;
2465 }
2466 /*
2467 * Distinct document (or distinct entities :-( ) case.
2468 */
2469 if (root != cur) {
2470 return(-2);
2471 }
2472 /*
2473 * get the nearest common ancestor.
2474 */
2475 while (depth1 > depth2) {
2476 depth1--;
2477 node1 = node1->parent;
2478 }
2479 while (depth2 > depth1) {
2480 depth2--;
2481 node2 = node2->parent;
2482 }
2483 while (node1->parent != node2->parent) {
2484 node1 = node1->parent;
2485 node2 = node2->parent;
2486 /* should not happen but just in case ... */
2487 if ((node1 == NULL) || (node2 == NULL))
2488 return(-2);
2489 }
2490 /*
2491 * Find who's first.
2492 */
2493 if (node1 == node2->prev)
2494 return(1);
2495 if (node1 == node2->next)
2496 return(-1);
2497 /*
2498 * Speedup using document order if available.
2499 */
2500 if ((node1->type == XML_ELEMENT_NODE) &&
2501 (node2->type == XML_ELEMENT_NODE) &&
2502 (0 > (ptrdiff_t) node1->content) &&
2503 (0 > (ptrdiff_t) node2->content) &&
2504 (node1->doc == node2->doc)) {
2505 ptrdiff_t l1, l2;
2506
2507 l1 = -((ptrdiff_t) node1->content);
2508 l2 = -((ptrdiff_t) node2->content);
2509 if (l1 < l2)
2510 return(1);
2511 if (l1 > l2)
2512 return(-1);
2513 }
2514
2515 for (cur = node1->next;cur != NULL;cur = cur->next)
2516 if (cur == node2)
2517 return(1);
2518 return(-1); /* assume there is no sibling list corruption */
2519 }
2520
2521 /**
2522 * xmlXPathNodeSetSort:
2523 * @set: the node set
2524 *
2525 * Sort the node set in document order
2526 */
2527 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)2528 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2529 #ifndef WITH_TIM_SORT
2530 int i, j, incr, len;
2531 xmlNodePtr tmp;
2532 #endif
2533
2534 if (set == NULL)
2535 return;
2536
2537 #ifndef WITH_TIM_SORT
2538 /*
2539 * Use the old Shell's sort implementation to sort the node-set
2540 * Timsort ought to be quite faster
2541 */
2542 len = set->nodeNr;
2543 for (incr = len / 2; incr > 0; incr /= 2) {
2544 for (i = incr; i < len; i++) {
2545 j = i - incr;
2546 while (j >= 0) {
2547 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2548 if (xmlXPathCmpNodesExt(set->nodeTab[j],
2549 set->nodeTab[j + incr]) == -1)
2550 #else
2551 if (xmlXPathCmpNodes(set->nodeTab[j],
2552 set->nodeTab[j + incr]) == -1)
2553 #endif
2554 {
2555 tmp = set->nodeTab[j];
2556 set->nodeTab[j] = set->nodeTab[j + incr];
2557 set->nodeTab[j + incr] = tmp;
2558 j -= incr;
2559 } else
2560 break;
2561 }
2562 }
2563 }
2564 #else /* WITH_TIM_SORT */
2565 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2566 #endif /* WITH_TIM_SORT */
2567 }
2568
2569 #define XML_NODESET_DEFAULT 10
2570 /**
2571 * xmlXPathNodeSetDupNs:
2572 * @node: the parent node of the namespace XPath node
2573 * @ns: the libxml namespace declaration node.
2574 *
2575 * Namespace node in libxml don't match the XPath semantic. In a node set
2576 * the namespace nodes are duplicated and the next pointer is set to the
2577 * parent node in the XPath semantic.
2578 *
2579 * Returns the newly created object.
2580 */
2581 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)2582 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2583 xmlNsPtr cur;
2584
2585 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2586 return(NULL);
2587 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2588 return((xmlNodePtr) ns);
2589
2590 /*
2591 * Allocate a new Namespace and fill the fields.
2592 */
2593 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2594 if (cur == NULL)
2595 return(NULL);
2596 memset(cur, 0, sizeof(xmlNs));
2597 cur->type = XML_NAMESPACE_DECL;
2598 if (ns->href != NULL) {
2599 cur->href = xmlStrdup(ns->href);
2600 if (cur->href == NULL) {
2601 xmlFree(cur);
2602 return(NULL);
2603 }
2604 }
2605 if (ns->prefix != NULL) {
2606 cur->prefix = xmlStrdup(ns->prefix);
2607 if (cur->prefix == NULL) {
2608 xmlFree((xmlChar *) cur->href);
2609 xmlFree(cur);
2610 return(NULL);
2611 }
2612 }
2613 cur->next = (xmlNsPtr) node;
2614 return((xmlNodePtr) cur);
2615 }
2616
2617 /**
2618 * xmlXPathNodeSetFreeNs:
2619 * @ns: the XPath namespace node found in a nodeset.
2620 *
2621 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2622 * the namespace nodes are duplicated and the next pointer is set to the
2623 * parent node in the XPath semantic. Check if such a node needs to be freed
2624 */
2625 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)2626 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2627 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2628 return;
2629
2630 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2631 if (ns->href != NULL)
2632 xmlFree((xmlChar *)ns->href);
2633 if (ns->prefix != NULL)
2634 xmlFree((xmlChar *)ns->prefix);
2635 xmlFree(ns);
2636 }
2637 }
2638
2639 /**
2640 * xmlXPathNodeSetCreate:
2641 * @val: an initial xmlNodePtr, or NULL
2642 *
2643 * Create a new xmlNodeSetPtr of type double and of value @val
2644 *
2645 * Returns the newly created object.
2646 */
2647 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)2648 xmlXPathNodeSetCreate(xmlNodePtr val) {
2649 xmlNodeSetPtr ret;
2650
2651 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2652 if (ret == NULL)
2653 return(NULL);
2654 memset(ret, 0 , sizeof(xmlNodeSet));
2655 if (val != NULL) {
2656 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2657 sizeof(xmlNodePtr));
2658 if (ret->nodeTab == NULL) {
2659 xmlFree(ret);
2660 return(NULL);
2661 }
2662 memset(ret->nodeTab, 0 ,
2663 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2664 ret->nodeMax = XML_NODESET_DEFAULT;
2665 if (val->type == XML_NAMESPACE_DECL) {
2666 xmlNsPtr ns = (xmlNsPtr) val;
2667 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2668
2669 if (nsNode == NULL) {
2670 xmlXPathFreeNodeSet(ret);
2671 return(NULL);
2672 }
2673 ret->nodeTab[ret->nodeNr++] = nsNode;
2674 } else
2675 ret->nodeTab[ret->nodeNr++] = val;
2676 }
2677 return(ret);
2678 }
2679
2680 /**
2681 * xmlXPathNodeSetContains:
2682 * @cur: the node-set
2683 * @val: the node
2684 *
2685 * checks whether @cur contains @val
2686 *
2687 * Returns true (1) if @cur contains @val, false (0) otherwise
2688 */
2689 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)2690 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2691 int i;
2692
2693 if ((cur == NULL) || (val == NULL)) return(0);
2694 if (val->type == XML_NAMESPACE_DECL) {
2695 for (i = 0; i < cur->nodeNr; i++) {
2696 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2697 xmlNsPtr ns1, ns2;
2698
2699 ns1 = (xmlNsPtr) val;
2700 ns2 = (xmlNsPtr) cur->nodeTab[i];
2701 if (ns1 == ns2)
2702 return(1);
2703 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2704 (xmlStrEqual(ns1->prefix, ns2->prefix)))
2705 return(1);
2706 }
2707 }
2708 } else {
2709 for (i = 0; i < cur->nodeNr; i++) {
2710 if (cur->nodeTab[i] == val)
2711 return(1);
2712 }
2713 }
2714 return(0);
2715 }
2716
2717 /**
2718 * xmlXPathNodeSetAddNs:
2719 * @cur: the initial node set
2720 * @node: the hosting node
2721 * @ns: a the namespace node
2722 *
2723 * add a new namespace node to an existing NodeSet
2724 *
2725 * Returns 0 in case of success and -1 in case of error
2726 */
2727 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)2728 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2729 int i;
2730 xmlNodePtr nsNode;
2731
2732 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2733 (ns->type != XML_NAMESPACE_DECL) ||
2734 (node->type != XML_ELEMENT_NODE))
2735 return(-1);
2736
2737 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2738 /*
2739 * prevent duplicates
2740 */
2741 for (i = 0;i < cur->nodeNr;i++) {
2742 if ((cur->nodeTab[i] != NULL) &&
2743 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2744 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2745 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2746 return(0);
2747 }
2748
2749 /*
2750 * grow the nodeTab if needed
2751 */
2752 if (cur->nodeMax == 0) {
2753 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2754 sizeof(xmlNodePtr));
2755 if (cur->nodeTab == NULL)
2756 return(-1);
2757 memset(cur->nodeTab, 0 ,
2758 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2759 cur->nodeMax = XML_NODESET_DEFAULT;
2760 } else if (cur->nodeNr == cur->nodeMax) {
2761 xmlNodePtr *temp;
2762
2763 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2764 return(-1);
2765 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2766 sizeof(xmlNodePtr));
2767 if (temp == NULL)
2768 return(-1);
2769 cur->nodeMax *= 2;
2770 cur->nodeTab = temp;
2771 }
2772 nsNode = xmlXPathNodeSetDupNs(node, ns);
2773 if(nsNode == NULL)
2774 return(-1);
2775 cur->nodeTab[cur->nodeNr++] = nsNode;
2776 return(0);
2777 }
2778
2779 /**
2780 * xmlXPathNodeSetAdd:
2781 * @cur: the initial node set
2782 * @val: a new xmlNodePtr
2783 *
2784 * add a new xmlNodePtr to an existing NodeSet
2785 *
2786 * Returns 0 in case of success, and -1 in case of error
2787 */
2788 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)2789 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2790 int i;
2791
2792 if ((cur == NULL) || (val == NULL)) return(-1);
2793
2794 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2795 /*
2796 * prevent duplicates
2797 */
2798 for (i = 0;i < cur->nodeNr;i++)
2799 if (cur->nodeTab[i] == val) return(0);
2800
2801 /*
2802 * grow the nodeTab if needed
2803 */
2804 if (cur->nodeMax == 0) {
2805 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2806 sizeof(xmlNodePtr));
2807 if (cur->nodeTab == NULL)
2808 return(-1);
2809 memset(cur->nodeTab, 0 ,
2810 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2811 cur->nodeMax = XML_NODESET_DEFAULT;
2812 } else if (cur->nodeNr == cur->nodeMax) {
2813 xmlNodePtr *temp;
2814
2815 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2816 return(-1);
2817 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2818 sizeof(xmlNodePtr));
2819 if (temp == NULL)
2820 return(-1);
2821 cur->nodeMax *= 2;
2822 cur->nodeTab = temp;
2823 }
2824 if (val->type == XML_NAMESPACE_DECL) {
2825 xmlNsPtr ns = (xmlNsPtr) val;
2826 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2827
2828 if (nsNode == NULL)
2829 return(-1);
2830 cur->nodeTab[cur->nodeNr++] = nsNode;
2831 } else
2832 cur->nodeTab[cur->nodeNr++] = val;
2833 return(0);
2834 }
2835
2836 /**
2837 * xmlXPathNodeSetAddUnique:
2838 * @cur: the initial node set
2839 * @val: a new xmlNodePtr
2840 *
2841 * add a new xmlNodePtr to an existing NodeSet, optimized version
2842 * when we are sure the node is not already in the set.
2843 *
2844 * Returns 0 in case of success and -1 in case of failure
2845 */
2846 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)2847 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2848 if ((cur == NULL) || (val == NULL)) return(-1);
2849
2850 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2851 /*
2852 * grow the nodeTab if needed
2853 */
2854 if (cur->nodeMax == 0) {
2855 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2856 sizeof(xmlNodePtr));
2857 if (cur->nodeTab == NULL)
2858 return(-1);
2859 memset(cur->nodeTab, 0 ,
2860 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2861 cur->nodeMax = XML_NODESET_DEFAULT;
2862 } else if (cur->nodeNr == cur->nodeMax) {
2863 xmlNodePtr *temp;
2864
2865 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2866 return(-1);
2867 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2868 sizeof(xmlNodePtr));
2869 if (temp == NULL)
2870 return(-1);
2871 cur->nodeTab = temp;
2872 cur->nodeMax *= 2;
2873 }
2874 if (val->type == XML_NAMESPACE_DECL) {
2875 xmlNsPtr ns = (xmlNsPtr) val;
2876 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2877
2878 if (nsNode == NULL)
2879 return(-1);
2880 cur->nodeTab[cur->nodeNr++] = nsNode;
2881 } else
2882 cur->nodeTab[cur->nodeNr++] = val;
2883 return(0);
2884 }
2885
2886 /**
2887 * xmlXPathNodeSetMerge:
2888 * @val1: the first NodeSet or NULL
2889 * @val2: the second NodeSet
2890 *
2891 * Merges two nodesets, all nodes from @val2 are added to @val1
2892 * if @val1 is NULL, a new set is created and copied from @val2
2893 *
2894 * Returns @val1 once extended or NULL in case of error.
2895 *
2896 * Frees @val1 in case of error.
2897 */
2898 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)2899 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
2900 int i, j, initNr, skip;
2901 xmlNodePtr n1, n2;
2902
2903 if (val1 == NULL) {
2904 val1 = xmlXPathNodeSetCreate(NULL);
2905 if (val1 == NULL)
2906 return (NULL);
2907 }
2908 if (val2 == NULL)
2909 return(val1);
2910
2911 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2912 initNr = val1->nodeNr;
2913
2914 for (i = 0;i < val2->nodeNr;i++) {
2915 n2 = val2->nodeTab[i];
2916 /*
2917 * check against duplicates
2918 */
2919 skip = 0;
2920 for (j = 0; j < initNr; j++) {
2921 n1 = val1->nodeTab[j];
2922 if (n1 == n2) {
2923 skip = 1;
2924 break;
2925 } else if ((n1->type == XML_NAMESPACE_DECL) &&
2926 (n2->type == XML_NAMESPACE_DECL)) {
2927 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2928 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2929 ((xmlNsPtr) n2)->prefix)))
2930 {
2931 skip = 1;
2932 break;
2933 }
2934 }
2935 }
2936 if (skip)
2937 continue;
2938
2939 /*
2940 * grow the nodeTab if needed
2941 */
2942 if (val1->nodeMax == 0) {
2943 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2944 sizeof(xmlNodePtr));
2945 if (val1->nodeTab == NULL)
2946 goto error;
2947 memset(val1->nodeTab, 0 ,
2948 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2949 val1->nodeMax = XML_NODESET_DEFAULT;
2950 } else if (val1->nodeNr == val1->nodeMax) {
2951 xmlNodePtr *temp;
2952
2953 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2954 goto error;
2955 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
2956 sizeof(xmlNodePtr));
2957 if (temp == NULL)
2958 goto error;
2959 val1->nodeTab = temp;
2960 val1->nodeMax *= 2;
2961 }
2962 if (n2->type == XML_NAMESPACE_DECL) {
2963 xmlNsPtr ns = (xmlNsPtr) n2;
2964 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2965
2966 if (nsNode == NULL)
2967 goto error;
2968 val1->nodeTab[val1->nodeNr++] = nsNode;
2969 } else
2970 val1->nodeTab[val1->nodeNr++] = n2;
2971 }
2972
2973 return(val1);
2974
2975 error:
2976 xmlXPathFreeNodeSet(val1);
2977 return(NULL);
2978 }
2979
2980
2981 /**
2982 * xmlXPathNodeSetMergeAndClear:
2983 * @set1: the first NodeSet or NULL
2984 * @set2: the second NodeSet
2985 *
2986 * Merges two nodesets, all nodes from @set2 are added to @set1.
2987 * Checks for duplicate nodes. Clears set2.
2988 *
2989 * Returns @set1 once extended or NULL in case of error.
2990 *
2991 * Frees @set1 in case of error.
2992 */
2993 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)2994 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
2995 {
2996 {
2997 int i, j, initNbSet1;
2998 xmlNodePtr n1, n2;
2999
3000 initNbSet1 = set1->nodeNr;
3001 for (i = 0;i < set2->nodeNr;i++) {
3002 n2 = set2->nodeTab[i];
3003 /*
3004 * Skip duplicates.
3005 */
3006 for (j = 0; j < initNbSet1; j++) {
3007 n1 = set1->nodeTab[j];
3008 if (n1 == n2) {
3009 goto skip_node;
3010 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3011 (n2->type == XML_NAMESPACE_DECL))
3012 {
3013 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3014 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3015 ((xmlNsPtr) n2)->prefix)))
3016 {
3017 /*
3018 * Free the namespace node.
3019 */
3020 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3021 goto skip_node;
3022 }
3023 }
3024 }
3025 /*
3026 * grow the nodeTab if needed
3027 */
3028 if (set1->nodeMax == 0) {
3029 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3030 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3031 if (set1->nodeTab == NULL)
3032 goto error;
3033 memset(set1->nodeTab, 0,
3034 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3035 set1->nodeMax = XML_NODESET_DEFAULT;
3036 } else if (set1->nodeNr >= set1->nodeMax) {
3037 xmlNodePtr *temp;
3038
3039 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3040 goto error;
3041 temp = (xmlNodePtr *) xmlRealloc(
3042 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3043 if (temp == NULL)
3044 goto error;
3045 set1->nodeTab = temp;
3046 set1->nodeMax *= 2;
3047 }
3048 set1->nodeTab[set1->nodeNr++] = n2;
3049 skip_node:
3050 set2->nodeTab[i] = NULL;
3051 }
3052 }
3053 set2->nodeNr = 0;
3054 return(set1);
3055
3056 error:
3057 xmlXPathFreeNodeSet(set1);
3058 xmlXPathNodeSetClear(set2, 1);
3059 return(NULL);
3060 }
3061
3062 /**
3063 * xmlXPathNodeSetMergeAndClearNoDupls:
3064 * @set1: the first NodeSet or NULL
3065 * @set2: the second NodeSet
3066 *
3067 * Merges two nodesets, all nodes from @set2 are added to @set1.
3068 * Doesn't check for duplicate nodes. Clears set2.
3069 *
3070 * Returns @set1 once extended or NULL in case of error.
3071 *
3072 * Frees @set1 in case of error.
3073 */
3074 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3075 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3076 {
3077 {
3078 int i;
3079 xmlNodePtr n2;
3080
3081 for (i = 0;i < set2->nodeNr;i++) {
3082 n2 = set2->nodeTab[i];
3083 if (set1->nodeMax == 0) {
3084 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3085 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3086 if (set1->nodeTab == NULL)
3087 goto error;
3088 memset(set1->nodeTab, 0,
3089 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3090 set1->nodeMax = XML_NODESET_DEFAULT;
3091 } else if (set1->nodeNr >= set1->nodeMax) {
3092 xmlNodePtr *temp;
3093
3094 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3095 goto error;
3096 temp = (xmlNodePtr *) xmlRealloc(
3097 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3098 if (temp == NULL)
3099 goto error;
3100 set1->nodeTab = temp;
3101 set1->nodeMax *= 2;
3102 }
3103 set1->nodeTab[set1->nodeNr++] = n2;
3104 set2->nodeTab[i] = NULL;
3105 }
3106 }
3107 set2->nodeNr = 0;
3108 return(set1);
3109
3110 error:
3111 xmlXPathFreeNodeSet(set1);
3112 xmlXPathNodeSetClear(set2, 1);
3113 return(NULL);
3114 }
3115
3116 /**
3117 * xmlXPathNodeSetDel:
3118 * @cur: the initial node set
3119 * @val: an xmlNodePtr
3120 *
3121 * Removes an xmlNodePtr from an existing NodeSet
3122 */
3123 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)3124 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3125 int i;
3126
3127 if (cur == NULL) return;
3128 if (val == NULL) return;
3129
3130 /*
3131 * find node in nodeTab
3132 */
3133 for (i = 0;i < cur->nodeNr;i++)
3134 if (cur->nodeTab[i] == val) break;
3135
3136 if (i >= cur->nodeNr) { /* not found */
3137 return;
3138 }
3139 if ((cur->nodeTab[i] != NULL) &&
3140 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3141 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3142 cur->nodeNr--;
3143 for (;i < cur->nodeNr;i++)
3144 cur->nodeTab[i] = cur->nodeTab[i + 1];
3145 cur->nodeTab[cur->nodeNr] = NULL;
3146 }
3147
3148 /**
3149 * xmlXPathNodeSetRemove:
3150 * @cur: the initial node set
3151 * @val: the index to remove
3152 *
3153 * Removes an entry from an existing NodeSet list.
3154 */
3155 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)3156 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3157 if (cur == NULL) return;
3158 if (val >= cur->nodeNr) return;
3159 if ((cur->nodeTab[val] != NULL) &&
3160 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3161 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3162 cur->nodeNr--;
3163 for (;val < cur->nodeNr;val++)
3164 cur->nodeTab[val] = cur->nodeTab[val + 1];
3165 cur->nodeTab[cur->nodeNr] = NULL;
3166 }
3167
3168 /**
3169 * xmlXPathFreeNodeSet:
3170 * @obj: the xmlNodeSetPtr to free
3171 *
3172 * Free the NodeSet compound (not the actual nodes !).
3173 */
3174 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)3175 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3176 if (obj == NULL) return;
3177 if (obj->nodeTab != NULL) {
3178 int i;
3179
3180 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3181 for (i = 0;i < obj->nodeNr;i++)
3182 if ((obj->nodeTab[i] != NULL) &&
3183 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3184 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3185 xmlFree(obj->nodeTab);
3186 }
3187 xmlFree(obj);
3188 }
3189
3190 /**
3191 * xmlXPathNodeSetClearFromPos:
3192 * @set: the node set to be cleared
3193 * @pos: the start position to clear from
3194 *
3195 * Clears the list from temporary XPath objects (e.g. namespace nodes
3196 * are feed) starting with the entry at @pos, but does *not* free the list
3197 * itself. Sets the length of the list to @pos.
3198 */
3199 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)3200 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3201 {
3202 if ((set == NULL) || (pos >= set->nodeNr))
3203 return;
3204 else if ((hasNsNodes)) {
3205 int i;
3206 xmlNodePtr node;
3207
3208 for (i = pos; i < set->nodeNr; i++) {
3209 node = set->nodeTab[i];
3210 if ((node != NULL) &&
3211 (node->type == XML_NAMESPACE_DECL))
3212 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3213 }
3214 }
3215 set->nodeNr = pos;
3216 }
3217
3218 /**
3219 * xmlXPathNodeSetClear:
3220 * @set: the node set to clear
3221 *
3222 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3223 * are feed), but does *not* free the list itself. Sets the length of the
3224 * list to 0.
3225 */
3226 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)3227 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3228 {
3229 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3230 }
3231
3232 /**
3233 * xmlXPathNodeSetKeepLast:
3234 * @set: the node set to be cleared
3235 *
3236 * Move the last node to the first position and clear temporary XPath objects
3237 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3238 * to 1.
3239 */
3240 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)3241 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3242 {
3243 int i;
3244 xmlNodePtr node;
3245
3246 if ((set == NULL) || (set->nodeNr <= 1))
3247 return;
3248 for (i = 0; i < set->nodeNr - 1; i++) {
3249 node = set->nodeTab[i];
3250 if ((node != NULL) &&
3251 (node->type == XML_NAMESPACE_DECL))
3252 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3253 }
3254 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3255 set->nodeNr = 1;
3256 }
3257
3258 /**
3259 * xmlXPathNewNodeSet:
3260 * @val: the NodePtr value
3261 *
3262 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3263 * it with the single Node @val
3264 *
3265 * Returns the newly created object.
3266 */
3267 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)3268 xmlXPathNewNodeSet(xmlNodePtr val) {
3269 xmlXPathObjectPtr ret;
3270
3271 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3272 if (ret == NULL)
3273 return(NULL);
3274 memset(ret, 0 , sizeof(xmlXPathObject));
3275 ret->type = XPATH_NODESET;
3276 ret->boolval = 0;
3277 ret->nodesetval = xmlXPathNodeSetCreate(val);
3278 if (ret->nodesetval == NULL) {
3279 xmlFree(ret);
3280 return(NULL);
3281 }
3282 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3283 return(ret);
3284 }
3285
3286 /**
3287 * xmlXPathNewValueTree:
3288 * @val: the NodePtr value
3289 *
3290 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3291 * it with the tree root @val
3292 *
3293 * Returns the newly created object.
3294 */
3295 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)3296 xmlXPathNewValueTree(xmlNodePtr val) {
3297 xmlXPathObjectPtr ret;
3298
3299 ret = xmlXPathNewNodeSet(val);
3300 if (ret == NULL)
3301 return(NULL);
3302 ret->type = XPATH_XSLT_TREE;
3303
3304 return(ret);
3305 }
3306
3307 /**
3308 * xmlXPathNewNodeSetList:
3309 * @val: an existing NodeSet
3310 *
3311 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3312 * it with the Nodeset @val
3313 *
3314 * Returns the newly created object.
3315 */
3316 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)3317 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3318 {
3319 xmlXPathObjectPtr ret;
3320
3321 if (val == NULL)
3322 ret = NULL;
3323 else if (val->nodeTab == NULL)
3324 ret = xmlXPathNewNodeSet(NULL);
3325 else {
3326 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3327 if (ret) {
3328 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3329 if (ret->nodesetval == NULL) {
3330 xmlFree(ret);
3331 return(NULL);
3332 }
3333 }
3334 }
3335
3336 return (ret);
3337 }
3338
3339 /**
3340 * xmlXPathWrapNodeSet:
3341 * @val: the NodePtr value
3342 *
3343 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3344 *
3345 * Returns the newly created object.
3346 *
3347 * In case of error the node set is destroyed and NULL is returned.
3348 */
3349 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)3350 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3351 xmlXPathObjectPtr ret;
3352
3353 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3354 if (ret == NULL) {
3355 xmlXPathFreeNodeSet(val);
3356 return(NULL);
3357 }
3358 memset(ret, 0 , sizeof(xmlXPathObject));
3359 ret->type = XPATH_NODESET;
3360 ret->nodesetval = val;
3361 return(ret);
3362 }
3363
3364 /**
3365 * xmlXPathFreeNodeSetList:
3366 * @obj: an existing NodeSetList object
3367 *
3368 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3369 * the list contrary to xmlXPathFreeObject().
3370 */
3371 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)3372 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3373 if (obj == NULL) return;
3374 xmlFree(obj);
3375 }
3376
3377 /**
3378 * xmlXPathDifference:
3379 * @nodes1: a node-set
3380 * @nodes2: a node-set
3381 *
3382 * Implements the EXSLT - Sets difference() function:
3383 * node-set set:difference (node-set, node-set)
3384 *
3385 * Returns the difference between the two node sets, or nodes1 if
3386 * nodes2 is empty
3387 */
3388 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3389 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3390 xmlNodeSetPtr ret;
3391 int i, l1;
3392 xmlNodePtr cur;
3393
3394 if (xmlXPathNodeSetIsEmpty(nodes2))
3395 return(nodes1);
3396
3397 ret = xmlXPathNodeSetCreate(NULL);
3398 if (ret == NULL)
3399 return(NULL);
3400 if (xmlXPathNodeSetIsEmpty(nodes1))
3401 return(ret);
3402
3403 l1 = xmlXPathNodeSetGetLength(nodes1);
3404
3405 for (i = 0; i < l1; i++) {
3406 cur = xmlXPathNodeSetItem(nodes1, i);
3407 if (!xmlXPathNodeSetContains(nodes2, cur)) {
3408 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3409 xmlXPathFreeNodeSet(ret);
3410 return(NULL);
3411 }
3412 }
3413 }
3414 return(ret);
3415 }
3416
3417 /**
3418 * xmlXPathIntersection:
3419 * @nodes1: a node-set
3420 * @nodes2: a node-set
3421 *
3422 * Implements the EXSLT - Sets intersection() function:
3423 * node-set set:intersection (node-set, node-set)
3424 *
3425 * Returns a node set comprising the nodes that are within both the
3426 * node sets passed as arguments
3427 */
3428 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3429 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3430 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3431 int i, l1;
3432 xmlNodePtr cur;
3433
3434 if (ret == NULL)
3435 return(ret);
3436 if (xmlXPathNodeSetIsEmpty(nodes1))
3437 return(ret);
3438 if (xmlXPathNodeSetIsEmpty(nodes2))
3439 return(ret);
3440
3441 l1 = xmlXPathNodeSetGetLength(nodes1);
3442
3443 for (i = 0; i < l1; i++) {
3444 cur = xmlXPathNodeSetItem(nodes1, i);
3445 if (xmlXPathNodeSetContains(nodes2, cur)) {
3446 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3447 xmlXPathFreeNodeSet(ret);
3448 return(NULL);
3449 }
3450 }
3451 }
3452 return(ret);
3453 }
3454
3455 /**
3456 * xmlXPathDistinctSorted:
3457 * @nodes: a node-set, sorted by document order
3458 *
3459 * Implements the EXSLT - Sets distinct() function:
3460 * node-set set:distinct (node-set)
3461 *
3462 * Returns a subset of the nodes contained in @nodes, or @nodes if
3463 * it is empty
3464 */
3465 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)3466 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3467 xmlNodeSetPtr ret;
3468 xmlHashTablePtr hash;
3469 int i, l;
3470 xmlChar * strval;
3471 xmlNodePtr cur;
3472
3473 if (xmlXPathNodeSetIsEmpty(nodes))
3474 return(nodes);
3475
3476 ret = xmlXPathNodeSetCreate(NULL);
3477 if (ret == NULL)
3478 return(ret);
3479 l = xmlXPathNodeSetGetLength(nodes);
3480 hash = xmlHashCreate (l);
3481 for (i = 0; i < l; i++) {
3482 cur = xmlXPathNodeSetItem(nodes, i);
3483 strval = xmlXPathCastNodeToString(cur);
3484 if (xmlHashLookup(hash, strval) == NULL) {
3485 if (xmlHashAddEntry(hash, strval, strval) < 0) {
3486 xmlFree(strval);
3487 goto error;
3488 }
3489 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3490 goto error;
3491 } else {
3492 xmlFree(strval);
3493 }
3494 }
3495 xmlHashFree(hash, xmlHashDefaultDeallocator);
3496 return(ret);
3497
3498 error:
3499 xmlHashFree(hash, xmlHashDefaultDeallocator);
3500 xmlXPathFreeNodeSet(ret);
3501 return(NULL);
3502 }
3503
3504 /**
3505 * xmlXPathDistinct:
3506 * @nodes: a node-set
3507 *
3508 * Implements the EXSLT - Sets distinct() function:
3509 * node-set set:distinct (node-set)
3510 * @nodes is sorted by document order, then #exslSetsDistinctSorted
3511 * is called with the sorted node-set
3512 *
3513 * Returns a subset of the nodes contained in @nodes, or @nodes if
3514 * it is empty
3515 */
3516 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)3517 xmlXPathDistinct (xmlNodeSetPtr nodes) {
3518 if (xmlXPathNodeSetIsEmpty(nodes))
3519 return(nodes);
3520
3521 xmlXPathNodeSetSort(nodes);
3522 return(xmlXPathDistinctSorted(nodes));
3523 }
3524
3525 /**
3526 * xmlXPathHasSameNodes:
3527 * @nodes1: a node-set
3528 * @nodes2: a node-set
3529 *
3530 * Implements the EXSLT - Sets has-same-nodes function:
3531 * boolean set:has-same-node(node-set, node-set)
3532 *
3533 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3534 * otherwise
3535 */
3536 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3537 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3538 int i, l;
3539 xmlNodePtr cur;
3540
3541 if (xmlXPathNodeSetIsEmpty(nodes1) ||
3542 xmlXPathNodeSetIsEmpty(nodes2))
3543 return(0);
3544
3545 l = xmlXPathNodeSetGetLength(nodes1);
3546 for (i = 0; i < l; i++) {
3547 cur = xmlXPathNodeSetItem(nodes1, i);
3548 if (xmlXPathNodeSetContains(nodes2, cur))
3549 return(1);
3550 }
3551 return(0);
3552 }
3553
3554 /**
3555 * xmlXPathNodeLeadingSorted:
3556 * @nodes: a node-set, sorted by document order
3557 * @node: a node
3558 *
3559 * Implements the EXSLT - Sets leading() function:
3560 * node-set set:leading (node-set, node-set)
3561 *
3562 * Returns the nodes in @nodes that precede @node in document order,
3563 * @nodes if @node is NULL or an empty node-set if @nodes
3564 * doesn't contain @node
3565 */
3566 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3567 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3568 int i, l;
3569 xmlNodePtr cur;
3570 xmlNodeSetPtr ret;
3571
3572 if (node == NULL)
3573 return(nodes);
3574
3575 ret = xmlXPathNodeSetCreate(NULL);
3576 if (ret == NULL)
3577 return(ret);
3578 if (xmlXPathNodeSetIsEmpty(nodes) ||
3579 (!xmlXPathNodeSetContains(nodes, node)))
3580 return(ret);
3581
3582 l = xmlXPathNodeSetGetLength(nodes);
3583 for (i = 0; i < l; i++) {
3584 cur = xmlXPathNodeSetItem(nodes, i);
3585 if (cur == node)
3586 break;
3587 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3588 xmlXPathFreeNodeSet(ret);
3589 return(NULL);
3590 }
3591 }
3592 return(ret);
3593 }
3594
3595 /**
3596 * xmlXPathNodeLeading:
3597 * @nodes: a node-set
3598 * @node: a node
3599 *
3600 * Implements the EXSLT - Sets leading() function:
3601 * node-set set:leading (node-set, node-set)
3602 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3603 * is called.
3604 *
3605 * Returns the nodes in @nodes that precede @node in document order,
3606 * @nodes if @node is NULL or an empty node-set if @nodes
3607 * doesn't contain @node
3608 */
3609 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)3610 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3611 xmlXPathNodeSetSort(nodes);
3612 return(xmlXPathNodeLeadingSorted(nodes, node));
3613 }
3614
3615 /**
3616 * xmlXPathLeadingSorted:
3617 * @nodes1: a node-set, sorted by document order
3618 * @nodes2: a node-set, sorted by document order
3619 *
3620 * Implements the EXSLT - Sets leading() function:
3621 * node-set set:leading (node-set, node-set)
3622 *
3623 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3624 * in document order, @nodes1 if @nodes2 is NULL or empty or
3625 * an empty node-set if @nodes1 doesn't contain @nodes2
3626 */
3627 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3628 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3629 if (xmlXPathNodeSetIsEmpty(nodes2))
3630 return(nodes1);
3631 return(xmlXPathNodeLeadingSorted(nodes1,
3632 xmlXPathNodeSetItem(nodes2, 1)));
3633 }
3634
3635 /**
3636 * xmlXPathLeading:
3637 * @nodes1: a node-set
3638 * @nodes2: a node-set
3639 *
3640 * Implements the EXSLT - Sets leading() function:
3641 * node-set set:leading (node-set, node-set)
3642 * @nodes1 and @nodes2 are sorted by document order, then
3643 * #exslSetsLeadingSorted is called.
3644 *
3645 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3646 * in document order, @nodes1 if @nodes2 is NULL or empty or
3647 * an empty node-set if @nodes1 doesn't contain @nodes2
3648 */
3649 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3650 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3651 if (xmlXPathNodeSetIsEmpty(nodes2))
3652 return(nodes1);
3653 if (xmlXPathNodeSetIsEmpty(nodes1))
3654 return(xmlXPathNodeSetCreate(NULL));
3655 xmlXPathNodeSetSort(nodes1);
3656 xmlXPathNodeSetSort(nodes2);
3657 return(xmlXPathNodeLeadingSorted(nodes1,
3658 xmlXPathNodeSetItem(nodes2, 1)));
3659 }
3660
3661 /**
3662 * xmlXPathNodeTrailingSorted:
3663 * @nodes: a node-set, sorted by document order
3664 * @node: a node
3665 *
3666 * Implements the EXSLT - Sets trailing() function:
3667 * node-set set:trailing (node-set, node-set)
3668 *
3669 * Returns the nodes in @nodes that follow @node in document order,
3670 * @nodes if @node is NULL or an empty node-set if @nodes
3671 * doesn't contain @node
3672 */
3673 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3674 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3675 int i, l;
3676 xmlNodePtr cur;
3677 xmlNodeSetPtr ret;
3678
3679 if (node == NULL)
3680 return(nodes);
3681
3682 ret = xmlXPathNodeSetCreate(NULL);
3683 if (ret == NULL)
3684 return(ret);
3685 if (xmlXPathNodeSetIsEmpty(nodes) ||
3686 (!xmlXPathNodeSetContains(nodes, node)))
3687 return(ret);
3688
3689 l = xmlXPathNodeSetGetLength(nodes);
3690 for (i = l - 1; i >= 0; i--) {
3691 cur = xmlXPathNodeSetItem(nodes, i);
3692 if (cur == node)
3693 break;
3694 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3695 xmlXPathFreeNodeSet(ret);
3696 return(NULL);
3697 }
3698 }
3699 xmlXPathNodeSetSort(ret); /* bug 413451 */
3700 return(ret);
3701 }
3702
3703 /**
3704 * xmlXPathNodeTrailing:
3705 * @nodes: a node-set
3706 * @node: a node
3707 *
3708 * Implements the EXSLT - Sets trailing() function:
3709 * node-set set:trailing (node-set, node-set)
3710 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3711 * is called.
3712 *
3713 * Returns the nodes in @nodes that follow @node in document order,
3714 * @nodes if @node is NULL or an empty node-set if @nodes
3715 * doesn't contain @node
3716 */
3717 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)3718 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3719 xmlXPathNodeSetSort(nodes);
3720 return(xmlXPathNodeTrailingSorted(nodes, node));
3721 }
3722
3723 /**
3724 * xmlXPathTrailingSorted:
3725 * @nodes1: a node-set, sorted by document order
3726 * @nodes2: a node-set, sorted by document order
3727 *
3728 * Implements the EXSLT - Sets trailing() function:
3729 * node-set set:trailing (node-set, node-set)
3730 *
3731 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3732 * in document order, @nodes1 if @nodes2 is NULL or empty or
3733 * an empty node-set if @nodes1 doesn't contain @nodes2
3734 */
3735 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3736 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3737 if (xmlXPathNodeSetIsEmpty(nodes2))
3738 return(nodes1);
3739 return(xmlXPathNodeTrailingSorted(nodes1,
3740 xmlXPathNodeSetItem(nodes2, 0)));
3741 }
3742
3743 /**
3744 * xmlXPathTrailing:
3745 * @nodes1: a node-set
3746 * @nodes2: a node-set
3747 *
3748 * Implements the EXSLT - Sets trailing() function:
3749 * node-set set:trailing (node-set, node-set)
3750 * @nodes1 and @nodes2 are sorted by document order, then
3751 * #xmlXPathTrailingSorted is called.
3752 *
3753 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3754 * in document order, @nodes1 if @nodes2 is NULL or empty or
3755 * an empty node-set if @nodes1 doesn't contain @nodes2
3756 */
3757 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3758 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3759 if (xmlXPathNodeSetIsEmpty(nodes2))
3760 return(nodes1);
3761 if (xmlXPathNodeSetIsEmpty(nodes1))
3762 return(xmlXPathNodeSetCreate(NULL));
3763 xmlXPathNodeSetSort(nodes1);
3764 xmlXPathNodeSetSort(nodes2);
3765 return(xmlXPathNodeTrailingSorted(nodes1,
3766 xmlXPathNodeSetItem(nodes2, 0)));
3767 }
3768
3769 /************************************************************************
3770 * *
3771 * Routines to handle extra functions *
3772 * *
3773 ************************************************************************/
3774
3775 /**
3776 * xmlXPathRegisterFunc:
3777 * @ctxt: the XPath context
3778 * @name: the function name
3779 * @f: the function implementation or NULL
3780 *
3781 * Register a new function. If @f is NULL it unregisters the function
3782 *
3783 * Returns 0 in case of success, -1 in case of error
3784 */
3785 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)3786 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3787 xmlXPathFunction f) {
3788 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3789 }
3790
3791 /**
3792 * xmlXPathRegisterFuncNS:
3793 * @ctxt: the XPath context
3794 * @name: the function name
3795 * @ns_uri: the function namespace URI
3796 * @f: the function implementation or NULL
3797 *
3798 * Register a new function. If @f is NULL it unregisters the function
3799 *
3800 * Returns 0 in case of success, -1 in case of error
3801 */
3802 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)3803 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3804 const xmlChar *ns_uri, xmlXPathFunction f) {
3805 int ret;
3806
3807 if (ctxt == NULL)
3808 return(-1);
3809 if (name == NULL)
3810 return(-1);
3811
3812 if (ctxt->funcHash == NULL)
3813 ctxt->funcHash = xmlHashCreate(0);
3814 if (ctxt->funcHash == NULL) {
3815 xmlXPathErrMemory(ctxt);
3816 return(-1);
3817 }
3818 if (f == NULL)
3819 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3820 XML_IGNORE_FPTR_CAST_WARNINGS
3821 ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3822 XML_POP_WARNINGS
3823 if (ret < 0) {
3824 xmlXPathErrMemory(ctxt);
3825 return(-1);
3826 }
3827
3828 return(0);
3829 }
3830
3831 /**
3832 * xmlXPathRegisterFuncLookup:
3833 * @ctxt: the XPath context
3834 * @f: the lookup function
3835 * @funcCtxt: the lookup data
3836 *
3837 * Registers an external mechanism to do function lookup.
3838 */
3839 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)3840 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3841 xmlXPathFuncLookupFunc f,
3842 void *funcCtxt) {
3843 if (ctxt == NULL)
3844 return;
3845 ctxt->funcLookupFunc = f;
3846 ctxt->funcLookupData = funcCtxt;
3847 }
3848
3849 /**
3850 * xmlXPathFunctionLookup:
3851 * @ctxt: the XPath context
3852 * @name: the function name
3853 *
3854 * Search in the Function array of the context for the given
3855 * function.
3856 *
3857 * Returns the xmlXPathFunction or NULL if not found
3858 */
3859 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)3860 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3861 if (ctxt == NULL)
3862 return (NULL);
3863
3864 if (ctxt->funcLookupFunc != NULL) {
3865 xmlXPathFunction ret;
3866 xmlXPathFuncLookupFunc f;
3867
3868 f = ctxt->funcLookupFunc;
3869 ret = f(ctxt->funcLookupData, name, NULL);
3870 if (ret != NULL)
3871 return(ret);
3872 }
3873 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3874 }
3875
3876 /**
3877 * xmlXPathFunctionLookupNS:
3878 * @ctxt: the XPath context
3879 * @name: the function name
3880 * @ns_uri: the function namespace URI
3881 *
3882 * Search in the Function array of the context for the given
3883 * function.
3884 *
3885 * Returns the xmlXPathFunction or NULL if not found
3886 */
3887 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)3888 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3889 const xmlChar *ns_uri) {
3890 xmlXPathFunction ret;
3891
3892 if (ctxt == NULL)
3893 return(NULL);
3894 if (name == NULL)
3895 return(NULL);
3896
3897 if (ctxt->funcLookupFunc != NULL) {
3898 xmlXPathFuncLookupFunc f;
3899
3900 f = ctxt->funcLookupFunc;
3901 ret = f(ctxt->funcLookupData, name, ns_uri);
3902 if (ret != NULL)
3903 return(ret);
3904 }
3905
3906 if (ctxt->funcHash == NULL)
3907 return(NULL);
3908
3909 XML_IGNORE_FPTR_CAST_WARNINGS
3910 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3911 XML_POP_WARNINGS
3912 return(ret);
3913 }
3914
3915 /**
3916 * xmlXPathRegisteredFuncsCleanup:
3917 * @ctxt: the XPath context
3918 *
3919 * Cleanup the XPath context data associated to registered functions
3920 */
3921 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)3922 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
3923 if (ctxt == NULL)
3924 return;
3925
3926 xmlHashFree(ctxt->funcHash, NULL);
3927 ctxt->funcHash = NULL;
3928 }
3929
3930 /************************************************************************
3931 * *
3932 * Routines to handle Variables *
3933 * *
3934 ************************************************************************/
3935
3936 /**
3937 * xmlXPathRegisterVariable:
3938 * @ctxt: the XPath context
3939 * @name: the variable name
3940 * @value: the variable value or NULL
3941 *
3942 * Register a new variable value. If @value is NULL it unregisters
3943 * the variable
3944 *
3945 * Returns 0 in case of success, -1 in case of error
3946 */
3947 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)3948 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
3949 xmlXPathObjectPtr value) {
3950 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3951 }
3952
3953 /**
3954 * xmlXPathRegisterVariableNS:
3955 * @ctxt: the XPath context
3956 * @name: the variable name
3957 * @ns_uri: the variable namespace URI
3958 * @value: the variable value or NULL
3959 *
3960 * Register a new variable value. If @value is NULL it unregisters
3961 * the variable
3962 *
3963 * Returns 0 in case of success, -1 in case of error
3964 */
3965 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)3966 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3967 const xmlChar *ns_uri,
3968 xmlXPathObjectPtr value) {
3969 if (ctxt == NULL)
3970 return(-1);
3971 if (name == NULL)
3972 return(-1);
3973
3974 if (ctxt->varHash == NULL)
3975 ctxt->varHash = xmlHashCreate(0);
3976 if (ctxt->varHash == NULL)
3977 return(-1);
3978 if (value == NULL)
3979 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3980 xmlXPathFreeObjectEntry));
3981 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3982 (void *) value, xmlXPathFreeObjectEntry));
3983 }
3984
3985 /**
3986 * xmlXPathRegisterVariableLookup:
3987 * @ctxt: the XPath context
3988 * @f: the lookup function
3989 * @data: the lookup data
3990 *
3991 * register an external mechanism to do variable lookup
3992 */
3993 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)3994 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3995 xmlXPathVariableLookupFunc f, void *data) {
3996 if (ctxt == NULL)
3997 return;
3998 ctxt->varLookupFunc = f;
3999 ctxt->varLookupData = data;
4000 }
4001
4002 /**
4003 * xmlXPathVariableLookup:
4004 * @ctxt: the XPath context
4005 * @name: the variable name
4006 *
4007 * Search in the Variable array of the context for the given
4008 * variable value.
4009 *
4010 * Returns a copy of the value or NULL if not found
4011 */
4012 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4013 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4014 if (ctxt == NULL)
4015 return(NULL);
4016
4017 if (ctxt->varLookupFunc != NULL) {
4018 xmlXPathObjectPtr ret;
4019
4020 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4021 (ctxt->varLookupData, name, NULL);
4022 return(ret);
4023 }
4024 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4025 }
4026
4027 /**
4028 * xmlXPathVariableLookupNS:
4029 * @ctxt: the XPath context
4030 * @name: the variable name
4031 * @ns_uri: the variable namespace URI
4032 *
4033 * Search in the Variable array of the context for the given
4034 * variable value.
4035 *
4036 * Returns the a copy of the value or NULL if not found
4037 */
4038 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4039 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4040 const xmlChar *ns_uri) {
4041 if (ctxt == NULL)
4042 return(NULL);
4043
4044 if (ctxt->varLookupFunc != NULL) {
4045 xmlXPathObjectPtr ret;
4046
4047 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4048 (ctxt->varLookupData, name, ns_uri);
4049 if (ret != NULL) return(ret);
4050 }
4051
4052 if (ctxt->varHash == NULL)
4053 return(NULL);
4054 if (name == NULL)
4055 return(NULL);
4056
4057 return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4058 }
4059
4060 /**
4061 * xmlXPathRegisteredVariablesCleanup:
4062 * @ctxt: the XPath context
4063 *
4064 * Cleanup the XPath context data associated to registered variables
4065 */
4066 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)4067 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4068 if (ctxt == NULL)
4069 return;
4070
4071 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4072 ctxt->varHash = NULL;
4073 }
4074
4075 /**
4076 * xmlXPathRegisterNs:
4077 * @ctxt: the XPath context
4078 * @prefix: the namespace prefix cannot be NULL or empty string
4079 * @ns_uri: the namespace name
4080 *
4081 * Register a new namespace. If @ns_uri is NULL it unregisters
4082 * the namespace
4083 *
4084 * Returns 0 in case of success, -1 in case of error
4085 */
4086 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)4087 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4088 const xmlChar *ns_uri) {
4089 xmlChar *copy;
4090
4091 if (ctxt == NULL)
4092 return(-1);
4093 if (prefix == NULL)
4094 return(-1);
4095 if (prefix[0] == 0)
4096 return(-1);
4097
4098 if (ctxt->nsHash == NULL)
4099 ctxt->nsHash = xmlHashCreate(10);
4100 if (ctxt->nsHash == NULL) {
4101 xmlXPathErrMemory(ctxt);
4102 return(-1);
4103 }
4104 if (ns_uri == NULL)
4105 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4106 xmlHashDefaultDeallocator));
4107
4108 copy = xmlStrdup(ns_uri);
4109 if (copy == NULL) {
4110 xmlXPathErrMemory(ctxt);
4111 return(-1);
4112 }
4113 if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4114 xmlHashDefaultDeallocator) < 0) {
4115 xmlXPathErrMemory(ctxt);
4116 xmlFree(copy);
4117 return(-1);
4118 }
4119
4120 return(0);
4121 }
4122
4123 /**
4124 * xmlXPathNsLookup:
4125 * @ctxt: the XPath context
4126 * @prefix: the namespace prefix value
4127 *
4128 * Search in the namespace declaration array of the context for the given
4129 * namespace name associated to the given prefix
4130 *
4131 * Returns the value or NULL if not found
4132 */
4133 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)4134 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4135 if (ctxt == NULL)
4136 return(NULL);
4137 if (prefix == NULL)
4138 return(NULL);
4139
4140 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4141 return(XML_XML_NAMESPACE);
4142
4143 if (ctxt->namespaces != NULL) {
4144 int i;
4145
4146 for (i = 0;i < ctxt->nsNr;i++) {
4147 if ((ctxt->namespaces[i] != NULL) &&
4148 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4149 return(ctxt->namespaces[i]->href);
4150 }
4151 }
4152
4153 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4154 }
4155
4156 /**
4157 * xmlXPathRegisteredNsCleanup:
4158 * @ctxt: the XPath context
4159 *
4160 * Cleanup the XPath context data associated to registered variables
4161 */
4162 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)4163 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4164 if (ctxt == NULL)
4165 return;
4166
4167 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4168 ctxt->nsHash = NULL;
4169 }
4170
4171 /************************************************************************
4172 * *
4173 * Routines to handle Values *
4174 * *
4175 ************************************************************************/
4176
4177 /* Allocations are terrible, one needs to optimize all this !!! */
4178
4179 /**
4180 * xmlXPathNewFloat:
4181 * @val: the double value
4182 *
4183 * Create a new xmlXPathObjectPtr of type double and of value @val
4184 *
4185 * Returns the newly created object.
4186 */
4187 xmlXPathObjectPtr
xmlXPathNewFloat(double val)4188 xmlXPathNewFloat(double val) {
4189 xmlXPathObjectPtr ret;
4190
4191 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4192 if (ret == NULL)
4193 return(NULL);
4194 memset(ret, 0 , sizeof(xmlXPathObject));
4195 ret->type = XPATH_NUMBER;
4196 ret->floatval = val;
4197 return(ret);
4198 }
4199
4200 /**
4201 * xmlXPathNewBoolean:
4202 * @val: the boolean value
4203 *
4204 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4205 *
4206 * Returns the newly created object.
4207 */
4208 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)4209 xmlXPathNewBoolean(int val) {
4210 xmlXPathObjectPtr ret;
4211
4212 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4213 if (ret == NULL)
4214 return(NULL);
4215 memset(ret, 0 , sizeof(xmlXPathObject));
4216 ret->type = XPATH_BOOLEAN;
4217 ret->boolval = (val != 0);
4218 return(ret);
4219 }
4220
4221 /**
4222 * xmlXPathNewString:
4223 * @val: the xmlChar * value
4224 *
4225 * Create a new xmlXPathObjectPtr of type string and of value @val
4226 *
4227 * Returns the newly created object.
4228 */
4229 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)4230 xmlXPathNewString(const xmlChar *val) {
4231 xmlXPathObjectPtr ret;
4232
4233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4234 if (ret == NULL)
4235 return(NULL);
4236 memset(ret, 0 , sizeof(xmlXPathObject));
4237 ret->type = XPATH_STRING;
4238 if (val == NULL)
4239 val = BAD_CAST "";
4240 ret->stringval = xmlStrdup(val);
4241 if (ret->stringval == NULL) {
4242 xmlFree(ret);
4243 return(NULL);
4244 }
4245 return(ret);
4246 }
4247
4248 /**
4249 * xmlXPathWrapString:
4250 * @val: the xmlChar * value
4251 *
4252 * Wraps the @val string into an XPath object.
4253 *
4254 * Returns the newly created object.
4255 *
4256 * Frees @val in case of error.
4257 */
4258 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)4259 xmlXPathWrapString (xmlChar *val) {
4260 xmlXPathObjectPtr ret;
4261
4262 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4263 if (ret == NULL) {
4264 xmlFree(val);
4265 return(NULL);
4266 }
4267 memset(ret, 0 , sizeof(xmlXPathObject));
4268 ret->type = XPATH_STRING;
4269 ret->stringval = val;
4270 return(ret);
4271 }
4272
4273 /**
4274 * xmlXPathNewCString:
4275 * @val: the char * value
4276 *
4277 * Create a new xmlXPathObjectPtr of type string and of value @val
4278 *
4279 * Returns the newly created object.
4280 */
4281 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)4282 xmlXPathNewCString(const char *val) {
4283 return(xmlXPathNewString(BAD_CAST val));
4284 }
4285
4286 /**
4287 * xmlXPathWrapCString:
4288 * @val: the char * value
4289 *
4290 * Wraps a string into an XPath object.
4291 *
4292 * Returns the newly created object.
4293 */
4294 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)4295 xmlXPathWrapCString (char * val) {
4296 return(xmlXPathWrapString((xmlChar *)(val)));
4297 }
4298
4299 /**
4300 * xmlXPathWrapExternal:
4301 * @val: the user data
4302 *
4303 * Wraps the @val data into an XPath object.
4304 *
4305 * Returns the newly created object.
4306 */
4307 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)4308 xmlXPathWrapExternal (void *val) {
4309 xmlXPathObjectPtr ret;
4310
4311 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4312 if (ret == NULL)
4313 return(NULL);
4314 memset(ret, 0 , sizeof(xmlXPathObject));
4315 ret->type = XPATH_USERS;
4316 ret->user = val;
4317 return(ret);
4318 }
4319
4320 /**
4321 * xmlXPathObjectCopy:
4322 * @val: the original object
4323 *
4324 * allocate a new copy of a given object
4325 *
4326 * Returns the newly created object.
4327 */
4328 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)4329 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4330 xmlXPathObjectPtr ret;
4331
4332 if (val == NULL)
4333 return(NULL);
4334
4335 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4336 if (ret == NULL)
4337 return(NULL);
4338 memcpy(ret, val , sizeof(xmlXPathObject));
4339 switch (val->type) {
4340 case XPATH_BOOLEAN:
4341 case XPATH_NUMBER:
4342 break;
4343 case XPATH_STRING:
4344 ret->stringval = xmlStrdup(val->stringval);
4345 if (ret->stringval == NULL) {
4346 xmlFree(ret);
4347 return(NULL);
4348 }
4349 break;
4350 case XPATH_XSLT_TREE:
4351 case XPATH_NODESET:
4352 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4353 if (ret->nodesetval == NULL) {
4354 xmlFree(ret);
4355 return(NULL);
4356 }
4357 /* Do not deallocate the copied tree value */
4358 ret->boolval = 0;
4359 break;
4360 case XPATH_USERS:
4361 ret->user = val->user;
4362 break;
4363 default:
4364 xmlFree(ret);
4365 ret = NULL;
4366 break;
4367 }
4368 return(ret);
4369 }
4370
4371 /**
4372 * xmlXPathFreeObject:
4373 * @obj: the object to free
4374 *
4375 * Free up an xmlXPathObjectPtr object.
4376 */
4377 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)4378 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4379 if (obj == NULL) return;
4380 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4381 if (obj->nodesetval != NULL)
4382 xmlXPathFreeNodeSet(obj->nodesetval);
4383 } else if (obj->type == XPATH_STRING) {
4384 if (obj->stringval != NULL)
4385 xmlFree(obj->stringval);
4386 }
4387 xmlFree(obj);
4388 }
4389
4390 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)4391 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4392 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4393 }
4394
4395 /**
4396 * xmlXPathReleaseObject:
4397 * @obj: the xmlXPathObjectPtr to free or to cache
4398 *
4399 * Depending on the state of the cache this frees the given
4400 * XPath object or stores it in the cache.
4401 */
4402 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)4403 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4404 {
4405 if (obj == NULL)
4406 return;
4407 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4408 xmlXPathFreeObject(obj);
4409 } else {
4410 xmlXPathContextCachePtr cache =
4411 (xmlXPathContextCachePtr) ctxt->cache;
4412
4413 switch (obj->type) {
4414 case XPATH_NODESET:
4415 case XPATH_XSLT_TREE:
4416 if (obj->nodesetval != NULL) {
4417 if ((obj->nodesetval->nodeMax <= 40) &&
4418 (cache->numNodeset < cache->maxNodeset)) {
4419 obj->stringval = (void *) cache->nodesetObjs;
4420 cache->nodesetObjs = obj;
4421 cache->numNodeset += 1;
4422 goto obj_cached;
4423 } else {
4424 xmlXPathFreeNodeSet(obj->nodesetval);
4425 obj->nodesetval = NULL;
4426 }
4427 }
4428 break;
4429 case XPATH_STRING:
4430 if (obj->stringval != NULL)
4431 xmlFree(obj->stringval);
4432 obj->stringval = NULL;
4433 break;
4434 case XPATH_BOOLEAN:
4435 case XPATH_NUMBER:
4436 break;
4437 default:
4438 goto free_obj;
4439 }
4440
4441 /*
4442 * Fallback to adding to the misc-objects slot.
4443 */
4444 if (cache->numMisc >= cache->maxMisc)
4445 goto free_obj;
4446 obj->stringval = (void *) cache->miscObjs;
4447 cache->miscObjs = obj;
4448 cache->numMisc += 1;
4449
4450 obj_cached:
4451 obj->boolval = 0;
4452 if (obj->nodesetval != NULL) {
4453 xmlNodeSetPtr tmpset = obj->nodesetval;
4454
4455 /*
4456 * Due to those nasty ns-nodes, we need to traverse
4457 * the list and free the ns-nodes.
4458 */
4459 if (tmpset->nodeNr > 0) {
4460 int i;
4461 xmlNodePtr node;
4462
4463 for (i = 0; i < tmpset->nodeNr; i++) {
4464 node = tmpset->nodeTab[i];
4465 if ((node != NULL) &&
4466 (node->type == XML_NAMESPACE_DECL))
4467 {
4468 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4469 }
4470 }
4471 }
4472 tmpset->nodeNr = 0;
4473 }
4474
4475 return;
4476
4477 free_obj:
4478 /*
4479 * Cache is full; free the object.
4480 */
4481 if (obj->nodesetval != NULL)
4482 xmlXPathFreeNodeSet(obj->nodesetval);
4483 xmlFree(obj);
4484 }
4485 }
4486
4487
4488 /************************************************************************
4489 * *
4490 * Type Casting Routines *
4491 * *
4492 ************************************************************************/
4493
4494 /**
4495 * xmlXPathCastBooleanToString:
4496 * @val: a boolean
4497 *
4498 * Converts a boolean to its string value.
4499 *
4500 * Returns a newly allocated string.
4501 */
4502 xmlChar *
xmlXPathCastBooleanToString(int val)4503 xmlXPathCastBooleanToString (int val) {
4504 xmlChar *ret;
4505 if (val)
4506 ret = xmlStrdup((const xmlChar *) "true");
4507 else
4508 ret = xmlStrdup((const xmlChar *) "false");
4509 return(ret);
4510 }
4511
4512 /**
4513 * xmlXPathCastNumberToString:
4514 * @val: a number
4515 *
4516 * Converts a number to its string value.
4517 *
4518 * Returns a newly allocated string.
4519 */
4520 xmlChar *
xmlXPathCastNumberToString(double val)4521 xmlXPathCastNumberToString (double val) {
4522 xmlChar *ret;
4523 switch (xmlXPathIsInf(val)) {
4524 case 1:
4525 ret = xmlStrdup((const xmlChar *) "Infinity");
4526 break;
4527 case -1:
4528 ret = xmlStrdup((const xmlChar *) "-Infinity");
4529 break;
4530 default:
4531 if (xmlXPathIsNaN(val)) {
4532 ret = xmlStrdup((const xmlChar *) "NaN");
4533 } else if (val == 0) {
4534 /* Omit sign for negative zero. */
4535 ret = xmlStrdup((const xmlChar *) "0");
4536 } else {
4537 /* could be improved */
4538 char buf[100];
4539 xmlXPathFormatNumber(val, buf, 99);
4540 buf[99] = 0;
4541 ret = xmlStrdup((const xmlChar *) buf);
4542 }
4543 }
4544 return(ret);
4545 }
4546
4547 /**
4548 * xmlXPathCastNodeToString:
4549 * @node: a node
4550 *
4551 * Converts a node to its string value.
4552 *
4553 * Returns a newly allocated string.
4554 */
4555 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)4556 xmlXPathCastNodeToString (xmlNodePtr node) {
4557 return(xmlNodeGetContent(node));
4558 }
4559
4560 /**
4561 * xmlXPathCastNodeSetToString:
4562 * @ns: a node-set
4563 *
4564 * Converts a node-set to its string value.
4565 *
4566 * Returns a newly allocated string.
4567 */
4568 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)4569 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4570 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4571 return(xmlStrdup((const xmlChar *) ""));
4572
4573 if (ns->nodeNr > 1)
4574 xmlXPathNodeSetSort(ns);
4575 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4576 }
4577
4578 /**
4579 * xmlXPathCastToString:
4580 * @val: an XPath object
4581 *
4582 * Converts an existing object to its string() equivalent
4583 *
4584 * Returns the allocated string value of the object, NULL in case of error.
4585 * It's up to the caller to free the string memory with xmlFree().
4586 */
4587 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)4588 xmlXPathCastToString(xmlXPathObjectPtr val) {
4589 xmlChar *ret = NULL;
4590
4591 if (val == NULL)
4592 return(xmlStrdup((const xmlChar *) ""));
4593 switch (val->type) {
4594 case XPATH_UNDEFINED:
4595 ret = xmlStrdup((const xmlChar *) "");
4596 break;
4597 case XPATH_NODESET:
4598 case XPATH_XSLT_TREE:
4599 ret = xmlXPathCastNodeSetToString(val->nodesetval);
4600 break;
4601 case XPATH_STRING:
4602 return(xmlStrdup(val->stringval));
4603 case XPATH_BOOLEAN:
4604 ret = xmlXPathCastBooleanToString(val->boolval);
4605 break;
4606 case XPATH_NUMBER: {
4607 ret = xmlXPathCastNumberToString(val->floatval);
4608 break;
4609 }
4610 case XPATH_USERS:
4611 /* TODO */
4612 ret = xmlStrdup((const xmlChar *) "");
4613 break;
4614 }
4615 return(ret);
4616 }
4617
4618 /**
4619 * xmlXPathConvertString:
4620 * @val: an XPath object
4621 *
4622 * Converts an existing object to its string() equivalent
4623 *
4624 * Returns the new object, the old one is freed (or the operation
4625 * is done directly on @val)
4626 */
4627 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)4628 xmlXPathConvertString(xmlXPathObjectPtr val) {
4629 xmlChar *res = NULL;
4630
4631 if (val == NULL)
4632 return(xmlXPathNewCString(""));
4633
4634 switch (val->type) {
4635 case XPATH_UNDEFINED:
4636 break;
4637 case XPATH_NODESET:
4638 case XPATH_XSLT_TREE:
4639 res = xmlXPathCastNodeSetToString(val->nodesetval);
4640 break;
4641 case XPATH_STRING:
4642 return(val);
4643 case XPATH_BOOLEAN:
4644 res = xmlXPathCastBooleanToString(val->boolval);
4645 break;
4646 case XPATH_NUMBER:
4647 res = xmlXPathCastNumberToString(val->floatval);
4648 break;
4649 case XPATH_USERS:
4650 /* TODO */
4651 break;
4652 }
4653 xmlXPathFreeObject(val);
4654 if (res == NULL)
4655 return(xmlXPathNewCString(""));
4656 return(xmlXPathWrapString(res));
4657 }
4658
4659 /**
4660 * xmlXPathCastBooleanToNumber:
4661 * @val: a boolean
4662 *
4663 * Converts a boolean to its number value
4664 *
4665 * Returns the number value
4666 */
4667 double
xmlXPathCastBooleanToNumber(int val)4668 xmlXPathCastBooleanToNumber(int val) {
4669 if (val)
4670 return(1.0);
4671 return(0.0);
4672 }
4673
4674 /**
4675 * xmlXPathCastStringToNumber:
4676 * @val: a string
4677 *
4678 * Converts a string to its number value
4679 *
4680 * Returns the number value
4681 */
4682 double
xmlXPathCastStringToNumber(const xmlChar * val)4683 xmlXPathCastStringToNumber(const xmlChar * val) {
4684 return(xmlXPathStringEvalNumber(val));
4685 }
4686
4687 /**
4688 * xmlXPathNodeToNumberInternal:
4689 * @node: a node
4690 *
4691 * Converts a node to its number value
4692 *
4693 * Returns the number value
4694 */
4695 static double
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr node)4696 xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4697 xmlChar *strval;
4698 double ret;
4699
4700 if (node == NULL)
4701 return(xmlXPathNAN);
4702 strval = xmlXPathCastNodeToString(node);
4703 if (strval == NULL) {
4704 xmlXPathPErrMemory(ctxt);
4705 return(xmlXPathNAN);
4706 }
4707 ret = xmlXPathCastStringToNumber(strval);
4708 xmlFree(strval);
4709
4710 return(ret);
4711 }
4712
4713 /**
4714 * xmlXPathCastNodeToNumber:
4715 * @node: a node
4716 *
4717 * Converts a node to its number value
4718 *
4719 * Returns the number value
4720 */
4721 double
xmlXPathCastNodeToNumber(xmlNodePtr node)4722 xmlXPathCastNodeToNumber (xmlNodePtr node) {
4723 return(xmlXPathNodeToNumberInternal(NULL, node));
4724 }
4725
4726 /**
4727 * xmlXPathCastNodeSetToNumber:
4728 * @ns: a node-set
4729 *
4730 * Converts a node-set to its number value
4731 *
4732 * Returns the number value
4733 */
4734 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)4735 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4736 xmlChar *str;
4737 double ret;
4738
4739 if (ns == NULL)
4740 return(xmlXPathNAN);
4741 str = xmlXPathCastNodeSetToString(ns);
4742 ret = xmlXPathCastStringToNumber(str);
4743 xmlFree(str);
4744 return(ret);
4745 }
4746
4747 /**
4748 * xmlXPathCastToNumber:
4749 * @val: an XPath object
4750 *
4751 * Converts an XPath object to its number value
4752 *
4753 * Returns the number value
4754 */
4755 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)4756 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4757 return(xmlXPathCastToNumberInternal(NULL, val));
4758 }
4759
4760 /**
4761 * xmlXPathConvertNumber:
4762 * @val: an XPath object
4763 *
4764 * Converts an existing object to its number() equivalent
4765 *
4766 * Returns the new object, the old one is freed (or the operation
4767 * is done directly on @val)
4768 */
4769 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)4770 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4771 xmlXPathObjectPtr ret;
4772
4773 if (val == NULL)
4774 return(xmlXPathNewFloat(0.0));
4775 if (val->type == XPATH_NUMBER)
4776 return(val);
4777 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4778 xmlXPathFreeObject(val);
4779 return(ret);
4780 }
4781
4782 /**
4783 * xmlXPathCastNumberToBoolean:
4784 * @val: a number
4785 *
4786 * Converts a number to its boolean value
4787 *
4788 * Returns the boolean value
4789 */
4790 int
xmlXPathCastNumberToBoolean(double val)4791 xmlXPathCastNumberToBoolean (double val) {
4792 if (xmlXPathIsNaN(val) || (val == 0.0))
4793 return(0);
4794 return(1);
4795 }
4796
4797 /**
4798 * xmlXPathCastStringToBoolean:
4799 * @val: a string
4800 *
4801 * Converts a string to its boolean value
4802 *
4803 * Returns the boolean value
4804 */
4805 int
xmlXPathCastStringToBoolean(const xmlChar * val)4806 xmlXPathCastStringToBoolean (const xmlChar *val) {
4807 if ((val == NULL) || (xmlStrlen(val) == 0))
4808 return(0);
4809 return(1);
4810 }
4811
4812 /**
4813 * xmlXPathCastNodeSetToBoolean:
4814 * @ns: a node-set
4815 *
4816 * Converts a node-set to its boolean value
4817 *
4818 * Returns the boolean value
4819 */
4820 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)4821 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
4822 if ((ns == NULL) || (ns->nodeNr == 0))
4823 return(0);
4824 return(1);
4825 }
4826
4827 /**
4828 * xmlXPathCastToBoolean:
4829 * @val: an XPath object
4830 *
4831 * Converts an XPath object to its boolean value
4832 *
4833 * Returns the boolean value
4834 */
4835 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)4836 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
4837 int ret = 0;
4838
4839 if (val == NULL)
4840 return(0);
4841 switch (val->type) {
4842 case XPATH_UNDEFINED:
4843 ret = 0;
4844 break;
4845 case XPATH_NODESET:
4846 case XPATH_XSLT_TREE:
4847 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4848 break;
4849 case XPATH_STRING:
4850 ret = xmlXPathCastStringToBoolean(val->stringval);
4851 break;
4852 case XPATH_NUMBER:
4853 ret = xmlXPathCastNumberToBoolean(val->floatval);
4854 break;
4855 case XPATH_BOOLEAN:
4856 ret = val->boolval;
4857 break;
4858 case XPATH_USERS:
4859 /* TODO */
4860 ret = 0;
4861 break;
4862 }
4863 return(ret);
4864 }
4865
4866
4867 /**
4868 * xmlXPathConvertBoolean:
4869 * @val: an XPath object
4870 *
4871 * Converts an existing object to its boolean() equivalent
4872 *
4873 * Returns the new object, the old one is freed (or the operation
4874 * is done directly on @val)
4875 */
4876 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)4877 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4878 xmlXPathObjectPtr ret;
4879
4880 if (val == NULL)
4881 return(xmlXPathNewBoolean(0));
4882 if (val->type == XPATH_BOOLEAN)
4883 return(val);
4884 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4885 xmlXPathFreeObject(val);
4886 return(ret);
4887 }
4888
4889 /************************************************************************
4890 * *
4891 * Routines to handle XPath contexts *
4892 * *
4893 ************************************************************************/
4894
4895 /**
4896 * xmlXPathNewContext:
4897 * @doc: the XML document
4898 *
4899 * Create a new xmlXPathContext
4900 *
4901 * Returns the xmlXPathContext just allocated. The caller will need to free it.
4902 */
4903 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)4904 xmlXPathNewContext(xmlDocPtr doc) {
4905 xmlXPathContextPtr ret;
4906
4907 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4908 if (ret == NULL)
4909 return(NULL);
4910 memset(ret, 0 , sizeof(xmlXPathContext));
4911 ret->doc = doc;
4912 ret->node = NULL;
4913
4914 ret->varHash = NULL;
4915
4916 ret->nb_types = 0;
4917 ret->max_types = 0;
4918 ret->types = NULL;
4919
4920 ret->nb_axis = 0;
4921 ret->max_axis = 0;
4922 ret->axis = NULL;
4923
4924 ret->nsHash = NULL;
4925 ret->user = NULL;
4926
4927 ret->contextSize = -1;
4928 ret->proximityPosition = -1;
4929
4930 #ifdef XP_DEFAULT_CACHE_ON
4931 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
4932 xmlXPathFreeContext(ret);
4933 return(NULL);
4934 }
4935 #endif
4936
4937 xmlXPathRegisterAllFunctions(ret);
4938
4939 if (ret->lastError.code != XML_ERR_OK) {
4940 xmlXPathFreeContext(ret);
4941 return(NULL);
4942 }
4943
4944 return(ret);
4945 }
4946
4947 /**
4948 * xmlXPathFreeContext:
4949 * @ctxt: the context to free
4950 *
4951 * Free up an xmlXPathContext
4952 */
4953 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)4954 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
4955 if (ctxt == NULL) return;
4956
4957 if (ctxt->cache != NULL)
4958 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4959 xmlXPathRegisteredNsCleanup(ctxt);
4960 xmlXPathRegisteredFuncsCleanup(ctxt);
4961 xmlXPathRegisteredVariablesCleanup(ctxt);
4962 xmlResetError(&ctxt->lastError);
4963 xmlFree(ctxt);
4964 }
4965
4966 /**
4967 * xmlXPathSetErrorHandler:
4968 * @ctxt: the XPath context
4969 * @handler: error handler
4970 * @data: user data which will be passed to the handler
4971 *
4972 * Register a callback function that will be called on errors and
4973 * warnings. If handler is NULL, the error handler will be deactivated.
4974 *
4975 * Available since 2.13.0.
4976 */
4977 void
xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,xmlStructuredErrorFunc handler,void * data)4978 xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
4979 xmlStructuredErrorFunc handler, void *data) {
4980 if (ctxt == NULL)
4981 return;
4982
4983 ctxt->error = handler;
4984 ctxt->userData = data;
4985 }
4986
4987 /************************************************************************
4988 * *
4989 * Routines to handle XPath parser contexts *
4990 * *
4991 ************************************************************************/
4992
4993 /**
4994 * xmlXPathNewParserContext:
4995 * @str: the XPath expression
4996 * @ctxt: the XPath context
4997 *
4998 * Create a new xmlXPathParserContext
4999 *
5000 * Returns the xmlXPathParserContext just allocated.
5001 */
5002 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)5003 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5004 xmlXPathParserContextPtr ret;
5005
5006 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5007 if (ret == NULL) {
5008 xmlXPathErrMemory(ctxt);
5009 return(NULL);
5010 }
5011 memset(ret, 0 , sizeof(xmlXPathParserContext));
5012 ret->cur = ret->base = str;
5013 ret->context = ctxt;
5014
5015 ret->comp = xmlXPathNewCompExpr();
5016 if (ret->comp == NULL) {
5017 xmlXPathErrMemory(ctxt);
5018 xmlFree(ret->valueTab);
5019 xmlFree(ret);
5020 return(NULL);
5021 }
5022 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5023 ret->comp->dict = ctxt->dict;
5024 xmlDictReference(ret->comp->dict);
5025 }
5026
5027 return(ret);
5028 }
5029
5030 /**
5031 * xmlXPathCompParserContext:
5032 * @comp: the XPath compiled expression
5033 * @ctxt: the XPath context
5034 *
5035 * Create a new xmlXPathParserContext when processing a compiled expression
5036 *
5037 * Returns the xmlXPathParserContext just allocated.
5038 */
5039 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)5040 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5041 xmlXPathParserContextPtr ret;
5042
5043 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5044 if (ret == NULL) {
5045 xmlXPathErrMemory(ctxt);
5046 return(NULL);
5047 }
5048 memset(ret, 0 , sizeof(xmlXPathParserContext));
5049
5050 /* Allocate the value stack */
5051 ret->valueTab = (xmlXPathObjectPtr *)
5052 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5053 if (ret->valueTab == NULL) {
5054 xmlFree(ret);
5055 xmlXPathErrMemory(ctxt);
5056 return(NULL);
5057 }
5058 ret->valueNr = 0;
5059 ret->valueMax = 10;
5060 ret->value = NULL;
5061
5062 ret->context = ctxt;
5063 ret->comp = comp;
5064
5065 return(ret);
5066 }
5067
5068 /**
5069 * xmlXPathFreeParserContext:
5070 * @ctxt: the context to free
5071 *
5072 * Free up an xmlXPathParserContext
5073 */
5074 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)5075 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5076 int i;
5077
5078 if (ctxt->valueTab != NULL) {
5079 for (i = 0; i < ctxt->valueNr; i++) {
5080 if (ctxt->context)
5081 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5082 else
5083 xmlXPathFreeObject(ctxt->valueTab[i]);
5084 }
5085 xmlFree(ctxt->valueTab);
5086 }
5087 if (ctxt->comp != NULL) {
5088 #ifdef XPATH_STREAMING
5089 if (ctxt->comp->stream != NULL) {
5090 xmlFreePatternList(ctxt->comp->stream);
5091 ctxt->comp->stream = NULL;
5092 }
5093 #endif
5094 xmlXPathFreeCompExpr(ctxt->comp);
5095 }
5096 xmlFree(ctxt);
5097 }
5098
5099 /************************************************************************
5100 * *
5101 * The implicit core function library *
5102 * *
5103 ************************************************************************/
5104
5105 /**
5106 * xmlXPathNodeValHash:
5107 * @node: a node pointer
5108 *
5109 * Function computing the beginning of the string value of the node,
5110 * used to speed up comparisons
5111 *
5112 * Returns an int usable as a hash
5113 */
5114 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)5115 xmlXPathNodeValHash(xmlNodePtr node) {
5116 int len = 2;
5117 const xmlChar * string = NULL;
5118 xmlNodePtr tmp = NULL;
5119 unsigned int ret = 0;
5120
5121 if (node == NULL)
5122 return(0);
5123
5124 if (node->type == XML_DOCUMENT_NODE) {
5125 tmp = xmlDocGetRootElement((xmlDocPtr) node);
5126 if (tmp == NULL)
5127 node = node->children;
5128 else
5129 node = tmp;
5130
5131 if (node == NULL)
5132 return(0);
5133 }
5134
5135 switch (node->type) {
5136 case XML_COMMENT_NODE:
5137 case XML_PI_NODE:
5138 case XML_CDATA_SECTION_NODE:
5139 case XML_TEXT_NODE:
5140 string = node->content;
5141 if (string == NULL)
5142 return(0);
5143 if (string[0] == 0)
5144 return(0);
5145 return(string[0] + (string[1] << 8));
5146 case XML_NAMESPACE_DECL:
5147 string = ((xmlNsPtr)node)->href;
5148 if (string == NULL)
5149 return(0);
5150 if (string[0] == 0)
5151 return(0);
5152 return(string[0] + (string[1] << 8));
5153 case XML_ATTRIBUTE_NODE:
5154 tmp = ((xmlAttrPtr) node)->children;
5155 break;
5156 case XML_ELEMENT_NODE:
5157 tmp = node->children;
5158 break;
5159 default:
5160 return(0);
5161 }
5162 while (tmp != NULL) {
5163 switch (tmp->type) {
5164 case XML_CDATA_SECTION_NODE:
5165 case XML_TEXT_NODE:
5166 string = tmp->content;
5167 break;
5168 default:
5169 string = NULL;
5170 break;
5171 }
5172 if ((string != NULL) && (string[0] != 0)) {
5173 if (len == 1) {
5174 return(ret + (string[0] << 8));
5175 }
5176 if (string[1] == 0) {
5177 len = 1;
5178 ret = string[0];
5179 } else {
5180 return(string[0] + (string[1] << 8));
5181 }
5182 }
5183 /*
5184 * Skip to next node
5185 */
5186 if ((tmp->children != NULL) &&
5187 (tmp->type != XML_DTD_NODE) &&
5188 (tmp->type != XML_ENTITY_REF_NODE) &&
5189 (tmp->children->type != XML_ENTITY_DECL)) {
5190 tmp = tmp->children;
5191 continue;
5192 }
5193 if (tmp == node)
5194 break;
5195
5196 if (tmp->next != NULL) {
5197 tmp = tmp->next;
5198 continue;
5199 }
5200
5201 do {
5202 tmp = tmp->parent;
5203 if (tmp == NULL)
5204 break;
5205 if (tmp == node) {
5206 tmp = NULL;
5207 break;
5208 }
5209 if (tmp->next != NULL) {
5210 tmp = tmp->next;
5211 break;
5212 }
5213 } while (tmp != NULL);
5214 }
5215 return(ret);
5216 }
5217
5218 /**
5219 * xmlXPathStringHash:
5220 * @string: a string
5221 *
5222 * Function computing the beginning of the string value of the node,
5223 * used to speed up comparisons
5224 *
5225 * Returns an int usable as a hash
5226 */
5227 static unsigned int
xmlXPathStringHash(const xmlChar * string)5228 xmlXPathStringHash(const xmlChar * string) {
5229 if (string == NULL)
5230 return(0);
5231 if (string[0] == 0)
5232 return(0);
5233 return(string[0] + (string[1] << 8));
5234 }
5235
5236 /**
5237 * xmlXPathCompareNodeSetFloat:
5238 * @ctxt: the XPath Parser context
5239 * @inf: less than (1) or greater than (0)
5240 * @strict: is the comparison strict
5241 * @arg: the node set
5242 * @f: the value
5243 *
5244 * Implement the compare operation between a nodeset and a number
5245 * @ns < @val (1, 1, ...
5246 * @ns <= @val (1, 0, ...
5247 * @ns > @val (0, 1, ...
5248 * @ns >= @val (0, 0, ...
5249 *
5250 * If one object to be compared is a node-set and the other is a number,
5251 * then the comparison will be true if and only if there is a node in the
5252 * node-set such that the result of performing the comparison on the number
5253 * to be compared and on the result of converting the string-value of that
5254 * node to a number using the number function is true.
5255 *
5256 * Returns 0 or 1 depending on the results of the test.
5257 */
5258 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)5259 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5260 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5261 int i, ret = 0;
5262 xmlNodeSetPtr ns;
5263 xmlChar *str2;
5264
5265 if ((f == NULL) || (arg == NULL) ||
5266 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5267 xmlXPathReleaseObject(ctxt->context, arg);
5268 xmlXPathReleaseObject(ctxt->context, f);
5269 return(0);
5270 }
5271 ns = arg->nodesetval;
5272 if (ns != NULL) {
5273 for (i = 0;i < ns->nodeNr;i++) {
5274 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5275 if (str2 != NULL) {
5276 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5277 xmlFree(str2);
5278 xmlXPathNumberFunction(ctxt, 1);
5279 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5280 ret = xmlXPathCompareValues(ctxt, inf, strict);
5281 if (ret)
5282 break;
5283 } else {
5284 xmlXPathPErrMemory(ctxt);
5285 }
5286 }
5287 }
5288 xmlXPathReleaseObject(ctxt->context, arg);
5289 xmlXPathReleaseObject(ctxt->context, f);
5290 return(ret);
5291 }
5292
5293 /**
5294 * xmlXPathCompareNodeSetString:
5295 * @ctxt: the XPath Parser context
5296 * @inf: less than (1) or greater than (0)
5297 * @strict: is the comparison strict
5298 * @arg: the node set
5299 * @s: the value
5300 *
5301 * Implement the compare operation between a nodeset and a string
5302 * @ns < @val (1, 1, ...
5303 * @ns <= @val (1, 0, ...
5304 * @ns > @val (0, 1, ...
5305 * @ns >= @val (0, 0, ...
5306 *
5307 * If one object to be compared is a node-set and the other is a string,
5308 * then the comparison will be true if and only if there is a node in
5309 * the node-set such that the result of performing the comparison on the
5310 * string-value of the node and the other string is true.
5311 *
5312 * Returns 0 or 1 depending on the results of the test.
5313 */
5314 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)5315 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5316 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5317 int i, ret = 0;
5318 xmlNodeSetPtr ns;
5319 xmlChar *str2;
5320
5321 if ((s == NULL) || (arg == NULL) ||
5322 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5323 xmlXPathReleaseObject(ctxt->context, arg);
5324 xmlXPathReleaseObject(ctxt->context, s);
5325 return(0);
5326 }
5327 ns = arg->nodesetval;
5328 if (ns != NULL) {
5329 for (i = 0;i < ns->nodeNr;i++) {
5330 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5331 if (str2 != NULL) {
5332 valuePush(ctxt,
5333 xmlXPathCacheNewString(ctxt, str2));
5334 xmlFree(str2);
5335 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5336 ret = xmlXPathCompareValues(ctxt, inf, strict);
5337 if (ret)
5338 break;
5339 } else {
5340 xmlXPathPErrMemory(ctxt);
5341 }
5342 }
5343 }
5344 xmlXPathReleaseObject(ctxt->context, arg);
5345 xmlXPathReleaseObject(ctxt->context, s);
5346 return(ret);
5347 }
5348
5349 /**
5350 * xmlXPathCompareNodeSets:
5351 * @inf: less than (1) or greater than (0)
5352 * @strict: is the comparison strict
5353 * @arg1: the first node set object
5354 * @arg2: the second node set object
5355 *
5356 * Implement the compare operation on nodesets:
5357 *
5358 * If both objects to be compared are node-sets, then the comparison
5359 * will be true if and only if there is a node in the first node-set
5360 * and a node in the second node-set such that the result of performing
5361 * the comparison on the string-values of the two nodes is true.
5362 * ....
5363 * When neither object to be compared is a node-set and the operator
5364 * is <=, <, >= or >, then the objects are compared by converting both
5365 * objects to numbers and comparing the numbers according to IEEE 754.
5366 * ....
5367 * The number function converts its argument to a number as follows:
5368 * - a string that consists of optional whitespace followed by an
5369 * optional minus sign followed by a Number followed by whitespace
5370 * is converted to the IEEE 754 number that is nearest (according
5371 * to the IEEE 754 round-to-nearest rule) to the mathematical value
5372 * represented by the string; any other string is converted to NaN
5373 *
5374 * Conclusion all nodes need to be converted first to their string value
5375 * and then the comparison must be done when possible
5376 */
5377 static int
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5378 xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5379 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5380 int i, j, init = 0;
5381 double val1;
5382 double *values2;
5383 int ret = 0;
5384 xmlNodeSetPtr ns1;
5385 xmlNodeSetPtr ns2;
5386
5387 if ((arg1 == NULL) ||
5388 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5389 xmlXPathFreeObject(arg2);
5390 return(0);
5391 }
5392 if ((arg2 == NULL) ||
5393 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5394 xmlXPathFreeObject(arg1);
5395 xmlXPathFreeObject(arg2);
5396 return(0);
5397 }
5398
5399 ns1 = arg1->nodesetval;
5400 ns2 = arg2->nodesetval;
5401
5402 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5403 xmlXPathFreeObject(arg1);
5404 xmlXPathFreeObject(arg2);
5405 return(0);
5406 }
5407 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5408 xmlXPathFreeObject(arg1);
5409 xmlXPathFreeObject(arg2);
5410 return(0);
5411 }
5412
5413 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5414 if (values2 == NULL) {
5415 xmlXPathPErrMemory(ctxt);
5416 xmlXPathFreeObject(arg1);
5417 xmlXPathFreeObject(arg2);
5418 return(0);
5419 }
5420 for (i = 0;i < ns1->nodeNr;i++) {
5421 val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5422 if (xmlXPathIsNaN(val1))
5423 continue;
5424 for (j = 0;j < ns2->nodeNr;j++) {
5425 if (init == 0) {
5426 values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5427 ns2->nodeTab[j]);
5428 }
5429 if (xmlXPathIsNaN(values2[j]))
5430 continue;
5431 if (inf && strict)
5432 ret = (val1 < values2[j]);
5433 else if (inf && !strict)
5434 ret = (val1 <= values2[j]);
5435 else if (!inf && strict)
5436 ret = (val1 > values2[j]);
5437 else if (!inf && !strict)
5438 ret = (val1 >= values2[j]);
5439 if (ret)
5440 break;
5441 }
5442 if (ret)
5443 break;
5444 init = 1;
5445 }
5446 xmlFree(values2);
5447 xmlXPathFreeObject(arg1);
5448 xmlXPathFreeObject(arg2);
5449 return(ret);
5450 }
5451
5452 /**
5453 * xmlXPathCompareNodeSetValue:
5454 * @ctxt: the XPath Parser context
5455 * @inf: less than (1) or greater than (0)
5456 * @strict: is the comparison strict
5457 * @arg: the node set
5458 * @val: the value
5459 *
5460 * Implement the compare operation between a nodeset and a value
5461 * @ns < @val (1, 1, ...
5462 * @ns <= @val (1, 0, ...
5463 * @ns > @val (0, 1, ...
5464 * @ns >= @val (0, 0, ...
5465 *
5466 * If one object to be compared is a node-set and the other is a boolean,
5467 * then the comparison will be true if and only if the result of performing
5468 * the comparison on the boolean and on the result of converting
5469 * the node-set to a boolean using the boolean function is true.
5470 *
5471 * Returns 0 or 1 depending on the results of the test.
5472 */
5473 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)5474 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5475 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5476 if ((val == NULL) || (arg == NULL) ||
5477 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5478 return(0);
5479
5480 switch(val->type) {
5481 case XPATH_NUMBER:
5482 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5483 case XPATH_NODESET:
5484 case XPATH_XSLT_TREE:
5485 return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5486 case XPATH_STRING:
5487 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5488 case XPATH_BOOLEAN:
5489 valuePush(ctxt, arg);
5490 xmlXPathBooleanFunction(ctxt, 1);
5491 valuePush(ctxt, val);
5492 return(xmlXPathCompareValues(ctxt, inf, strict));
5493 default:
5494 xmlXPathReleaseObject(ctxt->context, arg);
5495 xmlXPathReleaseObject(ctxt->context, val);
5496 XP_ERROR0(XPATH_INVALID_TYPE);
5497 }
5498 return(0);
5499 }
5500
5501 /**
5502 * xmlXPathEqualNodeSetString:
5503 * @arg: the nodeset object argument
5504 * @str: the string to compare to.
5505 * @neq: flag to show whether for '=' (0) or '!=' (1)
5506 *
5507 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5508 * If one object to be compared is a node-set and the other is a string,
5509 * then the comparison will be true if and only if there is a node in
5510 * the node-set such that the result of performing the comparison on the
5511 * string-value of the node and the other string is true.
5512 *
5513 * Returns 0 or 1 depending on the results of the test.
5514 */
5515 static int
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,const xmlChar * str,int neq)5516 xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5517 xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5518 {
5519 int i;
5520 xmlNodeSetPtr ns;
5521 xmlChar *str2;
5522 unsigned int hash;
5523
5524 if ((str == NULL) || (arg == NULL) ||
5525 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5526 return (0);
5527 ns = arg->nodesetval;
5528 /*
5529 * A NULL nodeset compared with a string is always false
5530 * (since there is no node equal, and no node not equal)
5531 */
5532 if ((ns == NULL) || (ns->nodeNr <= 0) )
5533 return (0);
5534 hash = xmlXPathStringHash(str);
5535 for (i = 0; i < ns->nodeNr; i++) {
5536 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5537 str2 = xmlNodeGetContent(ns->nodeTab[i]);
5538 if (str2 == NULL) {
5539 xmlXPathPErrMemory(ctxt);
5540 return(0);
5541 }
5542 if (xmlStrEqual(str, str2)) {
5543 xmlFree(str2);
5544 if (neq)
5545 continue;
5546 return (1);
5547 } else if (neq) {
5548 xmlFree(str2);
5549 return (1);
5550 }
5551 xmlFree(str2);
5552 } else if (neq)
5553 return (1);
5554 }
5555 return (0);
5556 }
5557
5558 /**
5559 * xmlXPathEqualNodeSetFloat:
5560 * @arg: the nodeset object argument
5561 * @f: the float to compare to
5562 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
5563 *
5564 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5565 * If one object to be compared is a node-set and the other is a number,
5566 * then the comparison will be true if and only if there is a node in
5567 * the node-set such that the result of performing the comparison on the
5568 * number to be compared and on the result of converting the string-value
5569 * of that node to a number using the number function is true.
5570 *
5571 * Returns 0 or 1 depending on the results of the test.
5572 */
5573 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)5574 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5575 xmlXPathObjectPtr arg, double f, int neq) {
5576 int i, ret=0;
5577 xmlNodeSetPtr ns;
5578 xmlChar *str2;
5579 xmlXPathObjectPtr val;
5580 double v;
5581
5582 if ((arg == NULL) ||
5583 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5584 return(0);
5585
5586 ns = arg->nodesetval;
5587 if (ns != NULL) {
5588 for (i=0;i<ns->nodeNr;i++) {
5589 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5590 if (str2 != NULL) {
5591 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5592 xmlFree(str2);
5593 xmlXPathNumberFunction(ctxt, 1);
5594 CHECK_ERROR0;
5595 val = valuePop(ctxt);
5596 v = val->floatval;
5597 xmlXPathReleaseObject(ctxt->context, val);
5598 if (!xmlXPathIsNaN(v)) {
5599 if ((!neq) && (v==f)) {
5600 ret = 1;
5601 break;
5602 } else if ((neq) && (v!=f)) {
5603 ret = 1;
5604 break;
5605 }
5606 } else { /* NaN is unequal to any value */
5607 if (neq)
5608 ret = 1;
5609 }
5610 } else {
5611 xmlXPathPErrMemory(ctxt);
5612 }
5613 }
5614 }
5615
5616 return(ret);
5617 }
5618
5619
5620 /**
5621 * xmlXPathEqualNodeSets:
5622 * @arg1: first nodeset object argument
5623 * @arg2: second nodeset object argument
5624 * @neq: flag to show whether to test '=' (0) or '!=' (1)
5625 *
5626 * Implement the equal / not equal operation on XPath nodesets:
5627 * @arg1 == @arg2 or @arg1 != @arg2
5628 * If both objects to be compared are node-sets, then the comparison
5629 * will be true if and only if there is a node in the first node-set and
5630 * a node in the second node-set such that the result of performing the
5631 * comparison on the string-values of the two nodes is true.
5632 *
5633 * (needless to say, this is a costly operation)
5634 *
5635 * Returns 0 or 1 depending on the results of the test.
5636 */
5637 static int
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)5638 xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5639 xmlXPathObjectPtr arg2, int neq) {
5640 int i, j;
5641 unsigned int *hashs1;
5642 unsigned int *hashs2;
5643 xmlChar **values1;
5644 xmlChar **values2;
5645 int ret = 0;
5646 xmlNodeSetPtr ns1;
5647 xmlNodeSetPtr ns2;
5648
5649 if ((arg1 == NULL) ||
5650 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5651 return(0);
5652 if ((arg2 == NULL) ||
5653 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5654 return(0);
5655
5656 ns1 = arg1->nodesetval;
5657 ns2 = arg2->nodesetval;
5658
5659 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5660 return(0);
5661 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5662 return(0);
5663
5664 /*
5665 * for equal, check if there is a node pertaining to both sets
5666 */
5667 if (neq == 0)
5668 for (i = 0;i < ns1->nodeNr;i++)
5669 for (j = 0;j < ns2->nodeNr;j++)
5670 if (ns1->nodeTab[i] == ns2->nodeTab[j])
5671 return(1);
5672
5673 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5674 if (values1 == NULL) {
5675 xmlXPathPErrMemory(ctxt);
5676 return(0);
5677 }
5678 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5679 if (hashs1 == NULL) {
5680 xmlXPathPErrMemory(ctxt);
5681 xmlFree(values1);
5682 return(0);
5683 }
5684 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5685 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5686 if (values2 == NULL) {
5687 xmlXPathPErrMemory(ctxt);
5688 xmlFree(hashs1);
5689 xmlFree(values1);
5690 return(0);
5691 }
5692 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5693 if (hashs2 == NULL) {
5694 xmlXPathPErrMemory(ctxt);
5695 xmlFree(hashs1);
5696 xmlFree(values1);
5697 xmlFree(values2);
5698 return(0);
5699 }
5700 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5701 for (i = 0;i < ns1->nodeNr;i++) {
5702 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5703 for (j = 0;j < ns2->nodeNr;j++) {
5704 if (i == 0)
5705 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5706 if (hashs1[i] != hashs2[j]) {
5707 if (neq) {
5708 ret = 1;
5709 break;
5710 }
5711 }
5712 else {
5713 if (values1[i] == NULL) {
5714 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5715 if (values1[i] == NULL)
5716 xmlXPathPErrMemory(ctxt);
5717 }
5718 if (values2[j] == NULL) {
5719 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5720 if (values2[j] == NULL)
5721 xmlXPathPErrMemory(ctxt);
5722 }
5723 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5724 if (ret)
5725 break;
5726 }
5727 }
5728 if (ret)
5729 break;
5730 }
5731 for (i = 0;i < ns1->nodeNr;i++)
5732 if (values1[i] != NULL)
5733 xmlFree(values1[i]);
5734 for (j = 0;j < ns2->nodeNr;j++)
5735 if (values2[j] != NULL)
5736 xmlFree(values2[j]);
5737 xmlFree(values1);
5738 xmlFree(values2);
5739 xmlFree(hashs1);
5740 xmlFree(hashs2);
5741 return(ret);
5742 }
5743
5744 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5745 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5746 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5747 int ret = 0;
5748 /*
5749 *At this point we are assured neither arg1 nor arg2
5750 *is a nodeset, so we can just pick the appropriate routine.
5751 */
5752 switch (arg1->type) {
5753 case XPATH_UNDEFINED:
5754 break;
5755 case XPATH_BOOLEAN:
5756 switch (arg2->type) {
5757 case XPATH_UNDEFINED:
5758 break;
5759 case XPATH_BOOLEAN:
5760 ret = (arg1->boolval == arg2->boolval);
5761 break;
5762 case XPATH_NUMBER:
5763 ret = (arg1->boolval ==
5764 xmlXPathCastNumberToBoolean(arg2->floatval));
5765 break;
5766 case XPATH_STRING:
5767 if ((arg2->stringval == NULL) ||
5768 (arg2->stringval[0] == 0)) ret = 0;
5769 else
5770 ret = 1;
5771 ret = (arg1->boolval == ret);
5772 break;
5773 case XPATH_USERS:
5774 /* TODO */
5775 break;
5776 case XPATH_NODESET:
5777 case XPATH_XSLT_TREE:
5778 break;
5779 }
5780 break;
5781 case XPATH_NUMBER:
5782 switch (arg2->type) {
5783 case XPATH_UNDEFINED:
5784 break;
5785 case XPATH_BOOLEAN:
5786 ret = (arg2->boolval==
5787 xmlXPathCastNumberToBoolean(arg1->floatval));
5788 break;
5789 case XPATH_STRING:
5790 valuePush(ctxt, arg2);
5791 xmlXPathNumberFunction(ctxt, 1);
5792 arg2 = valuePop(ctxt);
5793 if (ctxt->error)
5794 break;
5795 /* Falls through. */
5796 case XPATH_NUMBER:
5797 /* Hand check NaN and Infinity equalities */
5798 if (xmlXPathIsNaN(arg1->floatval) ||
5799 xmlXPathIsNaN(arg2->floatval)) {
5800 ret = 0;
5801 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5802 if (xmlXPathIsInf(arg2->floatval) == 1)
5803 ret = 1;
5804 else
5805 ret = 0;
5806 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5807 if (xmlXPathIsInf(arg2->floatval) == -1)
5808 ret = 1;
5809 else
5810 ret = 0;
5811 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5812 if (xmlXPathIsInf(arg1->floatval) == 1)
5813 ret = 1;
5814 else
5815 ret = 0;
5816 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5817 if (xmlXPathIsInf(arg1->floatval) == -1)
5818 ret = 1;
5819 else
5820 ret = 0;
5821 } else {
5822 ret = (arg1->floatval == arg2->floatval);
5823 }
5824 break;
5825 case XPATH_USERS:
5826 /* TODO */
5827 break;
5828 case XPATH_NODESET:
5829 case XPATH_XSLT_TREE:
5830 break;
5831 }
5832 break;
5833 case XPATH_STRING:
5834 switch (arg2->type) {
5835 case XPATH_UNDEFINED:
5836 break;
5837 case XPATH_BOOLEAN:
5838 if ((arg1->stringval == NULL) ||
5839 (arg1->stringval[0] == 0)) ret = 0;
5840 else
5841 ret = 1;
5842 ret = (arg2->boolval == ret);
5843 break;
5844 case XPATH_STRING:
5845 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5846 break;
5847 case XPATH_NUMBER:
5848 valuePush(ctxt, arg1);
5849 xmlXPathNumberFunction(ctxt, 1);
5850 arg1 = valuePop(ctxt);
5851 if (ctxt->error)
5852 break;
5853 /* Hand check NaN and Infinity equalities */
5854 if (xmlXPathIsNaN(arg1->floatval) ||
5855 xmlXPathIsNaN(arg2->floatval)) {
5856 ret = 0;
5857 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5858 if (xmlXPathIsInf(arg2->floatval) == 1)
5859 ret = 1;
5860 else
5861 ret = 0;
5862 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5863 if (xmlXPathIsInf(arg2->floatval) == -1)
5864 ret = 1;
5865 else
5866 ret = 0;
5867 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5868 if (xmlXPathIsInf(arg1->floatval) == 1)
5869 ret = 1;
5870 else
5871 ret = 0;
5872 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5873 if (xmlXPathIsInf(arg1->floatval) == -1)
5874 ret = 1;
5875 else
5876 ret = 0;
5877 } else {
5878 ret = (arg1->floatval == arg2->floatval);
5879 }
5880 break;
5881 case XPATH_USERS:
5882 /* TODO */
5883 break;
5884 case XPATH_NODESET:
5885 case XPATH_XSLT_TREE:
5886 break;
5887 }
5888 break;
5889 case XPATH_USERS:
5890 /* TODO */
5891 break;
5892 case XPATH_NODESET:
5893 case XPATH_XSLT_TREE:
5894 break;
5895 }
5896 xmlXPathReleaseObject(ctxt->context, arg1);
5897 xmlXPathReleaseObject(ctxt->context, arg2);
5898 return(ret);
5899 }
5900
5901 /**
5902 * xmlXPathEqualValues:
5903 * @ctxt: the XPath Parser context
5904 *
5905 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5906 *
5907 * Returns 0 or 1 depending on the results of the test.
5908 */
5909 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)5910 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
5911 xmlXPathObjectPtr arg1, arg2, argtmp;
5912 int ret = 0;
5913
5914 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5915 arg2 = valuePop(ctxt);
5916 arg1 = valuePop(ctxt);
5917 if ((arg1 == NULL) || (arg2 == NULL)) {
5918 if (arg1 != NULL)
5919 xmlXPathReleaseObject(ctxt->context, arg1);
5920 else
5921 xmlXPathReleaseObject(ctxt->context, arg2);
5922 XP_ERROR0(XPATH_INVALID_OPERAND);
5923 }
5924
5925 if (arg1 == arg2) {
5926 xmlXPathFreeObject(arg1);
5927 return(1);
5928 }
5929
5930 /*
5931 *If either argument is a nodeset, it's a 'special case'
5932 */
5933 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5934 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5935 /*
5936 *Hack it to assure arg1 is the nodeset
5937 */
5938 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5939 argtmp = arg2;
5940 arg2 = arg1;
5941 arg1 = argtmp;
5942 }
5943 switch (arg2->type) {
5944 case XPATH_UNDEFINED:
5945 break;
5946 case XPATH_NODESET:
5947 case XPATH_XSLT_TREE:
5948 ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5949 break;
5950 case XPATH_BOOLEAN:
5951 if ((arg1->nodesetval == NULL) ||
5952 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5953 else
5954 ret = 1;
5955 ret = (ret == arg2->boolval);
5956 break;
5957 case XPATH_NUMBER:
5958 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5959 break;
5960 case XPATH_STRING:
5961 ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5962 arg2->stringval, 0);
5963 break;
5964 case XPATH_USERS:
5965 /* TODO */
5966 break;
5967 }
5968 xmlXPathReleaseObject(ctxt->context, arg1);
5969 xmlXPathReleaseObject(ctxt->context, arg2);
5970 return(ret);
5971 }
5972
5973 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5974 }
5975
5976 /**
5977 * xmlXPathNotEqualValues:
5978 * @ctxt: the XPath Parser context
5979 *
5980 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5981 *
5982 * Returns 0 or 1 depending on the results of the test.
5983 */
5984 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)5985 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
5986 xmlXPathObjectPtr arg1, arg2, argtmp;
5987 int ret = 0;
5988
5989 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5990 arg2 = valuePop(ctxt);
5991 arg1 = valuePop(ctxt);
5992 if ((arg1 == NULL) || (arg2 == NULL)) {
5993 if (arg1 != NULL)
5994 xmlXPathReleaseObject(ctxt->context, arg1);
5995 else
5996 xmlXPathReleaseObject(ctxt->context, arg2);
5997 XP_ERROR0(XPATH_INVALID_OPERAND);
5998 }
5999
6000 if (arg1 == arg2) {
6001 xmlXPathReleaseObject(ctxt->context, arg1);
6002 return(0);
6003 }
6004
6005 /*
6006 *If either argument is a nodeset, it's a 'special case'
6007 */
6008 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6009 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6010 /*
6011 *Hack it to assure arg1 is the nodeset
6012 */
6013 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6014 argtmp = arg2;
6015 arg2 = arg1;
6016 arg1 = argtmp;
6017 }
6018 switch (arg2->type) {
6019 case XPATH_UNDEFINED:
6020 break;
6021 case XPATH_NODESET:
6022 case XPATH_XSLT_TREE:
6023 ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
6024 break;
6025 case XPATH_BOOLEAN:
6026 if ((arg1->nodesetval == NULL) ||
6027 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6028 else
6029 ret = 1;
6030 ret = (ret != arg2->boolval);
6031 break;
6032 case XPATH_NUMBER:
6033 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6034 break;
6035 case XPATH_STRING:
6036 ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6037 arg2->stringval, 1);
6038 break;
6039 case XPATH_USERS:
6040 /* TODO */
6041 break;
6042 }
6043 xmlXPathReleaseObject(ctxt->context, arg1);
6044 xmlXPathReleaseObject(ctxt->context, arg2);
6045 return(ret);
6046 }
6047
6048 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6049 }
6050
6051 /**
6052 * xmlXPathCompareValues:
6053 * @ctxt: the XPath Parser context
6054 * @inf: less than (1) or greater than (0)
6055 * @strict: is the comparison strict
6056 *
6057 * Implement the compare operation on XPath objects:
6058 * @arg1 < @arg2 (1, 1, ...
6059 * @arg1 <= @arg2 (1, 0, ...
6060 * @arg1 > @arg2 (0, 1, ...
6061 * @arg1 >= @arg2 (0, 0, ...
6062 *
6063 * When neither object to be compared is a node-set and the operator is
6064 * <=, <, >=, >, then the objects are compared by converted both objects
6065 * to numbers and comparing the numbers according to IEEE 754. The <
6066 * comparison will be true if and only if the first number is less than the
6067 * second number. The <= comparison will be true if and only if the first
6068 * number is less than or equal to the second number. The > comparison
6069 * will be true if and only if the first number is greater than the second
6070 * number. The >= comparison will be true if and only if the first number
6071 * is greater than or equal to the second number.
6072 *
6073 * Returns 1 if the comparison succeeded, 0 if it failed
6074 */
6075 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)6076 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6077 int ret = 0, arg1i = 0, arg2i = 0;
6078 xmlXPathObjectPtr arg1, arg2;
6079
6080 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6081 arg2 = valuePop(ctxt);
6082 arg1 = valuePop(ctxt);
6083 if ((arg1 == NULL) || (arg2 == NULL)) {
6084 if (arg1 != NULL)
6085 xmlXPathReleaseObject(ctxt->context, arg1);
6086 else
6087 xmlXPathReleaseObject(ctxt->context, arg2);
6088 XP_ERROR0(XPATH_INVALID_OPERAND);
6089 }
6090
6091 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6092 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6093 /*
6094 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6095 * are not freed from within this routine; they will be freed from the
6096 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6097 */
6098 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6099 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6100 ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6101 } else {
6102 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6103 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6104 arg1, arg2);
6105 } else {
6106 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6107 arg2, arg1);
6108 }
6109 }
6110 return(ret);
6111 }
6112
6113 if (arg1->type != XPATH_NUMBER) {
6114 valuePush(ctxt, arg1);
6115 xmlXPathNumberFunction(ctxt, 1);
6116 arg1 = valuePop(ctxt);
6117 }
6118 if (arg2->type != XPATH_NUMBER) {
6119 valuePush(ctxt, arg2);
6120 xmlXPathNumberFunction(ctxt, 1);
6121 arg2 = valuePop(ctxt);
6122 }
6123 if (ctxt->error)
6124 goto error;
6125 /*
6126 * Add tests for infinity and nan
6127 * => feedback on 3.4 for Inf and NaN
6128 */
6129 /* Hand check NaN and Infinity comparisons */
6130 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6131 ret=0;
6132 } else {
6133 arg1i=xmlXPathIsInf(arg1->floatval);
6134 arg2i=xmlXPathIsInf(arg2->floatval);
6135 if (inf && strict) {
6136 if ((arg1i == -1 && arg2i != -1) ||
6137 (arg2i == 1 && arg1i != 1)) {
6138 ret = 1;
6139 } else if (arg1i == 0 && arg2i == 0) {
6140 ret = (arg1->floatval < arg2->floatval);
6141 } else {
6142 ret = 0;
6143 }
6144 }
6145 else if (inf && !strict) {
6146 if (arg1i == -1 || arg2i == 1) {
6147 ret = 1;
6148 } else if (arg1i == 0 && arg2i == 0) {
6149 ret = (arg1->floatval <= arg2->floatval);
6150 } else {
6151 ret = 0;
6152 }
6153 }
6154 else if (!inf && strict) {
6155 if ((arg1i == 1 && arg2i != 1) ||
6156 (arg2i == -1 && arg1i != -1)) {
6157 ret = 1;
6158 } else if (arg1i == 0 && arg2i == 0) {
6159 ret = (arg1->floatval > arg2->floatval);
6160 } else {
6161 ret = 0;
6162 }
6163 }
6164 else if (!inf && !strict) {
6165 if (arg1i == 1 || arg2i == -1) {
6166 ret = 1;
6167 } else if (arg1i == 0 && arg2i == 0) {
6168 ret = (arg1->floatval >= arg2->floatval);
6169 } else {
6170 ret = 0;
6171 }
6172 }
6173 }
6174 error:
6175 xmlXPathReleaseObject(ctxt->context, arg1);
6176 xmlXPathReleaseObject(ctxt->context, arg2);
6177 return(ret);
6178 }
6179
6180 /**
6181 * xmlXPathValueFlipSign:
6182 * @ctxt: the XPath Parser context
6183 *
6184 * Implement the unary - operation on an XPath object
6185 * The numeric operators convert their operands to numbers as if
6186 * by calling the number function.
6187 */
6188 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)6189 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6190 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6191 CAST_TO_NUMBER;
6192 CHECK_TYPE(XPATH_NUMBER);
6193 ctxt->value->floatval = -ctxt->value->floatval;
6194 }
6195
6196 /**
6197 * xmlXPathAddValues:
6198 * @ctxt: the XPath Parser context
6199 *
6200 * Implement the add operation on XPath objects:
6201 * The numeric operators convert their operands to numbers as if
6202 * by calling the number function.
6203 */
6204 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)6205 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6206 xmlXPathObjectPtr arg;
6207 double val;
6208
6209 arg = valuePop(ctxt);
6210 if (arg == NULL)
6211 XP_ERROR(XPATH_INVALID_OPERAND);
6212 val = xmlXPathCastToNumberInternal(ctxt, arg);
6213 xmlXPathReleaseObject(ctxt->context, arg);
6214 CAST_TO_NUMBER;
6215 CHECK_TYPE(XPATH_NUMBER);
6216 ctxt->value->floatval += val;
6217 }
6218
6219 /**
6220 * xmlXPathSubValues:
6221 * @ctxt: the XPath Parser context
6222 *
6223 * Implement the subtraction operation on XPath objects:
6224 * The numeric operators convert their operands to numbers as if
6225 * by calling the number function.
6226 */
6227 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)6228 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6229 xmlXPathObjectPtr arg;
6230 double val;
6231
6232 arg = valuePop(ctxt);
6233 if (arg == NULL)
6234 XP_ERROR(XPATH_INVALID_OPERAND);
6235 val = xmlXPathCastToNumberInternal(ctxt, arg);
6236 xmlXPathReleaseObject(ctxt->context, arg);
6237 CAST_TO_NUMBER;
6238 CHECK_TYPE(XPATH_NUMBER);
6239 ctxt->value->floatval -= val;
6240 }
6241
6242 /**
6243 * xmlXPathMultValues:
6244 * @ctxt: the XPath Parser context
6245 *
6246 * Implement the multiply operation on XPath objects:
6247 * The numeric operators convert their operands to numbers as if
6248 * by calling the number function.
6249 */
6250 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)6251 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6252 xmlXPathObjectPtr arg;
6253 double val;
6254
6255 arg = valuePop(ctxt);
6256 if (arg == NULL)
6257 XP_ERROR(XPATH_INVALID_OPERAND);
6258 val = xmlXPathCastToNumberInternal(ctxt, arg);
6259 xmlXPathReleaseObject(ctxt->context, arg);
6260 CAST_TO_NUMBER;
6261 CHECK_TYPE(XPATH_NUMBER);
6262 ctxt->value->floatval *= val;
6263 }
6264
6265 /**
6266 * xmlXPathDivValues:
6267 * @ctxt: the XPath Parser context
6268 *
6269 * Implement the div operation on XPath objects @arg1 / @arg2:
6270 * The numeric operators convert their operands to numbers as if
6271 * by calling the number function.
6272 */
6273 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6274 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)6275 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6276 xmlXPathObjectPtr arg;
6277 double val;
6278
6279 arg = valuePop(ctxt);
6280 if (arg == NULL)
6281 XP_ERROR(XPATH_INVALID_OPERAND);
6282 val = xmlXPathCastToNumberInternal(ctxt, arg);
6283 xmlXPathReleaseObject(ctxt->context, arg);
6284 CAST_TO_NUMBER;
6285 CHECK_TYPE(XPATH_NUMBER);
6286 ctxt->value->floatval /= val;
6287 }
6288
6289 /**
6290 * xmlXPathModValues:
6291 * @ctxt: the XPath Parser context
6292 *
6293 * Implement the mod operation on XPath objects: @arg1 / @arg2
6294 * The numeric operators convert their operands to numbers as if
6295 * by calling the number function.
6296 */
6297 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)6298 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6299 xmlXPathObjectPtr arg;
6300 double arg1, arg2;
6301
6302 arg = valuePop(ctxt);
6303 if (arg == NULL)
6304 XP_ERROR(XPATH_INVALID_OPERAND);
6305 arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6306 xmlXPathReleaseObject(ctxt->context, arg);
6307 CAST_TO_NUMBER;
6308 CHECK_TYPE(XPATH_NUMBER);
6309 arg1 = ctxt->value->floatval;
6310 if (arg2 == 0)
6311 ctxt->value->floatval = xmlXPathNAN;
6312 else {
6313 ctxt->value->floatval = fmod(arg1, arg2);
6314 }
6315 }
6316
6317 /************************************************************************
6318 * *
6319 * The traversal functions *
6320 * *
6321 ************************************************************************/
6322
6323 /*
6324 * A traversal function enumerates nodes along an axis.
6325 * Initially it must be called with NULL, and it indicates
6326 * termination on the axis by returning NULL.
6327 */
6328 typedef xmlNodePtr (*xmlXPathTraversalFunction)
6329 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6330
6331 /*
6332 * xmlXPathTraversalFunctionExt:
6333 * A traversal function enumerates nodes along an axis.
6334 * Initially it must be called with NULL, and it indicates
6335 * termination on the axis by returning NULL.
6336 * The context node of the traversal is specified via @contextNode.
6337 */
6338 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6339 (xmlNodePtr cur, xmlNodePtr contextNode);
6340
6341 /*
6342 * xmlXPathNodeSetMergeFunction:
6343 * Used for merging node sets in xmlXPathCollectAndTest().
6344 */
6345 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6346 (xmlNodeSetPtr, xmlNodeSetPtr);
6347
6348
6349 /**
6350 * xmlXPathNextSelf:
6351 * @ctxt: the XPath Parser context
6352 * @cur: the current node in the traversal
6353 *
6354 * Traversal function for the "self" direction
6355 * The self axis contains just the context node itself
6356 *
6357 * Returns the next element following that axis
6358 */
6359 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6360 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6361 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6362 if (cur == NULL)
6363 return(ctxt->context->node);
6364 return(NULL);
6365 }
6366
6367 /**
6368 * xmlXPathNextChild:
6369 * @ctxt: the XPath Parser context
6370 * @cur: the current node in the traversal
6371 *
6372 * Traversal function for the "child" direction
6373 * The child axis contains the children of the context node in document order.
6374 *
6375 * Returns the next element following that axis
6376 */
6377 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6378 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6379 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6380 if (cur == NULL) {
6381 if (ctxt->context->node == NULL) return(NULL);
6382 switch (ctxt->context->node->type) {
6383 case XML_ELEMENT_NODE:
6384 case XML_TEXT_NODE:
6385 case XML_CDATA_SECTION_NODE:
6386 case XML_ENTITY_REF_NODE:
6387 case XML_ENTITY_NODE:
6388 case XML_PI_NODE:
6389 case XML_COMMENT_NODE:
6390 case XML_NOTATION_NODE:
6391 case XML_DTD_NODE:
6392 return(ctxt->context->node->children);
6393 case XML_DOCUMENT_NODE:
6394 case XML_DOCUMENT_TYPE_NODE:
6395 case XML_DOCUMENT_FRAG_NODE:
6396 case XML_HTML_DOCUMENT_NODE:
6397 return(((xmlDocPtr) ctxt->context->node)->children);
6398 case XML_ELEMENT_DECL:
6399 case XML_ATTRIBUTE_DECL:
6400 case XML_ENTITY_DECL:
6401 case XML_ATTRIBUTE_NODE:
6402 case XML_NAMESPACE_DECL:
6403 case XML_XINCLUDE_START:
6404 case XML_XINCLUDE_END:
6405 return(NULL);
6406 }
6407 return(NULL);
6408 }
6409 if ((cur->type == XML_DOCUMENT_NODE) ||
6410 (cur->type == XML_HTML_DOCUMENT_NODE))
6411 return(NULL);
6412 return(cur->next);
6413 }
6414
6415 /**
6416 * xmlXPathNextChildElement:
6417 * @ctxt: the XPath Parser context
6418 * @cur: the current node in the traversal
6419 *
6420 * Traversal function for the "child" direction and nodes of type element.
6421 * The child axis contains the children of the context node in document order.
6422 *
6423 * Returns the next element following that axis
6424 */
6425 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6426 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6427 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6428 if (cur == NULL) {
6429 cur = ctxt->context->node;
6430 if (cur == NULL) return(NULL);
6431 /*
6432 * Get the first element child.
6433 */
6434 switch (cur->type) {
6435 case XML_ELEMENT_NODE:
6436 case XML_DOCUMENT_FRAG_NODE:
6437 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6438 case XML_ENTITY_NODE:
6439 cur = cur->children;
6440 if (cur != NULL) {
6441 if (cur->type == XML_ELEMENT_NODE)
6442 return(cur);
6443 do {
6444 cur = cur->next;
6445 } while ((cur != NULL) &&
6446 (cur->type != XML_ELEMENT_NODE));
6447 return(cur);
6448 }
6449 return(NULL);
6450 case XML_DOCUMENT_NODE:
6451 case XML_HTML_DOCUMENT_NODE:
6452 return(xmlDocGetRootElement((xmlDocPtr) cur));
6453 default:
6454 return(NULL);
6455 }
6456 return(NULL);
6457 }
6458 /*
6459 * Get the next sibling element node.
6460 */
6461 switch (cur->type) {
6462 case XML_ELEMENT_NODE:
6463 case XML_TEXT_NODE:
6464 case XML_ENTITY_REF_NODE:
6465 case XML_ENTITY_NODE:
6466 case XML_CDATA_SECTION_NODE:
6467 case XML_PI_NODE:
6468 case XML_COMMENT_NODE:
6469 case XML_XINCLUDE_END:
6470 break;
6471 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6472 default:
6473 return(NULL);
6474 }
6475 if (cur->next != NULL) {
6476 if (cur->next->type == XML_ELEMENT_NODE)
6477 return(cur->next);
6478 cur = cur->next;
6479 do {
6480 cur = cur->next;
6481 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6482 return(cur);
6483 }
6484 return(NULL);
6485 }
6486
6487 /**
6488 * xmlXPathNextDescendant:
6489 * @ctxt: the XPath Parser context
6490 * @cur: the current node in the traversal
6491 *
6492 * Traversal function for the "descendant" direction
6493 * the descendant axis contains the descendants of the context node in document
6494 * order; a descendant is a child or a child of a child and so on.
6495 *
6496 * Returns the next element following that axis
6497 */
6498 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6499 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6500 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6501 if (cur == NULL) {
6502 if (ctxt->context->node == NULL)
6503 return(NULL);
6504 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6505 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6506 return(NULL);
6507
6508 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6509 return(ctxt->context->doc->children);
6510 return(ctxt->context->node->children);
6511 }
6512
6513 if (cur->type == XML_NAMESPACE_DECL)
6514 return(NULL);
6515 if (cur->children != NULL) {
6516 /*
6517 * Do not descend on entities declarations
6518 */
6519 if (cur->children->type != XML_ENTITY_DECL) {
6520 cur = cur->children;
6521 /*
6522 * Skip DTDs
6523 */
6524 if (cur->type != XML_DTD_NODE)
6525 return(cur);
6526 }
6527 }
6528
6529 if (cur == ctxt->context->node) return(NULL);
6530
6531 while (cur->next != NULL) {
6532 cur = cur->next;
6533 if ((cur->type != XML_ENTITY_DECL) &&
6534 (cur->type != XML_DTD_NODE))
6535 return(cur);
6536 }
6537
6538 do {
6539 cur = cur->parent;
6540 if (cur == NULL) break;
6541 if (cur == ctxt->context->node) return(NULL);
6542 if (cur->next != NULL) {
6543 cur = cur->next;
6544 return(cur);
6545 }
6546 } while (cur != NULL);
6547 return(cur);
6548 }
6549
6550 /**
6551 * xmlXPathNextDescendantOrSelf:
6552 * @ctxt: the XPath Parser context
6553 * @cur: the current node in the traversal
6554 *
6555 * Traversal function for the "descendant-or-self" direction
6556 * the descendant-or-self axis contains the context node and the descendants
6557 * of the context node in document order; thus the context node is the first
6558 * node on the axis, and the first child of the context node is the second node
6559 * on the axis
6560 *
6561 * Returns the next element following that axis
6562 */
6563 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6564 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6565 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6566 if (cur == NULL)
6567 return(ctxt->context->node);
6568
6569 if (ctxt->context->node == NULL)
6570 return(NULL);
6571 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6572 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6573 return(NULL);
6574
6575 return(xmlXPathNextDescendant(ctxt, cur));
6576 }
6577
6578 /**
6579 * xmlXPathNextParent:
6580 * @ctxt: the XPath Parser context
6581 * @cur: the current node in the traversal
6582 *
6583 * Traversal function for the "parent" direction
6584 * The parent axis contains the parent of the context node, if there is one.
6585 *
6586 * Returns the next element following that axis
6587 */
6588 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6589 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6590 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6591 /*
6592 * the parent of an attribute or namespace node is the element
6593 * to which the attribute or namespace node is attached
6594 * Namespace handling !!!
6595 */
6596 if (cur == NULL) {
6597 if (ctxt->context->node == NULL) return(NULL);
6598 switch (ctxt->context->node->type) {
6599 case XML_ELEMENT_NODE:
6600 case XML_TEXT_NODE:
6601 case XML_CDATA_SECTION_NODE:
6602 case XML_ENTITY_REF_NODE:
6603 case XML_ENTITY_NODE:
6604 case XML_PI_NODE:
6605 case XML_COMMENT_NODE:
6606 case XML_NOTATION_NODE:
6607 case XML_DTD_NODE:
6608 case XML_ELEMENT_DECL:
6609 case XML_ATTRIBUTE_DECL:
6610 case XML_XINCLUDE_START:
6611 case XML_XINCLUDE_END:
6612 case XML_ENTITY_DECL:
6613 if (ctxt->context->node->parent == NULL)
6614 return((xmlNodePtr) ctxt->context->doc);
6615 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6616 ((ctxt->context->node->parent->name[0] == ' ') ||
6617 (xmlStrEqual(ctxt->context->node->parent->name,
6618 BAD_CAST "fake node libxslt"))))
6619 return(NULL);
6620 return(ctxt->context->node->parent);
6621 case XML_ATTRIBUTE_NODE: {
6622 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6623
6624 return(att->parent);
6625 }
6626 case XML_DOCUMENT_NODE:
6627 case XML_DOCUMENT_TYPE_NODE:
6628 case XML_DOCUMENT_FRAG_NODE:
6629 case XML_HTML_DOCUMENT_NODE:
6630 return(NULL);
6631 case XML_NAMESPACE_DECL: {
6632 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6633
6634 if ((ns->next != NULL) &&
6635 (ns->next->type != XML_NAMESPACE_DECL))
6636 return((xmlNodePtr) ns->next);
6637 return(NULL);
6638 }
6639 }
6640 }
6641 return(NULL);
6642 }
6643
6644 /**
6645 * xmlXPathNextAncestor:
6646 * @ctxt: the XPath Parser context
6647 * @cur: the current node in the traversal
6648 *
6649 * Traversal function for the "ancestor" direction
6650 * the ancestor axis contains the ancestors of the context node; the ancestors
6651 * of the context node consist of the parent of context node and the parent's
6652 * parent and so on; the nodes are ordered in reverse document order; thus the
6653 * parent is the first node on the axis, and the parent's parent is the second
6654 * node on the axis
6655 *
6656 * Returns the next element following that axis
6657 */
6658 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6659 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6660 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6661 /*
6662 * the parent of an attribute or namespace node is the element
6663 * to which the attribute or namespace node is attached
6664 * !!!!!!!!!!!!!
6665 */
6666 if (cur == NULL) {
6667 if (ctxt->context->node == NULL) return(NULL);
6668 switch (ctxt->context->node->type) {
6669 case XML_ELEMENT_NODE:
6670 case XML_TEXT_NODE:
6671 case XML_CDATA_SECTION_NODE:
6672 case XML_ENTITY_REF_NODE:
6673 case XML_ENTITY_NODE:
6674 case XML_PI_NODE:
6675 case XML_COMMENT_NODE:
6676 case XML_DTD_NODE:
6677 case XML_ELEMENT_DECL:
6678 case XML_ATTRIBUTE_DECL:
6679 case XML_ENTITY_DECL:
6680 case XML_NOTATION_NODE:
6681 case XML_XINCLUDE_START:
6682 case XML_XINCLUDE_END:
6683 if (ctxt->context->node->parent == NULL)
6684 return((xmlNodePtr) ctxt->context->doc);
6685 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6686 ((ctxt->context->node->parent->name[0] == ' ') ||
6687 (xmlStrEqual(ctxt->context->node->parent->name,
6688 BAD_CAST "fake node libxslt"))))
6689 return(NULL);
6690 return(ctxt->context->node->parent);
6691 case XML_ATTRIBUTE_NODE: {
6692 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6693
6694 return(tmp->parent);
6695 }
6696 case XML_DOCUMENT_NODE:
6697 case XML_DOCUMENT_TYPE_NODE:
6698 case XML_DOCUMENT_FRAG_NODE:
6699 case XML_HTML_DOCUMENT_NODE:
6700 return(NULL);
6701 case XML_NAMESPACE_DECL: {
6702 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6703
6704 if ((ns->next != NULL) &&
6705 (ns->next->type != XML_NAMESPACE_DECL))
6706 return((xmlNodePtr) ns->next);
6707 /* Bad, how did that namespace end up here ? */
6708 return(NULL);
6709 }
6710 }
6711 return(NULL);
6712 }
6713 if (cur == ctxt->context->doc->children)
6714 return((xmlNodePtr) ctxt->context->doc);
6715 if (cur == (xmlNodePtr) ctxt->context->doc)
6716 return(NULL);
6717 switch (cur->type) {
6718 case XML_ELEMENT_NODE:
6719 case XML_TEXT_NODE:
6720 case XML_CDATA_SECTION_NODE:
6721 case XML_ENTITY_REF_NODE:
6722 case XML_ENTITY_NODE:
6723 case XML_PI_NODE:
6724 case XML_COMMENT_NODE:
6725 case XML_NOTATION_NODE:
6726 case XML_DTD_NODE:
6727 case XML_ELEMENT_DECL:
6728 case XML_ATTRIBUTE_DECL:
6729 case XML_ENTITY_DECL:
6730 case XML_XINCLUDE_START:
6731 case XML_XINCLUDE_END:
6732 if (cur->parent == NULL)
6733 return(NULL);
6734 if ((cur->parent->type == XML_ELEMENT_NODE) &&
6735 ((cur->parent->name[0] == ' ') ||
6736 (xmlStrEqual(cur->parent->name,
6737 BAD_CAST "fake node libxslt"))))
6738 return(NULL);
6739 return(cur->parent);
6740 case XML_ATTRIBUTE_NODE: {
6741 xmlAttrPtr att = (xmlAttrPtr) cur;
6742
6743 return(att->parent);
6744 }
6745 case XML_NAMESPACE_DECL: {
6746 xmlNsPtr ns = (xmlNsPtr) cur;
6747
6748 if ((ns->next != NULL) &&
6749 (ns->next->type != XML_NAMESPACE_DECL))
6750 return((xmlNodePtr) ns->next);
6751 /* Bad, how did that namespace end up here ? */
6752 return(NULL);
6753 }
6754 case XML_DOCUMENT_NODE:
6755 case XML_DOCUMENT_TYPE_NODE:
6756 case XML_DOCUMENT_FRAG_NODE:
6757 case XML_HTML_DOCUMENT_NODE:
6758 return(NULL);
6759 }
6760 return(NULL);
6761 }
6762
6763 /**
6764 * xmlXPathNextAncestorOrSelf:
6765 * @ctxt: the XPath Parser context
6766 * @cur: the current node in the traversal
6767 *
6768 * Traversal function for the "ancestor-or-self" direction
6769 * he ancestor-or-self axis contains the context node and ancestors of
6770 * the context node in reverse document order; thus the context node is
6771 * the first node on the axis, and the context node's parent the second;
6772 * parent here is defined the same as with the parent axis.
6773 *
6774 * Returns the next element following that axis
6775 */
6776 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6777 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6778 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6779 if (cur == NULL)
6780 return(ctxt->context->node);
6781 return(xmlXPathNextAncestor(ctxt, cur));
6782 }
6783
6784 /**
6785 * xmlXPathNextFollowingSibling:
6786 * @ctxt: the XPath Parser context
6787 * @cur: the current node in the traversal
6788 *
6789 * Traversal function for the "following-sibling" direction
6790 * The following-sibling axis contains the following siblings of the context
6791 * node in document order.
6792 *
6793 * Returns the next element following that axis
6794 */
6795 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6796 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6797 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6798 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6799 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6800 return(NULL);
6801 if (cur == (xmlNodePtr) ctxt->context->doc)
6802 return(NULL);
6803 if (cur == NULL)
6804 return(ctxt->context->node->next);
6805 return(cur->next);
6806 }
6807
6808 /**
6809 * xmlXPathNextPrecedingSibling:
6810 * @ctxt: the XPath Parser context
6811 * @cur: the current node in the traversal
6812 *
6813 * Traversal function for the "preceding-sibling" direction
6814 * The preceding-sibling axis contains the preceding siblings of the context
6815 * node in reverse document order; the first preceding sibling is first on the
6816 * axis; the sibling preceding that node is the second on the axis and so on.
6817 *
6818 * Returns the next element following that axis
6819 */
6820 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6821 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6822 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6823 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6824 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6825 return(NULL);
6826 if (cur == (xmlNodePtr) ctxt->context->doc)
6827 return(NULL);
6828 if (cur == NULL)
6829 return(ctxt->context->node->prev);
6830 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6831 cur = cur->prev;
6832 if (cur == NULL)
6833 return(ctxt->context->node->prev);
6834 }
6835 return(cur->prev);
6836 }
6837
6838 /**
6839 * xmlXPathNextFollowing:
6840 * @ctxt: the XPath Parser context
6841 * @cur: the current node in the traversal
6842 *
6843 * Traversal function for the "following" direction
6844 * The following axis contains all nodes in the same document as the context
6845 * node that are after the context node in document order, excluding any
6846 * descendants and excluding attribute nodes and namespace nodes; the nodes
6847 * are ordered in document order
6848 *
6849 * Returns the next element following that axis
6850 */
6851 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6852 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6853 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6854 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
6855 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6856 return(cur->children);
6857
6858 if (cur == NULL) {
6859 cur = ctxt->context->node;
6860 if (cur->type == XML_ATTRIBUTE_NODE) {
6861 cur = cur->parent;
6862 } else if (cur->type == XML_NAMESPACE_DECL) {
6863 xmlNsPtr ns = (xmlNsPtr) cur;
6864
6865 if ((ns->next == NULL) ||
6866 (ns->next->type == XML_NAMESPACE_DECL))
6867 return (NULL);
6868 cur = (xmlNodePtr) ns->next;
6869 }
6870 }
6871 if (cur == NULL) return(NULL) ; /* ERROR */
6872 if (cur->next != NULL) return(cur->next) ;
6873 do {
6874 cur = cur->parent;
6875 if (cur == NULL) break;
6876 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6877 if (cur->next != NULL) return(cur->next);
6878 } while (cur != NULL);
6879 return(cur);
6880 }
6881
6882 /*
6883 * xmlXPathIsAncestor:
6884 * @ancestor: the ancestor node
6885 * @node: the current node
6886 *
6887 * Check that @ancestor is a @node's ancestor
6888 *
6889 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
6890 */
6891 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)6892 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6893 if ((ancestor == NULL) || (node == NULL)) return(0);
6894 if (node->type == XML_NAMESPACE_DECL)
6895 return(0);
6896 if (ancestor->type == XML_NAMESPACE_DECL)
6897 return(0);
6898 /* nodes need to be in the same document */
6899 if (ancestor->doc != node->doc) return(0);
6900 /* avoid searching if ancestor or node is the root node */
6901 if (ancestor == (xmlNodePtr) node->doc) return(1);
6902 if (node == (xmlNodePtr) ancestor->doc) return(0);
6903 while (node->parent != NULL) {
6904 if (node->parent == ancestor)
6905 return(1);
6906 node = node->parent;
6907 }
6908 return(0);
6909 }
6910
6911 /**
6912 * xmlXPathNextPreceding:
6913 * @ctxt: the XPath Parser context
6914 * @cur: the current node in the traversal
6915 *
6916 * Traversal function for the "preceding" direction
6917 * the preceding axis contains all nodes in the same document as the context
6918 * node that are before the context node in document order, excluding any
6919 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6920 * ordered in reverse document order
6921 *
6922 * Returns the next element following that axis
6923 */
6924 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6925 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
6926 {
6927 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6928 if (cur == NULL) {
6929 cur = ctxt->context->node;
6930 if (cur->type == XML_ATTRIBUTE_NODE) {
6931 cur = cur->parent;
6932 } else if (cur->type == XML_NAMESPACE_DECL) {
6933 xmlNsPtr ns = (xmlNsPtr) cur;
6934
6935 if ((ns->next == NULL) ||
6936 (ns->next->type == XML_NAMESPACE_DECL))
6937 return (NULL);
6938 cur = (xmlNodePtr) ns->next;
6939 }
6940 }
6941 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
6942 return (NULL);
6943 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6944 cur = cur->prev;
6945 do {
6946 if (cur->prev != NULL) {
6947 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6948 return (cur);
6949 }
6950
6951 cur = cur->parent;
6952 if (cur == NULL)
6953 return (NULL);
6954 if (cur == ctxt->context->doc->children)
6955 return (NULL);
6956 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
6957 return (cur);
6958 }
6959
6960 /**
6961 * xmlXPathNextPrecedingInternal:
6962 * @ctxt: the XPath Parser context
6963 * @cur: the current node in the traversal
6964 *
6965 * Traversal function for the "preceding" direction
6966 * the preceding axis contains all nodes in the same document as the context
6967 * node that are before the context node in document order, excluding any
6968 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6969 * ordered in reverse document order
6970 * This is a faster implementation but internal only since it requires a
6971 * state kept in the parser context: ctxt->ancestor.
6972 *
6973 * Returns the next element following that axis
6974 */
6975 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6976 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6977 xmlNodePtr cur)
6978 {
6979 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6980 if (cur == NULL) {
6981 cur = ctxt->context->node;
6982 if (cur == NULL)
6983 return (NULL);
6984 if (cur->type == XML_ATTRIBUTE_NODE) {
6985 cur = cur->parent;
6986 } else if (cur->type == XML_NAMESPACE_DECL) {
6987 xmlNsPtr ns = (xmlNsPtr) cur;
6988
6989 if ((ns->next == NULL) ||
6990 (ns->next->type == XML_NAMESPACE_DECL))
6991 return (NULL);
6992 cur = (xmlNodePtr) ns->next;
6993 }
6994 ctxt->ancestor = cur->parent;
6995 }
6996 if (cur->type == XML_NAMESPACE_DECL)
6997 return(NULL);
6998 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6999 cur = cur->prev;
7000 while (cur->prev == NULL) {
7001 cur = cur->parent;
7002 if (cur == NULL)
7003 return (NULL);
7004 if (cur == ctxt->context->doc->children)
7005 return (NULL);
7006 if (cur != ctxt->ancestor)
7007 return (cur);
7008 ctxt->ancestor = cur->parent;
7009 }
7010 cur = cur->prev;
7011 while (cur->last != NULL)
7012 cur = cur->last;
7013 return (cur);
7014 }
7015
7016 /**
7017 * xmlXPathNextNamespace:
7018 * @ctxt: the XPath Parser context
7019 * @cur: the current attribute in the traversal
7020 *
7021 * Traversal function for the "namespace" direction
7022 * the namespace axis contains the namespace nodes of the context node;
7023 * the order of nodes on this axis is implementation-defined; the axis will
7024 * be empty unless the context node is an element
7025 *
7026 * We keep the XML namespace node at the end of the list.
7027 *
7028 * Returns the next element following that axis
7029 */
7030 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7031 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7032 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7033 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7034 if (cur == NULL) {
7035 if (ctxt->context->tmpNsList != NULL)
7036 xmlFree(ctxt->context->tmpNsList);
7037 ctxt->context->tmpNsNr = 0;
7038 if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7039 &ctxt->context->tmpNsList) < 0) {
7040 xmlXPathPErrMemory(ctxt);
7041 return(NULL);
7042 }
7043 if (ctxt->context->tmpNsList != NULL) {
7044 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7045 ctxt->context->tmpNsNr++;
7046 }
7047 }
7048 return((xmlNodePtr) xmlXPathXMLNamespace);
7049 }
7050 if (ctxt->context->tmpNsNr > 0) {
7051 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7052 } else {
7053 if (ctxt->context->tmpNsList != NULL)
7054 xmlFree(ctxt->context->tmpNsList);
7055 ctxt->context->tmpNsList = NULL;
7056 return(NULL);
7057 }
7058 }
7059
7060 /**
7061 * xmlXPathNextAttribute:
7062 * @ctxt: the XPath Parser context
7063 * @cur: the current attribute in the traversal
7064 *
7065 * Traversal function for the "attribute" direction
7066 * TODO: support DTD inherited default attributes
7067 *
7068 * Returns the next element following that axis
7069 */
7070 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7071 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7072 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7073 if (ctxt->context->node == NULL)
7074 return(NULL);
7075 if (ctxt->context->node->type != XML_ELEMENT_NODE)
7076 return(NULL);
7077 if (cur == NULL) {
7078 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7079 return(NULL);
7080 return((xmlNodePtr)ctxt->context->node->properties);
7081 }
7082 return((xmlNodePtr)cur->next);
7083 }
7084
7085 /************************************************************************
7086 * *
7087 * NodeTest Functions *
7088 * *
7089 ************************************************************************/
7090
7091 #define IS_FUNCTION 200
7092
7093
7094 /************************************************************************
7095 * *
7096 * Implicit tree core function library *
7097 * *
7098 ************************************************************************/
7099
7100 /**
7101 * xmlXPathRoot:
7102 * @ctxt: the XPath Parser context
7103 *
7104 * Initialize the context to the root of the document
7105 */
7106 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)7107 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7108 if ((ctxt == NULL) || (ctxt->context == NULL))
7109 return;
7110 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7111 (xmlNodePtr) ctxt->context->doc));
7112 }
7113
7114 /************************************************************************
7115 * *
7116 * The explicit core function library *
7117 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7118 * *
7119 ************************************************************************/
7120
7121
7122 /**
7123 * xmlXPathLastFunction:
7124 * @ctxt: the XPath Parser context
7125 * @nargs: the number of arguments
7126 *
7127 * Implement the last() XPath function
7128 * number last()
7129 * The last function returns the number of nodes in the context node list.
7130 */
7131 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)7132 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7133 CHECK_ARITY(0);
7134 if (ctxt->context->contextSize >= 0) {
7135 valuePush(ctxt,
7136 xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7137 } else {
7138 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7139 }
7140 }
7141
7142 /**
7143 * xmlXPathPositionFunction:
7144 * @ctxt: the XPath Parser context
7145 * @nargs: the number of arguments
7146 *
7147 * Implement the position() XPath function
7148 * number position()
7149 * The position function returns the position of the context node in the
7150 * context node list. The first position is 1, and so the last position
7151 * will be equal to last().
7152 */
7153 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)7154 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7155 CHECK_ARITY(0);
7156 if (ctxt->context->proximityPosition >= 0) {
7157 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7158 (double) ctxt->context->proximityPosition));
7159 } else {
7160 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7161 }
7162 }
7163
7164 /**
7165 * xmlXPathCountFunction:
7166 * @ctxt: the XPath Parser context
7167 * @nargs: the number of arguments
7168 *
7169 * Implement the count() XPath function
7170 * number count(node-set)
7171 */
7172 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)7173 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7174 xmlXPathObjectPtr cur;
7175
7176 CHECK_ARITY(1);
7177 if ((ctxt->value == NULL) ||
7178 ((ctxt->value->type != XPATH_NODESET) &&
7179 (ctxt->value->type != XPATH_XSLT_TREE)))
7180 XP_ERROR(XPATH_INVALID_TYPE);
7181 cur = valuePop(ctxt);
7182
7183 if ((cur == NULL) || (cur->nodesetval == NULL))
7184 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7185 else
7186 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7187 (double) cur->nodesetval->nodeNr));
7188 xmlXPathReleaseObject(ctxt->context, cur);
7189 }
7190
7191 /**
7192 * xmlXPathGetElementsByIds:
7193 * @doc: the document
7194 * @ids: a whitespace separated list of IDs
7195 *
7196 * Selects elements by their unique ID.
7197 *
7198 * Returns a node-set of selected elements.
7199 */
7200 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)7201 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7202 xmlNodeSetPtr ret;
7203 const xmlChar *cur = ids;
7204 xmlChar *ID;
7205 xmlAttrPtr attr;
7206 xmlNodePtr elem = NULL;
7207
7208 if (ids == NULL) return(NULL);
7209
7210 ret = xmlXPathNodeSetCreate(NULL);
7211 if (ret == NULL)
7212 return(ret);
7213
7214 while (IS_BLANK_CH(*cur)) cur++;
7215 while (*cur != 0) {
7216 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7217 cur++;
7218
7219 ID = xmlStrndup(ids, cur - ids);
7220 if (ID == NULL) {
7221 xmlXPathFreeNodeSet(ret);
7222 return(NULL);
7223 }
7224 /*
7225 * We used to check the fact that the value passed
7226 * was an NCName, but this generated much troubles for
7227 * me and Aleksey Sanin, people blatantly violated that
7228 * constraint, like Visa3D spec.
7229 * if (xmlValidateNCName(ID, 1) == 0)
7230 */
7231 attr = xmlGetID(doc, ID);
7232 xmlFree(ID);
7233 if (attr != NULL) {
7234 if (attr->type == XML_ATTRIBUTE_NODE)
7235 elem = attr->parent;
7236 else if (attr->type == XML_ELEMENT_NODE)
7237 elem = (xmlNodePtr) attr;
7238 else
7239 elem = NULL;
7240 if (elem != NULL) {
7241 if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7242 xmlXPathFreeNodeSet(ret);
7243 return(NULL);
7244 }
7245 }
7246 }
7247
7248 while (IS_BLANK_CH(*cur)) cur++;
7249 ids = cur;
7250 }
7251 return(ret);
7252 }
7253
7254 /**
7255 * xmlXPathIdFunction:
7256 * @ctxt: the XPath Parser context
7257 * @nargs: the number of arguments
7258 *
7259 * Implement the id() XPath function
7260 * node-set id(object)
7261 * The id function selects elements by their unique ID
7262 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7263 * then the result is the union of the result of applying id to the
7264 * string value of each of the nodes in the argument node-set. When the
7265 * argument to id is of any other type, the argument is converted to a
7266 * string as if by a call to the string function; the string is split
7267 * into a whitespace-separated list of tokens (whitespace is any sequence
7268 * of characters matching the production S); the result is a node-set
7269 * containing the elements in the same document as the context node that
7270 * have a unique ID equal to any of the tokens in the list.
7271 */
7272 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)7273 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7274 xmlChar *tokens;
7275 xmlNodeSetPtr ret;
7276 xmlXPathObjectPtr obj;
7277
7278 CHECK_ARITY(1);
7279 obj = valuePop(ctxt);
7280 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7281 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7282 xmlNodeSetPtr ns;
7283 int i;
7284
7285 ret = xmlXPathNodeSetCreate(NULL);
7286 if (ret == NULL)
7287 xmlXPathPErrMemory(ctxt);
7288
7289 if (obj->nodesetval != NULL) {
7290 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7291 tokens =
7292 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7293 if (tokens == NULL)
7294 xmlXPathPErrMemory(ctxt);
7295 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7296 if (ns == NULL)
7297 xmlXPathPErrMemory(ctxt);
7298 ret = xmlXPathNodeSetMerge(ret, ns);
7299 if (ret == NULL)
7300 xmlXPathPErrMemory(ctxt);
7301 xmlXPathFreeNodeSet(ns);
7302 if (tokens != NULL)
7303 xmlFree(tokens);
7304 }
7305 }
7306 xmlXPathReleaseObject(ctxt->context, obj);
7307 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7308 return;
7309 }
7310 tokens = xmlXPathCastToString(obj);
7311 if (tokens == NULL)
7312 xmlXPathPErrMemory(ctxt);
7313 xmlXPathReleaseObject(ctxt->context, obj);
7314 ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7315 if (ret == NULL)
7316 xmlXPathPErrMemory(ctxt);
7317 xmlFree(tokens);
7318 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7319 }
7320
7321 /**
7322 * xmlXPathLocalNameFunction:
7323 * @ctxt: the XPath Parser context
7324 * @nargs: the number of arguments
7325 *
7326 * Implement the local-name() XPath function
7327 * string local-name(node-set?)
7328 * The local-name function returns a string containing the local part
7329 * of the name of the node in the argument node-set that is first in
7330 * document order. If the node-set is empty or the first node has no
7331 * name, an empty string is returned. If the argument is omitted it
7332 * defaults to the context node.
7333 */
7334 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7335 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7336 xmlXPathObjectPtr cur;
7337
7338 if (ctxt == NULL) return;
7339
7340 if (nargs == 0) {
7341 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7342 nargs = 1;
7343 }
7344
7345 CHECK_ARITY(1);
7346 if ((ctxt->value == NULL) ||
7347 ((ctxt->value->type != XPATH_NODESET) &&
7348 (ctxt->value->type != XPATH_XSLT_TREE)))
7349 XP_ERROR(XPATH_INVALID_TYPE);
7350 cur = valuePop(ctxt);
7351
7352 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7353 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7354 } else {
7355 int i = 0; /* Should be first in document order !!!!! */
7356 switch (cur->nodesetval->nodeTab[i]->type) {
7357 case XML_ELEMENT_NODE:
7358 case XML_ATTRIBUTE_NODE:
7359 case XML_PI_NODE:
7360 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7361 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7362 else
7363 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7364 cur->nodesetval->nodeTab[i]->name));
7365 break;
7366 case XML_NAMESPACE_DECL:
7367 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7368 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7369 break;
7370 default:
7371 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7372 }
7373 }
7374 xmlXPathReleaseObject(ctxt->context, cur);
7375 }
7376
7377 /**
7378 * xmlXPathNamespaceURIFunction:
7379 * @ctxt: the XPath Parser context
7380 * @nargs: the number of arguments
7381 *
7382 * Implement the namespace-uri() XPath function
7383 * string namespace-uri(node-set?)
7384 * The namespace-uri function returns a string containing the
7385 * namespace URI of the expanded name of the node in the argument
7386 * node-set that is first in document order. If the node-set is empty,
7387 * the first node has no name, or the expanded name has no namespace
7388 * URI, an empty string is returned. If the argument is omitted it
7389 * defaults to the context node.
7390 */
7391 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)7392 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7393 xmlXPathObjectPtr cur;
7394
7395 if (ctxt == NULL) return;
7396
7397 if (nargs == 0) {
7398 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7399 nargs = 1;
7400 }
7401 CHECK_ARITY(1);
7402 if ((ctxt->value == NULL) ||
7403 ((ctxt->value->type != XPATH_NODESET) &&
7404 (ctxt->value->type != XPATH_XSLT_TREE)))
7405 XP_ERROR(XPATH_INVALID_TYPE);
7406 cur = valuePop(ctxt);
7407
7408 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7409 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7410 } else {
7411 int i = 0; /* Should be first in document order !!!!! */
7412 switch (cur->nodesetval->nodeTab[i]->type) {
7413 case XML_ELEMENT_NODE:
7414 case XML_ATTRIBUTE_NODE:
7415 if (cur->nodesetval->nodeTab[i]->ns == NULL)
7416 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7417 else
7418 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7419 cur->nodesetval->nodeTab[i]->ns->href));
7420 break;
7421 default:
7422 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7423 }
7424 }
7425 xmlXPathReleaseObject(ctxt->context, cur);
7426 }
7427
7428 /**
7429 * xmlXPathNameFunction:
7430 * @ctxt: the XPath Parser context
7431 * @nargs: the number of arguments
7432 *
7433 * Implement the name() XPath function
7434 * string name(node-set?)
7435 * The name function returns a string containing a QName representing
7436 * the name of the node in the argument node-set that is first in document
7437 * order. The QName must represent the name with respect to the namespace
7438 * declarations in effect on the node whose name is being represented.
7439 * Typically, this will be the form in which the name occurred in the XML
7440 * source. This need not be the case if there are namespace declarations
7441 * in effect on the node that associate multiple prefixes with the same
7442 * namespace. However, an implementation may include information about
7443 * the original prefix in its representation of nodes; in this case, an
7444 * implementation can ensure that the returned string is always the same
7445 * as the QName used in the XML source. If the argument it omitted it
7446 * defaults to the context node.
7447 * Libxml keep the original prefix so the "real qualified name" used is
7448 * returned.
7449 */
7450 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7451 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7452 {
7453 xmlXPathObjectPtr cur;
7454
7455 if (nargs == 0) {
7456 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7457 nargs = 1;
7458 }
7459
7460 CHECK_ARITY(1);
7461 if ((ctxt->value == NULL) ||
7462 ((ctxt->value->type != XPATH_NODESET) &&
7463 (ctxt->value->type != XPATH_XSLT_TREE)))
7464 XP_ERROR(XPATH_INVALID_TYPE);
7465 cur = valuePop(ctxt);
7466
7467 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7468 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7469 } else {
7470 int i = 0; /* Should be first in document order !!!!! */
7471
7472 switch (cur->nodesetval->nodeTab[i]->type) {
7473 case XML_ELEMENT_NODE:
7474 case XML_ATTRIBUTE_NODE:
7475 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7476 valuePush(ctxt,
7477 xmlXPathCacheNewCString(ctxt, ""));
7478 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7479 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7480 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7481 cur->nodesetval->nodeTab[i]->name));
7482 } else {
7483 xmlChar *fullname;
7484
7485 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7486 cur->nodesetval->nodeTab[i]->ns->prefix,
7487 NULL, 0);
7488 if (fullname == cur->nodesetval->nodeTab[i]->name)
7489 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7490 if (fullname == NULL)
7491 xmlXPathPErrMemory(ctxt);
7492 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7493 }
7494 break;
7495 default:
7496 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7497 cur->nodesetval->nodeTab[i]));
7498 xmlXPathLocalNameFunction(ctxt, 1);
7499 }
7500 }
7501 xmlXPathReleaseObject(ctxt->context, cur);
7502 }
7503
7504
7505 /**
7506 * xmlXPathStringFunction:
7507 * @ctxt: the XPath Parser context
7508 * @nargs: the number of arguments
7509 *
7510 * Implement the string() XPath function
7511 * string string(object?)
7512 * The string function converts an object to a string as follows:
7513 * - A node-set is converted to a string by returning the value of
7514 * the node in the node-set that is first in document order.
7515 * If the node-set is empty, an empty string is returned.
7516 * - A number is converted to a string as follows
7517 * + NaN is converted to the string NaN
7518 * + positive zero is converted to the string 0
7519 * + negative zero is converted to the string 0
7520 * + positive infinity is converted to the string Infinity
7521 * + negative infinity is converted to the string -Infinity
7522 * + if the number is an integer, the number is represented in
7523 * decimal form as a Number with no decimal point and no leading
7524 * zeros, preceded by a minus sign (-) if the number is negative
7525 * + otherwise, the number is represented in decimal form as a
7526 * Number including a decimal point with at least one digit
7527 * before the decimal point and at least one digit after the
7528 * decimal point, preceded by a minus sign (-) if the number
7529 * is negative; there must be no leading zeros before the decimal
7530 * point apart possibly from the one required digit immediately
7531 * before the decimal point; beyond the one required digit
7532 * after the decimal point there must be as many, but only as
7533 * many, more digits as are needed to uniquely distinguish the
7534 * number from all other IEEE 754 numeric values.
7535 * - The boolean false value is converted to the string false.
7536 * The boolean true value is converted to the string true.
7537 *
7538 * If the argument is omitted, it defaults to a node-set with the
7539 * context node as its only member.
7540 */
7541 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)7542 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7543 xmlXPathObjectPtr cur;
7544 xmlChar *stringval;
7545
7546 if (ctxt == NULL) return;
7547 if (nargs == 0) {
7548 stringval = xmlXPathCastNodeToString(ctxt->context->node);
7549 if (stringval == NULL)
7550 xmlXPathPErrMemory(ctxt);
7551 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7552 return;
7553 }
7554
7555 CHECK_ARITY(1);
7556 cur = valuePop(ctxt);
7557 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7558 if (cur->type != XPATH_STRING) {
7559 stringval = xmlXPathCastToString(cur);
7560 if (stringval == NULL)
7561 xmlXPathPErrMemory(ctxt);
7562 xmlXPathReleaseObject(ctxt->context, cur);
7563 cur = xmlXPathCacheWrapString(ctxt, stringval);
7564 }
7565 valuePush(ctxt, cur);
7566 }
7567
7568 /**
7569 * xmlXPathStringLengthFunction:
7570 * @ctxt: the XPath Parser context
7571 * @nargs: the number of arguments
7572 *
7573 * Implement the string-length() XPath function
7574 * number string-length(string?)
7575 * The string-length returns the number of characters in the string
7576 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7577 * the context node converted to a string, in other words the value
7578 * of the context node.
7579 */
7580 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)7581 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7582 xmlXPathObjectPtr cur;
7583
7584 if (nargs == 0) {
7585 if ((ctxt == NULL) || (ctxt->context == NULL))
7586 return;
7587 if (ctxt->context->node == NULL) {
7588 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7589 } else {
7590 xmlChar *content;
7591
7592 content = xmlXPathCastNodeToString(ctxt->context->node);
7593 if (content == NULL)
7594 xmlXPathPErrMemory(ctxt);
7595 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7596 xmlUTF8Strlen(content)));
7597 xmlFree(content);
7598 }
7599 return;
7600 }
7601 CHECK_ARITY(1);
7602 CAST_TO_STRING;
7603 CHECK_TYPE(XPATH_STRING);
7604 cur = valuePop(ctxt);
7605 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7606 xmlUTF8Strlen(cur->stringval)));
7607 xmlXPathReleaseObject(ctxt->context, cur);
7608 }
7609
7610 /**
7611 * xmlXPathConcatFunction:
7612 * @ctxt: the XPath Parser context
7613 * @nargs: the number of arguments
7614 *
7615 * Implement the concat() XPath function
7616 * string concat(string, string, string*)
7617 * The concat function returns the concatenation of its arguments.
7618 */
7619 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)7620 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7621 xmlXPathObjectPtr cur, newobj;
7622 xmlChar *tmp;
7623
7624 if (ctxt == NULL) return;
7625 if (nargs < 2) {
7626 CHECK_ARITY(2);
7627 }
7628
7629 CAST_TO_STRING;
7630 cur = valuePop(ctxt);
7631 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7632 xmlXPathReleaseObject(ctxt->context, cur);
7633 return;
7634 }
7635 nargs--;
7636
7637 while (nargs > 0) {
7638 CAST_TO_STRING;
7639 newobj = valuePop(ctxt);
7640 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7641 xmlXPathReleaseObject(ctxt->context, newobj);
7642 xmlXPathReleaseObject(ctxt->context, cur);
7643 XP_ERROR(XPATH_INVALID_TYPE);
7644 }
7645 tmp = xmlStrcat(newobj->stringval, cur->stringval);
7646 if (tmp == NULL)
7647 xmlXPathPErrMemory(ctxt);
7648 newobj->stringval = cur->stringval;
7649 cur->stringval = tmp;
7650 xmlXPathReleaseObject(ctxt->context, newobj);
7651 nargs--;
7652 }
7653 valuePush(ctxt, cur);
7654 }
7655
7656 /**
7657 * xmlXPathContainsFunction:
7658 * @ctxt: the XPath Parser context
7659 * @nargs: the number of arguments
7660 *
7661 * Implement the contains() XPath function
7662 * boolean contains(string, string)
7663 * The contains function returns true if the first argument string
7664 * contains the second argument string, and otherwise returns false.
7665 */
7666 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)7667 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7668 xmlXPathObjectPtr hay, needle;
7669
7670 CHECK_ARITY(2);
7671 CAST_TO_STRING;
7672 CHECK_TYPE(XPATH_STRING);
7673 needle = valuePop(ctxt);
7674 CAST_TO_STRING;
7675 hay = valuePop(ctxt);
7676
7677 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7678 xmlXPathReleaseObject(ctxt->context, hay);
7679 xmlXPathReleaseObject(ctxt->context, needle);
7680 XP_ERROR(XPATH_INVALID_TYPE);
7681 }
7682 if (xmlStrstr(hay->stringval, needle->stringval))
7683 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7684 else
7685 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7686 xmlXPathReleaseObject(ctxt->context, hay);
7687 xmlXPathReleaseObject(ctxt->context, needle);
7688 }
7689
7690 /**
7691 * xmlXPathStartsWithFunction:
7692 * @ctxt: the XPath Parser context
7693 * @nargs: the number of arguments
7694 *
7695 * Implement the starts-with() XPath function
7696 * boolean starts-with(string, string)
7697 * The starts-with function returns true if the first argument string
7698 * starts with the second argument string, and otherwise returns false.
7699 */
7700 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)7701 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7702 xmlXPathObjectPtr hay, needle;
7703 int n;
7704
7705 CHECK_ARITY(2);
7706 CAST_TO_STRING;
7707 CHECK_TYPE(XPATH_STRING);
7708 needle = valuePop(ctxt);
7709 CAST_TO_STRING;
7710 hay = valuePop(ctxt);
7711
7712 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7713 xmlXPathReleaseObject(ctxt->context, hay);
7714 xmlXPathReleaseObject(ctxt->context, needle);
7715 XP_ERROR(XPATH_INVALID_TYPE);
7716 }
7717 n = xmlStrlen(needle->stringval);
7718 if (xmlStrncmp(hay->stringval, needle->stringval, n))
7719 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7720 else
7721 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7722 xmlXPathReleaseObject(ctxt->context, hay);
7723 xmlXPathReleaseObject(ctxt->context, needle);
7724 }
7725
7726 /**
7727 * xmlXPathSubstringFunction:
7728 * @ctxt: the XPath Parser context
7729 * @nargs: the number of arguments
7730 *
7731 * Implement the substring() XPath function
7732 * string substring(string, number, number?)
7733 * The substring function returns the substring of the first argument
7734 * starting at the position specified in the second argument with
7735 * length specified in the third argument. For example,
7736 * substring("12345",2,3) returns "234". If the third argument is not
7737 * specified, it returns the substring starting at the position specified
7738 * in the second argument and continuing to the end of the string. For
7739 * example, substring("12345",2) returns "2345". More precisely, each
7740 * character in the string (see [3.6 Strings]) is considered to have a
7741 * numeric position: the position of the first character is 1, the position
7742 * of the second character is 2 and so on. The returned substring contains
7743 * those characters for which the position of the character is greater than
7744 * or equal to the second argument and, if the third argument is specified,
7745 * less than the sum of the second and third arguments; the comparisons
7746 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7747 * - substring("12345", 1.5, 2.6) returns "234"
7748 * - substring("12345", 0, 3) returns "12"
7749 * - substring("12345", 0 div 0, 3) returns ""
7750 * - substring("12345", 1, 0 div 0) returns ""
7751 * - substring("12345", -42, 1 div 0) returns "12345"
7752 * - substring("12345", -1 div 0, 1 div 0) returns ""
7753 */
7754 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)7755 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7756 xmlXPathObjectPtr str, start, len;
7757 double le=0, in;
7758 int i = 1, j = INT_MAX;
7759
7760 if (nargs < 2) {
7761 CHECK_ARITY(2);
7762 }
7763 if (nargs > 3) {
7764 CHECK_ARITY(3);
7765 }
7766 /*
7767 * take care of possible last (position) argument
7768 */
7769 if (nargs == 3) {
7770 CAST_TO_NUMBER;
7771 CHECK_TYPE(XPATH_NUMBER);
7772 len = valuePop(ctxt);
7773 le = len->floatval;
7774 xmlXPathReleaseObject(ctxt->context, len);
7775 }
7776
7777 CAST_TO_NUMBER;
7778 CHECK_TYPE(XPATH_NUMBER);
7779 start = valuePop(ctxt);
7780 in = start->floatval;
7781 xmlXPathReleaseObject(ctxt->context, start);
7782 CAST_TO_STRING;
7783 CHECK_TYPE(XPATH_STRING);
7784 str = valuePop(ctxt);
7785
7786 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7787 i = INT_MAX;
7788 } else if (in >= 1.0) {
7789 i = (int)in;
7790 if (in - floor(in) >= 0.5)
7791 i += 1;
7792 }
7793
7794 if (nargs == 3) {
7795 double rin, rle, end;
7796
7797 rin = floor(in);
7798 if (in - rin >= 0.5)
7799 rin += 1.0;
7800
7801 rle = floor(le);
7802 if (le - rle >= 0.5)
7803 rle += 1.0;
7804
7805 end = rin + rle;
7806 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7807 j = 1;
7808 } else if (end < INT_MAX) {
7809 j = (int)end;
7810 }
7811 }
7812
7813 i -= 1;
7814 j -= 1;
7815
7816 if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7817 xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7818 if (ret == NULL)
7819 xmlXPathPErrMemory(ctxt);
7820 valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7821 xmlFree(ret);
7822 } else {
7823 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7824 }
7825
7826 xmlXPathReleaseObject(ctxt->context, str);
7827 }
7828
7829 /**
7830 * xmlXPathSubstringBeforeFunction:
7831 * @ctxt: the XPath Parser context
7832 * @nargs: the number of arguments
7833 *
7834 * Implement the substring-before() XPath function
7835 * string substring-before(string, string)
7836 * The substring-before function returns the substring of the first
7837 * argument string that precedes the first occurrence of the second
7838 * argument string in the first argument string, or the empty string
7839 * if the first argument string does not contain the second argument
7840 * string. For example, substring-before("1999/04/01","/") returns 1999.
7841 */
7842 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)7843 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7844 xmlXPathObjectPtr str = NULL;
7845 xmlXPathObjectPtr find = NULL;
7846 const xmlChar *point;
7847 xmlChar *result;
7848
7849 CHECK_ARITY(2);
7850 CAST_TO_STRING;
7851 find = valuePop(ctxt);
7852 CAST_TO_STRING;
7853 str = valuePop(ctxt);
7854 if (ctxt->error != 0)
7855 goto error;
7856
7857 point = xmlStrstr(str->stringval, find->stringval);
7858 if (point == NULL) {
7859 result = xmlStrdup(BAD_CAST "");
7860 } else {
7861 result = xmlStrndup(str->stringval, point - str->stringval);
7862 }
7863 if (result == NULL) {
7864 xmlXPathPErrMemory(ctxt);
7865 goto error;
7866 }
7867 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7868
7869 error:
7870 xmlXPathReleaseObject(ctxt->context, str);
7871 xmlXPathReleaseObject(ctxt->context, find);
7872 }
7873
7874 /**
7875 * xmlXPathSubstringAfterFunction:
7876 * @ctxt: the XPath Parser context
7877 * @nargs: the number of arguments
7878 *
7879 * Implement the substring-after() XPath function
7880 * string substring-after(string, string)
7881 * The substring-after function returns the substring of the first
7882 * argument string that follows the first occurrence of the second
7883 * argument string in the first argument string, or the empty string
7884 * if the first argument string does not contain the second argument
7885 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7886 * and substring-after("1999/04/01","19") returns 99/04/01.
7887 */
7888 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)7889 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7890 xmlXPathObjectPtr str = NULL;
7891 xmlXPathObjectPtr find = NULL;
7892 const xmlChar *point;
7893 xmlChar *result;
7894
7895 CHECK_ARITY(2);
7896 CAST_TO_STRING;
7897 find = valuePop(ctxt);
7898 CAST_TO_STRING;
7899 str = valuePop(ctxt);
7900 if (ctxt->error != 0)
7901 goto error;
7902
7903 point = xmlStrstr(str->stringval, find->stringval);
7904 if (point == NULL) {
7905 result = xmlStrdup(BAD_CAST "");
7906 } else {
7907 result = xmlStrdup(point + xmlStrlen(find->stringval));
7908 }
7909 if (result == NULL) {
7910 xmlXPathPErrMemory(ctxt);
7911 goto error;
7912 }
7913 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7914
7915 error:
7916 xmlXPathReleaseObject(ctxt->context, str);
7917 xmlXPathReleaseObject(ctxt->context, find);
7918 }
7919
7920 /**
7921 * xmlXPathNormalizeFunction:
7922 * @ctxt: the XPath Parser context
7923 * @nargs: the number of arguments
7924 *
7925 * Implement the normalize-space() XPath function
7926 * string normalize-space(string?)
7927 * The normalize-space function returns the argument string with white
7928 * space normalized by stripping leading and trailing whitespace
7929 * and replacing sequences of whitespace characters by a single
7930 * space. Whitespace characters are the same allowed by the S production
7931 * in XML. If the argument is omitted, it defaults to the context
7932 * node converted to a string, in other words the value of the context node.
7933 */
7934 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)7935 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7936 xmlChar *source, *target;
7937 int blank;
7938
7939 if (ctxt == NULL) return;
7940 if (nargs == 0) {
7941 /* Use current context node */
7942 source = xmlXPathCastNodeToString(ctxt->context->node);
7943 if (source == NULL)
7944 xmlXPathPErrMemory(ctxt);
7945 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7946 nargs = 1;
7947 }
7948
7949 CHECK_ARITY(1);
7950 CAST_TO_STRING;
7951 CHECK_TYPE(XPATH_STRING);
7952 source = ctxt->value->stringval;
7953 if (source == NULL)
7954 return;
7955 target = source;
7956
7957 /* Skip leading whitespaces */
7958 while (IS_BLANK_CH(*source))
7959 source++;
7960
7961 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7962 blank = 0;
7963 while (*source) {
7964 if (IS_BLANK_CH(*source)) {
7965 blank = 1;
7966 } else {
7967 if (blank) {
7968 *target++ = 0x20;
7969 blank = 0;
7970 }
7971 *target++ = *source;
7972 }
7973 source++;
7974 }
7975 *target = 0;
7976 }
7977
7978 /**
7979 * xmlXPathTranslateFunction:
7980 * @ctxt: the XPath Parser context
7981 * @nargs: the number of arguments
7982 *
7983 * Implement the translate() XPath function
7984 * string translate(string, string, string)
7985 * The translate function returns the first argument string with
7986 * occurrences of characters in the second argument string replaced
7987 * by the character at the corresponding position in the third argument
7988 * string. For example, translate("bar","abc","ABC") returns the string
7989 * BAr. If there is a character in the second argument string with no
7990 * character at a corresponding position in the third argument string
7991 * (because the second argument string is longer than the third argument
7992 * string), then occurrences of that character in the first argument
7993 * string are removed. For example, translate("--aaa--","abc-","ABC")
7994 * returns "AAA". If a character occurs more than once in second
7995 * argument string, then the first occurrence determines the replacement
7996 * character. If the third argument string is longer than the second
7997 * argument string, then excess characters are ignored.
7998 */
7999 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)8000 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8001 xmlXPathObjectPtr str = NULL;
8002 xmlXPathObjectPtr from = NULL;
8003 xmlXPathObjectPtr to = NULL;
8004 xmlBufPtr target;
8005 int offset, max;
8006 int ch;
8007 const xmlChar *point;
8008 xmlChar *cptr, *content;
8009
8010 CHECK_ARITY(3);
8011
8012 CAST_TO_STRING;
8013 to = valuePop(ctxt);
8014 CAST_TO_STRING;
8015 from = valuePop(ctxt);
8016 CAST_TO_STRING;
8017 str = valuePop(ctxt);
8018 if (ctxt->error != 0)
8019 goto error;
8020
8021 /*
8022 * Account for quadratic runtime
8023 */
8024 if (ctxt->context->opLimit != 0) {
8025 unsigned long f1 = xmlStrlen(from->stringval);
8026 unsigned long f2 = xmlStrlen(str->stringval);
8027
8028 if ((f1 > 0) && (f2 > 0)) {
8029 unsigned long p;
8030
8031 f1 = f1 / 10 + 1;
8032 f2 = f2 / 10 + 1;
8033 p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
8034 if (xmlXPathCheckOpLimit(ctxt, p) < 0)
8035 goto error;
8036 }
8037 }
8038
8039 target = xmlBufCreate(50);
8040 if (target == NULL) {
8041 xmlXPathPErrMemory(ctxt);
8042 goto error;
8043 }
8044
8045 max = xmlUTF8Strlen(to->stringval);
8046 for (cptr = str->stringval; (ch=*cptr); ) {
8047 offset = xmlUTF8Strloc(from->stringval, cptr);
8048 if (offset >= 0) {
8049 if (offset < max) {
8050 point = xmlUTF8Strpos(to->stringval, offset);
8051 if (point)
8052 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8053 }
8054 } else
8055 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8056
8057 /* Step to next character in input */
8058 cptr++;
8059 if ( ch & 0x80 ) {
8060 /* if not simple ascii, verify proper format */
8061 if ( (ch & 0xc0) != 0xc0 ) {
8062 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8063 break;
8064 }
8065 /* then skip over remaining bytes for this char */
8066 while ( (ch <<= 1) & 0x80 )
8067 if ( (*cptr++ & 0xc0) != 0x80 ) {
8068 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8069 break;
8070 }
8071 if (ch & 0x80) /* must have had error encountered */
8072 break;
8073 }
8074 }
8075
8076 content = xmlBufDetach(target);
8077 if (content == NULL)
8078 xmlXPathPErrMemory(ctxt);
8079 else
8080 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
8081 xmlBufFree(target);
8082 error:
8083 xmlXPathReleaseObject(ctxt->context, str);
8084 xmlXPathReleaseObject(ctxt->context, from);
8085 xmlXPathReleaseObject(ctxt->context, to);
8086 }
8087
8088 /**
8089 * xmlXPathBooleanFunction:
8090 * @ctxt: the XPath Parser context
8091 * @nargs: the number of arguments
8092 *
8093 * Implement the boolean() XPath function
8094 * boolean boolean(object)
8095 * The boolean function converts its argument to a boolean as follows:
8096 * - a number is true if and only if it is neither positive or
8097 * negative zero nor NaN
8098 * - a node-set is true if and only if it is non-empty
8099 * - a string is true if and only if its length is non-zero
8100 */
8101 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)8102 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8103 xmlXPathObjectPtr cur;
8104
8105 CHECK_ARITY(1);
8106 cur = valuePop(ctxt);
8107 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8108 if (cur->type != XPATH_BOOLEAN) {
8109 int boolval = xmlXPathCastToBoolean(cur);
8110
8111 xmlXPathReleaseObject(ctxt->context, cur);
8112 cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8113 }
8114 valuePush(ctxt, cur);
8115 }
8116
8117 /**
8118 * xmlXPathNotFunction:
8119 * @ctxt: the XPath Parser context
8120 * @nargs: the number of arguments
8121 *
8122 * Implement the not() XPath function
8123 * boolean not(boolean)
8124 * The not function returns true if its argument is false,
8125 * and false otherwise.
8126 */
8127 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)8128 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8129 CHECK_ARITY(1);
8130 CAST_TO_BOOLEAN;
8131 CHECK_TYPE(XPATH_BOOLEAN);
8132 ctxt->value->boolval = ! ctxt->value->boolval;
8133 }
8134
8135 /**
8136 * xmlXPathTrueFunction:
8137 * @ctxt: the XPath Parser context
8138 * @nargs: the number of arguments
8139 *
8140 * Implement the true() XPath function
8141 * boolean true()
8142 */
8143 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)8144 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8145 CHECK_ARITY(0);
8146 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8147 }
8148
8149 /**
8150 * xmlXPathFalseFunction:
8151 * @ctxt: the XPath Parser context
8152 * @nargs: the number of arguments
8153 *
8154 * Implement the false() XPath function
8155 * boolean false()
8156 */
8157 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)8158 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8159 CHECK_ARITY(0);
8160 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8161 }
8162
8163 /**
8164 * xmlXPathLangFunction:
8165 * @ctxt: the XPath Parser context
8166 * @nargs: the number of arguments
8167 *
8168 * Implement the lang() XPath function
8169 * boolean lang(string)
8170 * The lang function returns true or false depending on whether the
8171 * language of the context node as specified by xml:lang attributes
8172 * is the same as or is a sublanguage of the language specified by
8173 * the argument string. The language of the context node is determined
8174 * by the value of the xml:lang attribute on the context node, or, if
8175 * the context node has no xml:lang attribute, by the value of the
8176 * xml:lang attribute on the nearest ancestor of the context node that
8177 * has an xml:lang attribute. If there is no such attribute, then lang
8178 * returns false. If there is such an attribute, then lang returns
8179 * true if the attribute value is equal to the argument ignoring case,
8180 * or if there is some suffix starting with - such that the attribute
8181 * value is equal to the argument ignoring that suffix of the attribute
8182 * value and ignoring case.
8183 */
8184 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)8185 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8186 xmlXPathObjectPtr val;
8187 xmlNodePtr cur;
8188 xmlChar *theLang;
8189 const xmlChar *lang;
8190 int ret = 0;
8191 int i;
8192
8193 CHECK_ARITY(1);
8194 CAST_TO_STRING;
8195 CHECK_TYPE(XPATH_STRING);
8196 val = valuePop(ctxt);
8197 lang = val->stringval;
8198 cur = ctxt->context->node;
8199 while (cur != NULL) {
8200 if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8201 &theLang) < 0)
8202 xmlXPathPErrMemory(ctxt);
8203 if (theLang != NULL)
8204 break;
8205 cur = cur->parent;
8206 }
8207 if ((theLang != NULL) && (lang != NULL)) {
8208 for (i = 0;lang[i] != 0;i++)
8209 if (toupper(lang[i]) != toupper(theLang[i]))
8210 goto not_equal;
8211 if ((theLang[i] == 0) || (theLang[i] == '-'))
8212 ret = 1;
8213 }
8214 not_equal:
8215 if (theLang != NULL)
8216 xmlFree((void *)theLang);
8217
8218 xmlXPathReleaseObject(ctxt->context, val);
8219 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8220 }
8221
8222 /**
8223 * xmlXPathNumberFunction:
8224 * @ctxt: the XPath Parser context
8225 * @nargs: the number of arguments
8226 *
8227 * Implement the number() XPath function
8228 * number number(object?)
8229 */
8230 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)8231 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8232 xmlXPathObjectPtr cur;
8233 double res;
8234
8235 if (ctxt == NULL) return;
8236 if (nargs == 0) {
8237 if (ctxt->context->node == NULL) {
8238 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8239 } else {
8240 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8241 if (content == NULL)
8242 xmlXPathPErrMemory(ctxt);
8243
8244 res = xmlXPathStringEvalNumber(content);
8245 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8246 xmlFree(content);
8247 }
8248 return;
8249 }
8250
8251 CHECK_ARITY(1);
8252 cur = valuePop(ctxt);
8253 if (cur->type != XPATH_NUMBER) {
8254 double floatval;
8255
8256 floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8257 xmlXPathReleaseObject(ctxt->context, cur);
8258 cur = xmlXPathCacheNewFloat(ctxt, floatval);
8259 }
8260 valuePush(ctxt, cur);
8261 }
8262
8263 /**
8264 * xmlXPathSumFunction:
8265 * @ctxt: the XPath Parser context
8266 * @nargs: the number of arguments
8267 *
8268 * Implement the sum() XPath function
8269 * number sum(node-set)
8270 * The sum function returns the sum of the values of the nodes in
8271 * the argument node-set.
8272 */
8273 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)8274 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8275 xmlXPathObjectPtr cur;
8276 int i;
8277 double res = 0.0;
8278
8279 CHECK_ARITY(1);
8280 if ((ctxt->value == NULL) ||
8281 ((ctxt->value->type != XPATH_NODESET) &&
8282 (ctxt->value->type != XPATH_XSLT_TREE)))
8283 XP_ERROR(XPATH_INVALID_TYPE);
8284 cur = valuePop(ctxt);
8285
8286 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8287 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8288 res += xmlXPathNodeToNumberInternal(ctxt,
8289 cur->nodesetval->nodeTab[i]);
8290 }
8291 }
8292 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8293 xmlXPathReleaseObject(ctxt->context, cur);
8294 }
8295
8296 /**
8297 * xmlXPathFloorFunction:
8298 * @ctxt: the XPath Parser context
8299 * @nargs: the number of arguments
8300 *
8301 * Implement the floor() XPath function
8302 * number floor(number)
8303 * The floor function returns the largest (closest to positive infinity)
8304 * number that is not greater than the argument and that is an integer.
8305 */
8306 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)8307 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8308 CHECK_ARITY(1);
8309 CAST_TO_NUMBER;
8310 CHECK_TYPE(XPATH_NUMBER);
8311
8312 ctxt->value->floatval = floor(ctxt->value->floatval);
8313 }
8314
8315 /**
8316 * xmlXPathCeilingFunction:
8317 * @ctxt: the XPath Parser context
8318 * @nargs: the number of arguments
8319 *
8320 * Implement the ceiling() XPath function
8321 * number ceiling(number)
8322 * The ceiling function returns the smallest (closest to negative infinity)
8323 * number that is not less than the argument and that is an integer.
8324 */
8325 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)8326 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8327 CHECK_ARITY(1);
8328 CAST_TO_NUMBER;
8329 CHECK_TYPE(XPATH_NUMBER);
8330
8331 #ifdef _AIX
8332 /* Work around buggy ceil() function on AIX */
8333 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8334 #else
8335 ctxt->value->floatval = ceil(ctxt->value->floatval);
8336 #endif
8337 }
8338
8339 /**
8340 * xmlXPathRoundFunction:
8341 * @ctxt: the XPath Parser context
8342 * @nargs: the number of arguments
8343 *
8344 * Implement the round() XPath function
8345 * number round(number)
8346 * The round function returns the number that is closest to the
8347 * argument and that is an integer. If there are two such numbers,
8348 * then the one that is closest to positive infinity is returned.
8349 */
8350 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)8351 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8352 double f;
8353
8354 CHECK_ARITY(1);
8355 CAST_TO_NUMBER;
8356 CHECK_TYPE(XPATH_NUMBER);
8357
8358 f = ctxt->value->floatval;
8359
8360 if ((f >= -0.5) && (f < 0.5)) {
8361 /* Handles negative zero. */
8362 ctxt->value->floatval *= 0.0;
8363 }
8364 else {
8365 double rounded = floor(f);
8366 if (f - rounded >= 0.5)
8367 rounded += 1.0;
8368 ctxt->value->floatval = rounded;
8369 }
8370 }
8371
8372 /************************************************************************
8373 * *
8374 * The Parser *
8375 * *
8376 ************************************************************************/
8377
8378 /*
8379 * a few forward declarations since we use a recursive call based
8380 * implementation.
8381 */
8382 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8383 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8384 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8385 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8386 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8387 int qualified);
8388
8389 /**
8390 * xmlXPathCurrentChar:
8391 * @ctxt: the XPath parser context
8392 * @cur: pointer to the beginning of the char
8393 * @len: pointer to the length of the char read
8394 *
8395 * The current char value, if using UTF-8 this may actually span multiple
8396 * bytes in the input buffer.
8397 *
8398 * Returns the current char value and its length
8399 */
8400
8401 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)8402 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8403 unsigned char c;
8404 unsigned int val;
8405 const xmlChar *cur;
8406
8407 if (ctxt == NULL)
8408 return(0);
8409 cur = ctxt->cur;
8410
8411 /*
8412 * We are supposed to handle UTF8, check it's valid
8413 * From rfc2044: encoding of the Unicode values on UTF-8:
8414 *
8415 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
8416 * 0000 0000-0000 007F 0xxxxxxx
8417 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
8418 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
8419 *
8420 * Check for the 0x110000 limit too
8421 */
8422 c = *cur;
8423 if (c & 0x80) {
8424 if ((cur[1] & 0xc0) != 0x80)
8425 goto encoding_error;
8426 if ((c & 0xe0) == 0xe0) {
8427
8428 if ((cur[2] & 0xc0) != 0x80)
8429 goto encoding_error;
8430 if ((c & 0xf0) == 0xf0) {
8431 if (((c & 0xf8) != 0xf0) ||
8432 ((cur[3] & 0xc0) != 0x80))
8433 goto encoding_error;
8434 /* 4-byte code */
8435 *len = 4;
8436 val = (cur[0] & 0x7) << 18;
8437 val |= (cur[1] & 0x3f) << 12;
8438 val |= (cur[2] & 0x3f) << 6;
8439 val |= cur[3] & 0x3f;
8440 } else {
8441 /* 3-byte code */
8442 *len = 3;
8443 val = (cur[0] & 0xf) << 12;
8444 val |= (cur[1] & 0x3f) << 6;
8445 val |= cur[2] & 0x3f;
8446 }
8447 } else {
8448 /* 2-byte code */
8449 *len = 2;
8450 val = (cur[0] & 0x1f) << 6;
8451 val |= cur[1] & 0x3f;
8452 }
8453 if (!IS_CHAR(val)) {
8454 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8455 }
8456 return(val);
8457 } else {
8458 /* 1-byte code */
8459 *len = 1;
8460 return(*cur);
8461 }
8462 encoding_error:
8463 /*
8464 * If we detect an UTF8 error that probably means that the
8465 * input encoding didn't get properly advertised in the
8466 * declaration header. Report the error and switch the encoding
8467 * to ISO-Latin-1 (if you don't like this policy, just declare the
8468 * encoding !)
8469 */
8470 *len = 0;
8471 XP_ERROR0(XPATH_ENCODING_ERROR);
8472 }
8473
8474 /**
8475 * xmlXPathParseNCName:
8476 * @ctxt: the XPath Parser context
8477 *
8478 * parse an XML namespace non qualified name.
8479 *
8480 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8481 *
8482 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8483 * CombiningChar | Extender
8484 *
8485 * Returns the namespace name or NULL
8486 */
8487
8488 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)8489 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8490 const xmlChar *in;
8491 xmlChar *ret;
8492 int count = 0;
8493
8494 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8495 /*
8496 * Accelerator for simple ASCII names
8497 */
8498 in = ctxt->cur;
8499 if (((*in >= 0x61) && (*in <= 0x7A)) ||
8500 ((*in >= 0x41) && (*in <= 0x5A)) ||
8501 (*in == '_')) {
8502 in++;
8503 while (((*in >= 0x61) && (*in <= 0x7A)) ||
8504 ((*in >= 0x41) && (*in <= 0x5A)) ||
8505 ((*in >= 0x30) && (*in <= 0x39)) ||
8506 (*in == '_') || (*in == '.') ||
8507 (*in == '-'))
8508 in++;
8509 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8510 (*in == '[') || (*in == ']') || (*in == ':') ||
8511 (*in == '@') || (*in == '*')) {
8512 count = in - ctxt->cur;
8513 if (count == 0)
8514 return(NULL);
8515 ret = xmlStrndup(ctxt->cur, count);
8516 if (ret == NULL)
8517 xmlXPathPErrMemory(ctxt);
8518 ctxt->cur = in;
8519 return(ret);
8520 }
8521 }
8522 return(xmlXPathParseNameComplex(ctxt, 0));
8523 }
8524
8525
8526 /**
8527 * xmlXPathParseQName:
8528 * @ctxt: the XPath Parser context
8529 * @prefix: a xmlChar **
8530 *
8531 * parse an XML qualified name
8532 *
8533 * [NS 5] QName ::= (Prefix ':')? LocalPart
8534 *
8535 * [NS 6] Prefix ::= NCName
8536 *
8537 * [NS 7] LocalPart ::= NCName
8538 *
8539 * Returns the function returns the local part, and prefix is updated
8540 * to get the Prefix if any.
8541 */
8542
8543 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)8544 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8545 xmlChar *ret = NULL;
8546
8547 *prefix = NULL;
8548 ret = xmlXPathParseNCName(ctxt);
8549 if (ret && CUR == ':') {
8550 *prefix = ret;
8551 NEXT;
8552 ret = xmlXPathParseNCName(ctxt);
8553 }
8554 return(ret);
8555 }
8556
8557 /**
8558 * xmlXPathParseName:
8559 * @ctxt: the XPath Parser context
8560 *
8561 * parse an XML name
8562 *
8563 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8564 * CombiningChar | Extender
8565 *
8566 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8567 *
8568 * Returns the namespace name or NULL
8569 */
8570
8571 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)8572 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8573 const xmlChar *in;
8574 xmlChar *ret;
8575 size_t count = 0;
8576
8577 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8578 /*
8579 * Accelerator for simple ASCII names
8580 */
8581 in = ctxt->cur;
8582 if (((*in >= 0x61) && (*in <= 0x7A)) ||
8583 ((*in >= 0x41) && (*in <= 0x5A)) ||
8584 (*in == '_') || (*in == ':')) {
8585 in++;
8586 while (((*in >= 0x61) && (*in <= 0x7A)) ||
8587 ((*in >= 0x41) && (*in <= 0x5A)) ||
8588 ((*in >= 0x30) && (*in <= 0x39)) ||
8589 (*in == '_') || (*in == '-') ||
8590 (*in == ':') || (*in == '.'))
8591 in++;
8592 if ((*in > 0) && (*in < 0x80)) {
8593 count = in - ctxt->cur;
8594 if (count > XML_MAX_NAME_LENGTH) {
8595 ctxt->cur = in;
8596 XP_ERRORNULL(XPATH_EXPR_ERROR);
8597 }
8598 ret = xmlStrndup(ctxt->cur, count);
8599 if (ret == NULL)
8600 xmlXPathPErrMemory(ctxt);
8601 ctxt->cur = in;
8602 return(ret);
8603 }
8604 }
8605 return(xmlXPathParseNameComplex(ctxt, 1));
8606 }
8607
8608 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)8609 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8610 xmlChar *ret;
8611 xmlChar buf[XML_MAX_NAMELEN + 5];
8612 int len = 0, l;
8613 int c;
8614
8615 /*
8616 * Handler for more complex cases
8617 */
8618 c = CUR_CHAR(l);
8619 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8620 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8621 (c == '*') || /* accelerators */
8622 (!IS_LETTER(c) && (c != '_') &&
8623 ((!qualified) || (c != ':')))) {
8624 return(NULL);
8625 }
8626
8627 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8628 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8629 (c == '.') || (c == '-') ||
8630 (c == '_') || ((qualified) && (c == ':')) ||
8631 (IS_COMBINING(c)) ||
8632 (IS_EXTENDER(c)))) {
8633 COPY_BUF(buf,len,c);
8634 NEXTL(l);
8635 c = CUR_CHAR(l);
8636 if (len >= XML_MAX_NAMELEN) {
8637 /*
8638 * Okay someone managed to make a huge name, so he's ready to pay
8639 * for the processing speed.
8640 */
8641 xmlChar *buffer;
8642 int max = len * 2;
8643
8644 if (len > XML_MAX_NAME_LENGTH) {
8645 XP_ERRORNULL(XPATH_EXPR_ERROR);
8646 }
8647 buffer = xmlMalloc(max);
8648 if (buffer == NULL) {
8649 xmlXPathPErrMemory(ctxt);
8650 return(NULL);
8651 }
8652 memcpy(buffer, buf, len);
8653 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8654 (c == '.') || (c == '-') ||
8655 (c == '_') || ((qualified) && (c == ':')) ||
8656 (IS_COMBINING(c)) ||
8657 (IS_EXTENDER(c))) {
8658 if (len + 10 > max) {
8659 xmlChar *tmp;
8660 if (max > XML_MAX_NAME_LENGTH) {
8661 xmlFree(buffer);
8662 XP_ERRORNULL(XPATH_EXPR_ERROR);
8663 }
8664 max *= 2;
8665 tmp = (xmlChar *) xmlRealloc(buffer, max);
8666 if (tmp == NULL) {
8667 xmlFree(buffer);
8668 xmlXPathPErrMemory(ctxt);
8669 return(NULL);
8670 }
8671 buffer = tmp;
8672 }
8673 COPY_BUF(buffer,len,c);
8674 NEXTL(l);
8675 c = CUR_CHAR(l);
8676 }
8677 buffer[len] = 0;
8678 return(buffer);
8679 }
8680 }
8681 if (len == 0)
8682 return(NULL);
8683 ret = xmlStrndup(buf, len);
8684 if (ret == NULL)
8685 xmlXPathPErrMemory(ctxt);
8686 return(ret);
8687 }
8688
8689 #define MAX_FRAC 20
8690
8691 /**
8692 * xmlXPathStringEvalNumber:
8693 * @str: A string to scan
8694 *
8695 * [30a] Float ::= Number ('e' Digits?)?
8696 *
8697 * [30] Number ::= Digits ('.' Digits?)?
8698 * | '.' Digits
8699 * [31] Digits ::= [0-9]+
8700 *
8701 * Compile a Number in the string
8702 * In complement of the Number expression, this function also handles
8703 * negative values : '-' Number.
8704 *
8705 * Returns the double value.
8706 */
8707 double
xmlXPathStringEvalNumber(const xmlChar * str)8708 xmlXPathStringEvalNumber(const xmlChar *str) {
8709 const xmlChar *cur = str;
8710 double ret;
8711 int ok = 0;
8712 int isneg = 0;
8713 int exponent = 0;
8714 int is_exponent_negative = 0;
8715 #ifdef __GNUC__
8716 unsigned long tmp = 0;
8717 double temp;
8718 #endif
8719 if (cur == NULL) return(0);
8720 while (IS_BLANK_CH(*cur)) cur++;
8721 if (*cur == '-') {
8722 isneg = 1;
8723 cur++;
8724 }
8725 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8726 return(xmlXPathNAN);
8727 }
8728
8729 #ifdef __GNUC__
8730 /*
8731 * tmp/temp is a workaround against a gcc compiler bug
8732 * http://veillard.com/gcc.bug
8733 */
8734 ret = 0;
8735 while ((*cur >= '0') && (*cur <= '9')) {
8736 ret = ret * 10;
8737 tmp = (*cur - '0');
8738 ok = 1;
8739 cur++;
8740 temp = (double) tmp;
8741 ret = ret + temp;
8742 }
8743 #else
8744 ret = 0;
8745 while ((*cur >= '0') && (*cur <= '9')) {
8746 ret = ret * 10 + (*cur - '0');
8747 ok = 1;
8748 cur++;
8749 }
8750 #endif
8751
8752 if (*cur == '.') {
8753 int v, frac = 0, max;
8754 double fraction = 0;
8755
8756 cur++;
8757 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8758 return(xmlXPathNAN);
8759 }
8760 while (*cur == '0') {
8761 frac = frac + 1;
8762 cur++;
8763 }
8764 max = frac + MAX_FRAC;
8765 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8766 v = (*cur - '0');
8767 fraction = fraction * 10 + v;
8768 frac = frac + 1;
8769 cur++;
8770 }
8771 fraction /= pow(10.0, frac);
8772 ret = ret + fraction;
8773 while ((*cur >= '0') && (*cur <= '9'))
8774 cur++;
8775 }
8776 if ((*cur == 'e') || (*cur == 'E')) {
8777 cur++;
8778 if (*cur == '-') {
8779 is_exponent_negative = 1;
8780 cur++;
8781 } else if (*cur == '+') {
8782 cur++;
8783 }
8784 while ((*cur >= '0') && (*cur <= '9')) {
8785 if (exponent < 1000000)
8786 exponent = exponent * 10 + (*cur - '0');
8787 cur++;
8788 }
8789 }
8790 while (IS_BLANK_CH(*cur)) cur++;
8791 if (*cur != 0) return(xmlXPathNAN);
8792 if (isneg) ret = -ret;
8793 if (is_exponent_negative) exponent = -exponent;
8794 ret *= pow(10.0, (double)exponent);
8795 return(ret);
8796 }
8797
8798 /**
8799 * xmlXPathCompNumber:
8800 * @ctxt: the XPath Parser context
8801 *
8802 * [30] Number ::= Digits ('.' Digits?)?
8803 * | '.' Digits
8804 * [31] Digits ::= [0-9]+
8805 *
8806 * Compile a Number, then push it on the stack
8807 *
8808 */
8809 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)8810 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8811 {
8812 double ret = 0.0;
8813 int ok = 0;
8814 int exponent = 0;
8815 int is_exponent_negative = 0;
8816 xmlXPathObjectPtr num;
8817 #ifdef __GNUC__
8818 unsigned long tmp = 0;
8819 double temp;
8820 #endif
8821
8822 CHECK_ERROR;
8823 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8824 XP_ERROR(XPATH_NUMBER_ERROR);
8825 }
8826 #ifdef __GNUC__
8827 /*
8828 * tmp/temp is a workaround against a gcc compiler bug
8829 * http://veillard.com/gcc.bug
8830 */
8831 ret = 0;
8832 while ((CUR >= '0') && (CUR <= '9')) {
8833 ret = ret * 10;
8834 tmp = (CUR - '0');
8835 ok = 1;
8836 NEXT;
8837 temp = (double) tmp;
8838 ret = ret + temp;
8839 }
8840 #else
8841 ret = 0;
8842 while ((CUR >= '0') && (CUR <= '9')) {
8843 ret = ret * 10 + (CUR - '0');
8844 ok = 1;
8845 NEXT;
8846 }
8847 #endif
8848 if (CUR == '.') {
8849 int v, frac = 0, max;
8850 double fraction = 0;
8851
8852 NEXT;
8853 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8854 XP_ERROR(XPATH_NUMBER_ERROR);
8855 }
8856 while (CUR == '0') {
8857 frac = frac + 1;
8858 NEXT;
8859 }
8860 max = frac + MAX_FRAC;
8861 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8862 v = (CUR - '0');
8863 fraction = fraction * 10 + v;
8864 frac = frac + 1;
8865 NEXT;
8866 }
8867 fraction /= pow(10.0, frac);
8868 ret = ret + fraction;
8869 while ((CUR >= '0') && (CUR <= '9'))
8870 NEXT;
8871 }
8872 if ((CUR == 'e') || (CUR == 'E')) {
8873 NEXT;
8874 if (CUR == '-') {
8875 is_exponent_negative = 1;
8876 NEXT;
8877 } else if (CUR == '+') {
8878 NEXT;
8879 }
8880 while ((CUR >= '0') && (CUR <= '9')) {
8881 if (exponent < 1000000)
8882 exponent = exponent * 10 + (CUR - '0');
8883 NEXT;
8884 }
8885 if (is_exponent_negative)
8886 exponent = -exponent;
8887 ret *= pow(10.0, (double) exponent);
8888 }
8889 num = xmlXPathCacheNewFloat(ctxt, ret);
8890 if (num == NULL) {
8891 ctxt->error = XPATH_MEMORY_ERROR;
8892 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8893 NULL) == -1) {
8894 xmlXPathReleaseObject(ctxt->context, num);
8895 }
8896 }
8897
8898 /**
8899 * xmlXPathParseLiteral:
8900 * @ctxt: the XPath Parser context
8901 *
8902 * Parse a Literal
8903 *
8904 * [29] Literal ::= '"' [^"]* '"'
8905 * | "'" [^']* "'"
8906 *
8907 * Returns the value found or NULL in case of error
8908 */
8909 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)8910 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8911 const xmlChar *q;
8912 xmlChar *ret = NULL;
8913 int quote;
8914
8915 if (CUR == '"') {
8916 quote = '"';
8917 } else if (CUR == '\'') {
8918 quote = '\'';
8919 } else {
8920 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8921 }
8922
8923 NEXT;
8924 q = CUR_PTR;
8925 while (CUR != quote) {
8926 int ch;
8927 int len = 4;
8928
8929 if (CUR == 0)
8930 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8931 ch = xmlGetUTF8Char(CUR_PTR, &len);
8932 if ((ch < 0) || (IS_CHAR(ch) == 0))
8933 XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8934 CUR_PTR += len;
8935 }
8936 ret = xmlStrndup(q, CUR_PTR - q);
8937 if (ret == NULL)
8938 xmlXPathPErrMemory(ctxt);
8939 NEXT;
8940 return(ret);
8941 }
8942
8943 /**
8944 * xmlXPathCompLiteral:
8945 * @ctxt: the XPath Parser context
8946 *
8947 * Parse a Literal and push it on the stack.
8948 *
8949 * [29] Literal ::= '"' [^"]* '"'
8950 * | "'" [^']* "'"
8951 *
8952 * TODO: xmlXPathCompLiteral memory allocation could be improved.
8953 */
8954 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)8955 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8956 xmlChar *ret = NULL;
8957 xmlXPathObjectPtr lit;
8958
8959 ret = xmlXPathParseLiteral(ctxt);
8960 if (ret == NULL)
8961 return;
8962 lit = xmlXPathCacheNewString(ctxt, ret);
8963 if (lit == NULL) {
8964 ctxt->error = XPATH_MEMORY_ERROR;
8965 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8966 NULL) == -1) {
8967 xmlXPathReleaseObject(ctxt->context, lit);
8968 }
8969 xmlFree(ret);
8970 }
8971
8972 /**
8973 * xmlXPathCompVariableReference:
8974 * @ctxt: the XPath Parser context
8975 *
8976 * Parse a VariableReference, evaluate it and push it on the stack.
8977 *
8978 * The variable bindings consist of a mapping from variable names
8979 * to variable values. The value of a variable is an object, which can be
8980 * of any of the types that are possible for the value of an expression,
8981 * and may also be of additional types not specified here.
8982 *
8983 * Early evaluation is possible since:
8984 * The variable bindings [...] used to evaluate a subexpression are
8985 * always the same as those used to evaluate the containing expression.
8986 *
8987 * [36] VariableReference ::= '$' QName
8988 */
8989 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)8990 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8991 xmlChar *name;
8992 xmlChar *prefix;
8993
8994 SKIP_BLANKS;
8995 if (CUR != '$') {
8996 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8997 }
8998 NEXT;
8999 name = xmlXPathParseQName(ctxt, &prefix);
9000 if (name == NULL) {
9001 xmlFree(prefix);
9002 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9003 }
9004 ctxt->comp->last = -1;
9005 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9006 xmlFree(prefix);
9007 xmlFree(name);
9008 }
9009 SKIP_BLANKS;
9010 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9011 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9012 }
9013 }
9014
9015 /**
9016 * xmlXPathIsNodeType:
9017 * @name: a name string
9018 *
9019 * Is the name given a NodeType one.
9020 *
9021 * [38] NodeType ::= 'comment'
9022 * | 'text'
9023 * | 'processing-instruction'
9024 * | 'node'
9025 *
9026 * Returns 1 if true 0 otherwise
9027 */
9028 int
xmlXPathIsNodeType(const xmlChar * name)9029 xmlXPathIsNodeType(const xmlChar *name) {
9030 if (name == NULL)
9031 return(0);
9032
9033 if (xmlStrEqual(name, BAD_CAST "node"))
9034 return(1);
9035 if (xmlStrEqual(name, BAD_CAST "text"))
9036 return(1);
9037 if (xmlStrEqual(name, BAD_CAST "comment"))
9038 return(1);
9039 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9040 return(1);
9041 return(0);
9042 }
9043
9044 /**
9045 * xmlXPathCompFunctionCall:
9046 * @ctxt: the XPath Parser context
9047 *
9048 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9049 * [17] Argument ::= Expr
9050 *
9051 * Compile a function call, the evaluation of all arguments are
9052 * pushed on the stack
9053 */
9054 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)9055 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9056 xmlChar *name;
9057 xmlChar *prefix;
9058 int nbargs = 0;
9059 int sort = 1;
9060
9061 name = xmlXPathParseQName(ctxt, &prefix);
9062 if (name == NULL) {
9063 xmlFree(prefix);
9064 XP_ERROR(XPATH_EXPR_ERROR);
9065 }
9066 SKIP_BLANKS;
9067
9068 if (CUR != '(') {
9069 xmlFree(name);
9070 xmlFree(prefix);
9071 XP_ERROR(XPATH_EXPR_ERROR);
9072 }
9073 NEXT;
9074 SKIP_BLANKS;
9075
9076 /*
9077 * Optimization for count(): we don't need the node-set to be sorted.
9078 */
9079 if ((prefix == NULL) && (name[0] == 'c') &&
9080 xmlStrEqual(name, BAD_CAST "count"))
9081 {
9082 sort = 0;
9083 }
9084 ctxt->comp->last = -1;
9085 if (CUR != ')') {
9086 while (CUR != 0) {
9087 int op1 = ctxt->comp->last;
9088 ctxt->comp->last = -1;
9089 xmlXPathCompileExpr(ctxt, sort);
9090 if (ctxt->error != XPATH_EXPRESSION_OK) {
9091 xmlFree(name);
9092 xmlFree(prefix);
9093 return;
9094 }
9095 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9096 nbargs++;
9097 if (CUR == ')') break;
9098 if (CUR != ',') {
9099 xmlFree(name);
9100 xmlFree(prefix);
9101 XP_ERROR(XPATH_EXPR_ERROR);
9102 }
9103 NEXT;
9104 SKIP_BLANKS;
9105 }
9106 }
9107 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9108 xmlFree(prefix);
9109 xmlFree(name);
9110 }
9111 NEXT;
9112 SKIP_BLANKS;
9113 }
9114
9115 /**
9116 * xmlXPathCompPrimaryExpr:
9117 * @ctxt: the XPath Parser context
9118 *
9119 * [15] PrimaryExpr ::= VariableReference
9120 * | '(' Expr ')'
9121 * | Literal
9122 * | Number
9123 * | FunctionCall
9124 *
9125 * Compile a primary expression.
9126 */
9127 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)9128 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9129 SKIP_BLANKS;
9130 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9131 else if (CUR == '(') {
9132 NEXT;
9133 SKIP_BLANKS;
9134 xmlXPathCompileExpr(ctxt, 1);
9135 CHECK_ERROR;
9136 if (CUR != ')') {
9137 XP_ERROR(XPATH_EXPR_ERROR);
9138 }
9139 NEXT;
9140 SKIP_BLANKS;
9141 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9142 xmlXPathCompNumber(ctxt);
9143 } else if ((CUR == '\'') || (CUR == '"')) {
9144 xmlXPathCompLiteral(ctxt);
9145 } else {
9146 xmlXPathCompFunctionCall(ctxt);
9147 }
9148 SKIP_BLANKS;
9149 }
9150
9151 /**
9152 * xmlXPathCompFilterExpr:
9153 * @ctxt: the XPath Parser context
9154 *
9155 * [20] FilterExpr ::= PrimaryExpr
9156 * | FilterExpr Predicate
9157 *
9158 * Compile a filter expression.
9159 * Square brackets are used to filter expressions in the same way that
9160 * they are used in location paths. It is an error if the expression to
9161 * be filtered does not evaluate to a node-set. The context node list
9162 * used for evaluating the expression in square brackets is the node-set
9163 * to be filtered listed in document order.
9164 */
9165
9166 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)9167 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9168 xmlXPathCompPrimaryExpr(ctxt);
9169 CHECK_ERROR;
9170 SKIP_BLANKS;
9171
9172 while (CUR == '[') {
9173 xmlXPathCompPredicate(ctxt, 1);
9174 SKIP_BLANKS;
9175 }
9176
9177
9178 }
9179
9180 /**
9181 * xmlXPathScanName:
9182 * @ctxt: the XPath Parser context
9183 *
9184 * Trickery: parse an XML name but without consuming the input flow
9185 * Needed to avoid insanity in the parser state.
9186 *
9187 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9188 * CombiningChar | Extender
9189 *
9190 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9191 *
9192 * [6] Names ::= Name (S Name)*
9193 *
9194 * Returns the Name parsed or NULL
9195 */
9196
9197 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)9198 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9199 int l;
9200 int c;
9201 const xmlChar *cur;
9202 xmlChar *ret;
9203
9204 cur = ctxt->cur;
9205
9206 c = CUR_CHAR(l);
9207 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9208 (!IS_LETTER(c) && (c != '_') &&
9209 (c != ':'))) {
9210 return(NULL);
9211 }
9212
9213 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9214 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9215 (c == '.') || (c == '-') ||
9216 (c == '_') || (c == ':') ||
9217 (IS_COMBINING(c)) ||
9218 (IS_EXTENDER(c)))) {
9219 NEXTL(l);
9220 c = CUR_CHAR(l);
9221 }
9222 ret = xmlStrndup(cur, ctxt->cur - cur);
9223 if (ret == NULL)
9224 xmlXPathPErrMemory(ctxt);
9225 ctxt->cur = cur;
9226 return(ret);
9227 }
9228
9229 /**
9230 * xmlXPathCompPathExpr:
9231 * @ctxt: the XPath Parser context
9232 *
9233 * [19] PathExpr ::= LocationPath
9234 * | FilterExpr
9235 * | FilterExpr '/' RelativeLocationPath
9236 * | FilterExpr '//' RelativeLocationPath
9237 *
9238 * Compile a path expression.
9239 * The / operator and // operators combine an arbitrary expression
9240 * and a relative location path. It is an error if the expression
9241 * does not evaluate to a node-set.
9242 * The / operator does composition in the same way as when / is
9243 * used in a location path. As in location paths, // is short for
9244 * /descendant-or-self::node()/.
9245 */
9246
9247 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)9248 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9249 int lc = 1; /* Should we branch to LocationPath ? */
9250 xmlChar *name = NULL; /* we may have to preparse a name to find out */
9251
9252 SKIP_BLANKS;
9253 if ((CUR == '$') || (CUR == '(') ||
9254 (IS_ASCII_DIGIT(CUR)) ||
9255 (CUR == '\'') || (CUR == '"') ||
9256 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9257 lc = 0;
9258 } else if (CUR == '*') {
9259 /* relative or absolute location path */
9260 lc = 1;
9261 } else if (CUR == '/') {
9262 /* relative or absolute location path */
9263 lc = 1;
9264 } else if (CUR == '@') {
9265 /* relative abbreviated attribute location path */
9266 lc = 1;
9267 } else if (CUR == '.') {
9268 /* relative abbreviated attribute location path */
9269 lc = 1;
9270 } else {
9271 /*
9272 * Problem is finding if we have a name here whether it's:
9273 * - a nodetype
9274 * - a function call in which case it's followed by '('
9275 * - an axis in which case it's followed by ':'
9276 * - a element name
9277 * We do an a priori analysis here rather than having to
9278 * maintain parsed token content through the recursive function
9279 * calls. This looks uglier but makes the code easier to
9280 * read/write/debug.
9281 */
9282 SKIP_BLANKS;
9283 name = xmlXPathScanName(ctxt);
9284 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9285 lc = 1;
9286 xmlFree(name);
9287 } else if (name != NULL) {
9288 int len =xmlStrlen(name);
9289
9290
9291 while (NXT(len) != 0) {
9292 if (NXT(len) == '/') {
9293 /* element name */
9294 lc = 1;
9295 break;
9296 } else if (IS_BLANK_CH(NXT(len))) {
9297 /* ignore blanks */
9298 ;
9299 } else if (NXT(len) == ':') {
9300 lc = 1;
9301 break;
9302 } else if ((NXT(len) == '(')) {
9303 /* Node Type or Function */
9304 if (xmlXPathIsNodeType(name)) {
9305 lc = 1;
9306 } else {
9307 lc = 0;
9308 }
9309 break;
9310 } else if ((NXT(len) == '[')) {
9311 /* element name */
9312 lc = 1;
9313 break;
9314 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9315 (NXT(len) == '=')) {
9316 lc = 1;
9317 break;
9318 } else {
9319 lc = 1;
9320 break;
9321 }
9322 len++;
9323 }
9324 if (NXT(len) == 0) {
9325 /* element name */
9326 lc = 1;
9327 }
9328 xmlFree(name);
9329 } else {
9330 /* make sure all cases are covered explicitly */
9331 XP_ERROR(XPATH_EXPR_ERROR);
9332 }
9333 }
9334
9335 if (lc) {
9336 if (CUR == '/') {
9337 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9338 } else {
9339 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9340 }
9341 xmlXPathCompLocationPath(ctxt);
9342 } else {
9343 xmlXPathCompFilterExpr(ctxt);
9344 CHECK_ERROR;
9345 if ((CUR == '/') && (NXT(1) == '/')) {
9346 SKIP(2);
9347 SKIP_BLANKS;
9348
9349 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9350 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9351
9352 xmlXPathCompRelativeLocationPath(ctxt);
9353 } else if (CUR == '/') {
9354 xmlXPathCompRelativeLocationPath(ctxt);
9355 }
9356 }
9357 SKIP_BLANKS;
9358 }
9359
9360 /**
9361 * xmlXPathCompUnionExpr:
9362 * @ctxt: the XPath Parser context
9363 *
9364 * [18] UnionExpr ::= PathExpr
9365 * | UnionExpr '|' PathExpr
9366 *
9367 * Compile an union expression.
9368 */
9369
9370 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)9371 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9372 xmlXPathCompPathExpr(ctxt);
9373 CHECK_ERROR;
9374 SKIP_BLANKS;
9375 while (CUR == '|') {
9376 int op1 = ctxt->comp->last;
9377 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9378
9379 NEXT;
9380 SKIP_BLANKS;
9381 xmlXPathCompPathExpr(ctxt);
9382
9383 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9384
9385 SKIP_BLANKS;
9386 }
9387 }
9388
9389 /**
9390 * xmlXPathCompUnaryExpr:
9391 * @ctxt: the XPath Parser context
9392 *
9393 * [27] UnaryExpr ::= UnionExpr
9394 * | '-' UnaryExpr
9395 *
9396 * Compile an unary expression.
9397 */
9398
9399 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)9400 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9401 int minus = 0;
9402 int found = 0;
9403
9404 SKIP_BLANKS;
9405 while (CUR == '-') {
9406 minus = 1 - minus;
9407 found = 1;
9408 NEXT;
9409 SKIP_BLANKS;
9410 }
9411
9412 xmlXPathCompUnionExpr(ctxt);
9413 CHECK_ERROR;
9414 if (found) {
9415 if (minus)
9416 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9417 else
9418 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9419 }
9420 }
9421
9422 /**
9423 * xmlXPathCompMultiplicativeExpr:
9424 * @ctxt: the XPath Parser context
9425 *
9426 * [26] MultiplicativeExpr ::= UnaryExpr
9427 * | MultiplicativeExpr MultiplyOperator UnaryExpr
9428 * | MultiplicativeExpr 'div' UnaryExpr
9429 * | MultiplicativeExpr 'mod' UnaryExpr
9430 * [34] MultiplyOperator ::= '*'
9431 *
9432 * Compile an Additive expression.
9433 */
9434
9435 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)9436 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9437 xmlXPathCompUnaryExpr(ctxt);
9438 CHECK_ERROR;
9439 SKIP_BLANKS;
9440 while ((CUR == '*') ||
9441 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9442 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9443 int op = -1;
9444 int op1 = ctxt->comp->last;
9445
9446 if (CUR == '*') {
9447 op = 0;
9448 NEXT;
9449 } else if (CUR == 'd') {
9450 op = 1;
9451 SKIP(3);
9452 } else if (CUR == 'm') {
9453 op = 2;
9454 SKIP(3);
9455 }
9456 SKIP_BLANKS;
9457 xmlXPathCompUnaryExpr(ctxt);
9458 CHECK_ERROR;
9459 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9460 SKIP_BLANKS;
9461 }
9462 }
9463
9464 /**
9465 * xmlXPathCompAdditiveExpr:
9466 * @ctxt: the XPath Parser context
9467 *
9468 * [25] AdditiveExpr ::= MultiplicativeExpr
9469 * | AdditiveExpr '+' MultiplicativeExpr
9470 * | AdditiveExpr '-' MultiplicativeExpr
9471 *
9472 * Compile an Additive expression.
9473 */
9474
9475 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)9476 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9477
9478 xmlXPathCompMultiplicativeExpr(ctxt);
9479 CHECK_ERROR;
9480 SKIP_BLANKS;
9481 while ((CUR == '+') || (CUR == '-')) {
9482 int plus;
9483 int op1 = ctxt->comp->last;
9484
9485 if (CUR == '+') plus = 1;
9486 else plus = 0;
9487 NEXT;
9488 SKIP_BLANKS;
9489 xmlXPathCompMultiplicativeExpr(ctxt);
9490 CHECK_ERROR;
9491 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9492 SKIP_BLANKS;
9493 }
9494 }
9495
9496 /**
9497 * xmlXPathCompRelationalExpr:
9498 * @ctxt: the XPath Parser context
9499 *
9500 * [24] RelationalExpr ::= AdditiveExpr
9501 * | RelationalExpr '<' AdditiveExpr
9502 * | RelationalExpr '>' AdditiveExpr
9503 * | RelationalExpr '<=' AdditiveExpr
9504 * | RelationalExpr '>=' AdditiveExpr
9505 *
9506 * A <= B > C is allowed ? Answer from James, yes with
9507 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9508 * which is basically what got implemented.
9509 *
9510 * Compile a Relational expression, then push the result
9511 * on the stack
9512 */
9513
9514 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)9515 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9516 xmlXPathCompAdditiveExpr(ctxt);
9517 CHECK_ERROR;
9518 SKIP_BLANKS;
9519 while ((CUR == '<') || (CUR == '>')) {
9520 int inf, strict;
9521 int op1 = ctxt->comp->last;
9522
9523 if (CUR == '<') inf = 1;
9524 else inf = 0;
9525 if (NXT(1) == '=') strict = 0;
9526 else strict = 1;
9527 NEXT;
9528 if (!strict) NEXT;
9529 SKIP_BLANKS;
9530 xmlXPathCompAdditiveExpr(ctxt);
9531 CHECK_ERROR;
9532 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9533 SKIP_BLANKS;
9534 }
9535 }
9536
9537 /**
9538 * xmlXPathCompEqualityExpr:
9539 * @ctxt: the XPath Parser context
9540 *
9541 * [23] EqualityExpr ::= RelationalExpr
9542 * | EqualityExpr '=' RelationalExpr
9543 * | EqualityExpr '!=' RelationalExpr
9544 *
9545 * A != B != C is allowed ? Answer from James, yes with
9546 * (RelationalExpr = RelationalExpr) = RelationalExpr
9547 * (RelationalExpr != RelationalExpr) != RelationalExpr
9548 * which is basically what got implemented.
9549 *
9550 * Compile an Equality expression.
9551 *
9552 */
9553 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)9554 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9555 xmlXPathCompRelationalExpr(ctxt);
9556 CHECK_ERROR;
9557 SKIP_BLANKS;
9558 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9559 int eq;
9560 int op1 = ctxt->comp->last;
9561
9562 if (CUR == '=') eq = 1;
9563 else eq = 0;
9564 NEXT;
9565 if (!eq) NEXT;
9566 SKIP_BLANKS;
9567 xmlXPathCompRelationalExpr(ctxt);
9568 CHECK_ERROR;
9569 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9570 SKIP_BLANKS;
9571 }
9572 }
9573
9574 /**
9575 * xmlXPathCompAndExpr:
9576 * @ctxt: the XPath Parser context
9577 *
9578 * [22] AndExpr ::= EqualityExpr
9579 * | AndExpr 'and' EqualityExpr
9580 *
9581 * Compile an AND expression.
9582 *
9583 */
9584 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)9585 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9586 xmlXPathCompEqualityExpr(ctxt);
9587 CHECK_ERROR;
9588 SKIP_BLANKS;
9589 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9590 int op1 = ctxt->comp->last;
9591 SKIP(3);
9592 SKIP_BLANKS;
9593 xmlXPathCompEqualityExpr(ctxt);
9594 CHECK_ERROR;
9595 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9596 SKIP_BLANKS;
9597 }
9598 }
9599
9600 /**
9601 * xmlXPathCompileExpr:
9602 * @ctxt: the XPath Parser context
9603 *
9604 * [14] Expr ::= OrExpr
9605 * [21] OrExpr ::= AndExpr
9606 * | OrExpr 'or' AndExpr
9607 *
9608 * Parse and compile an expression
9609 */
9610 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)9611 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9612 xmlXPathContextPtr xpctxt = ctxt->context;
9613
9614 if (xpctxt != NULL) {
9615 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9616 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9617 /*
9618 * Parsing a single '(' pushes about 10 functions on the call stack
9619 * before recursing!
9620 */
9621 xpctxt->depth += 10;
9622 }
9623
9624 xmlXPathCompAndExpr(ctxt);
9625 CHECK_ERROR;
9626 SKIP_BLANKS;
9627 while ((CUR == 'o') && (NXT(1) == 'r')) {
9628 int op1 = ctxt->comp->last;
9629 SKIP(2);
9630 SKIP_BLANKS;
9631 xmlXPathCompAndExpr(ctxt);
9632 CHECK_ERROR;
9633 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9634 SKIP_BLANKS;
9635 }
9636 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9637 /* more ops could be optimized too */
9638 /*
9639 * This is the main place to eliminate sorting for
9640 * operations which don't require a sorted node-set.
9641 * E.g. count().
9642 */
9643 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9644 }
9645
9646 if (xpctxt != NULL)
9647 xpctxt->depth -= 10;
9648 }
9649
9650 /**
9651 * xmlXPathCompPredicate:
9652 * @ctxt: the XPath Parser context
9653 * @filter: act as a filter
9654 *
9655 * [8] Predicate ::= '[' PredicateExpr ']'
9656 * [9] PredicateExpr ::= Expr
9657 *
9658 * Compile a predicate expression
9659 */
9660 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)9661 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9662 int op1 = ctxt->comp->last;
9663
9664 SKIP_BLANKS;
9665 if (CUR != '[') {
9666 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9667 }
9668 NEXT;
9669 SKIP_BLANKS;
9670
9671 ctxt->comp->last = -1;
9672 /*
9673 * This call to xmlXPathCompileExpr() will deactivate sorting
9674 * of the predicate result.
9675 * TODO: Sorting is still activated for filters, since I'm not
9676 * sure if needed. Normally sorting should not be needed, since
9677 * a filter can only diminish the number of items in a sequence,
9678 * but won't change its order; so if the initial sequence is sorted,
9679 * subsequent sorting is not needed.
9680 */
9681 if (! filter)
9682 xmlXPathCompileExpr(ctxt, 0);
9683 else
9684 xmlXPathCompileExpr(ctxt, 1);
9685 CHECK_ERROR;
9686
9687 if (CUR != ']') {
9688 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9689 }
9690
9691 if (filter)
9692 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9693 else
9694 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9695
9696 NEXT;
9697 SKIP_BLANKS;
9698 }
9699
9700 /**
9701 * xmlXPathCompNodeTest:
9702 * @ctxt: the XPath Parser context
9703 * @test: pointer to a xmlXPathTestVal
9704 * @type: pointer to a xmlXPathTypeVal
9705 * @prefix: placeholder for a possible name prefix
9706 *
9707 * [7] NodeTest ::= NameTest
9708 * | NodeType '(' ')'
9709 * | 'processing-instruction' '(' Literal ')'
9710 *
9711 * [37] NameTest ::= '*'
9712 * | NCName ':' '*'
9713 * | QName
9714 * [38] NodeType ::= 'comment'
9715 * | 'text'
9716 * | 'processing-instruction'
9717 * | 'node'
9718 *
9719 * Returns the name found and updates @test, @type and @prefix appropriately
9720 */
9721 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)9722 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9723 xmlXPathTypeVal *type, xmlChar **prefix,
9724 xmlChar *name) {
9725 int blanks;
9726
9727 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9728 return(NULL);
9729 }
9730 *type = (xmlXPathTypeVal) 0;
9731 *test = (xmlXPathTestVal) 0;
9732 *prefix = NULL;
9733 SKIP_BLANKS;
9734
9735 if ((name == NULL) && (CUR == '*')) {
9736 /*
9737 * All elements
9738 */
9739 NEXT;
9740 *test = NODE_TEST_ALL;
9741 return(NULL);
9742 }
9743
9744 if (name == NULL)
9745 name = xmlXPathParseNCName(ctxt);
9746 if (name == NULL) {
9747 XP_ERRORNULL(XPATH_EXPR_ERROR);
9748 }
9749
9750 blanks = IS_BLANK_CH(CUR);
9751 SKIP_BLANKS;
9752 if (CUR == '(') {
9753 NEXT;
9754 /*
9755 * NodeType or PI search
9756 */
9757 if (xmlStrEqual(name, BAD_CAST "comment"))
9758 *type = NODE_TYPE_COMMENT;
9759 else if (xmlStrEqual(name, BAD_CAST "node"))
9760 *type = NODE_TYPE_NODE;
9761 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9762 *type = NODE_TYPE_PI;
9763 else if (xmlStrEqual(name, BAD_CAST "text"))
9764 *type = NODE_TYPE_TEXT;
9765 else {
9766 if (name != NULL)
9767 xmlFree(name);
9768 XP_ERRORNULL(XPATH_EXPR_ERROR);
9769 }
9770
9771 *test = NODE_TEST_TYPE;
9772
9773 SKIP_BLANKS;
9774 if (*type == NODE_TYPE_PI) {
9775 /*
9776 * Specific case: search a PI by name.
9777 */
9778 if (name != NULL)
9779 xmlFree(name);
9780 name = NULL;
9781 if (CUR != ')') {
9782 name = xmlXPathParseLiteral(ctxt);
9783 *test = NODE_TEST_PI;
9784 SKIP_BLANKS;
9785 }
9786 }
9787 if (CUR != ')') {
9788 if (name != NULL)
9789 xmlFree(name);
9790 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9791 }
9792 NEXT;
9793 return(name);
9794 }
9795 *test = NODE_TEST_NAME;
9796 if ((!blanks) && (CUR == ':')) {
9797 NEXT;
9798
9799 /*
9800 * Since currently the parser context don't have a
9801 * namespace list associated:
9802 * The namespace name for this prefix can be computed
9803 * only at evaluation time. The compilation is done
9804 * outside of any context.
9805 */
9806 *prefix = name;
9807
9808 if (CUR == '*') {
9809 /*
9810 * All elements
9811 */
9812 NEXT;
9813 *test = NODE_TEST_ALL;
9814 return(NULL);
9815 }
9816
9817 name = xmlXPathParseNCName(ctxt);
9818 if (name == NULL) {
9819 XP_ERRORNULL(XPATH_EXPR_ERROR);
9820 }
9821 }
9822 return(name);
9823 }
9824
9825 /**
9826 * xmlXPathIsAxisName:
9827 * @name: a preparsed name token
9828 *
9829 * [6] AxisName ::= 'ancestor'
9830 * | 'ancestor-or-self'
9831 * | 'attribute'
9832 * | 'child'
9833 * | 'descendant'
9834 * | 'descendant-or-self'
9835 * | 'following'
9836 * | 'following-sibling'
9837 * | 'namespace'
9838 * | 'parent'
9839 * | 'preceding'
9840 * | 'preceding-sibling'
9841 * | 'self'
9842 *
9843 * Returns the axis or 0
9844 */
9845 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)9846 xmlXPathIsAxisName(const xmlChar *name) {
9847 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9848 switch (name[0]) {
9849 case 'a':
9850 if (xmlStrEqual(name, BAD_CAST "ancestor"))
9851 ret = AXIS_ANCESTOR;
9852 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9853 ret = AXIS_ANCESTOR_OR_SELF;
9854 if (xmlStrEqual(name, BAD_CAST "attribute"))
9855 ret = AXIS_ATTRIBUTE;
9856 break;
9857 case 'c':
9858 if (xmlStrEqual(name, BAD_CAST "child"))
9859 ret = AXIS_CHILD;
9860 break;
9861 case 'd':
9862 if (xmlStrEqual(name, BAD_CAST "descendant"))
9863 ret = AXIS_DESCENDANT;
9864 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9865 ret = AXIS_DESCENDANT_OR_SELF;
9866 break;
9867 case 'f':
9868 if (xmlStrEqual(name, BAD_CAST "following"))
9869 ret = AXIS_FOLLOWING;
9870 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9871 ret = AXIS_FOLLOWING_SIBLING;
9872 break;
9873 case 'n':
9874 if (xmlStrEqual(name, BAD_CAST "namespace"))
9875 ret = AXIS_NAMESPACE;
9876 break;
9877 case 'p':
9878 if (xmlStrEqual(name, BAD_CAST "parent"))
9879 ret = AXIS_PARENT;
9880 if (xmlStrEqual(name, BAD_CAST "preceding"))
9881 ret = AXIS_PRECEDING;
9882 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9883 ret = AXIS_PRECEDING_SIBLING;
9884 break;
9885 case 's':
9886 if (xmlStrEqual(name, BAD_CAST "self"))
9887 ret = AXIS_SELF;
9888 break;
9889 }
9890 return(ret);
9891 }
9892
9893 /**
9894 * xmlXPathCompStep:
9895 * @ctxt: the XPath Parser context
9896 *
9897 * [4] Step ::= AxisSpecifier NodeTest Predicate*
9898 * | AbbreviatedStep
9899 *
9900 * [12] AbbreviatedStep ::= '.' | '..'
9901 *
9902 * [5] AxisSpecifier ::= AxisName '::'
9903 * | AbbreviatedAxisSpecifier
9904 *
9905 * [13] AbbreviatedAxisSpecifier ::= '@'?
9906 *
9907 * Modified for XPtr range support as:
9908 *
9909 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9910 * | AbbreviatedStep
9911 * | 'range-to' '(' Expr ')' Predicate*
9912 *
9913 * Compile one step in a Location Path
9914 * A location step of . is short for self::node(). This is
9915 * particularly useful in conjunction with //. For example, the
9916 * location path .//para is short for
9917 * self::node()/descendant-or-self::node()/child::para
9918 * and so will select all para descendant elements of the context
9919 * node.
9920 * Similarly, a location step of .. is short for parent::node().
9921 * For example, ../title is short for parent::node()/child::title
9922 * and so will select the title children of the parent of the context
9923 * node.
9924 */
9925 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)9926 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9927 SKIP_BLANKS;
9928 if ((CUR == '.') && (NXT(1) == '.')) {
9929 SKIP(2);
9930 SKIP_BLANKS;
9931 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9932 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9933 } else if (CUR == '.') {
9934 NEXT;
9935 SKIP_BLANKS;
9936 } else {
9937 xmlChar *name = NULL;
9938 xmlChar *prefix = NULL;
9939 xmlXPathTestVal test = (xmlXPathTestVal) 0;
9940 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9941 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9942 int op1;
9943
9944 if (CUR == '*') {
9945 axis = AXIS_CHILD;
9946 } else {
9947 if (name == NULL)
9948 name = xmlXPathParseNCName(ctxt);
9949 if (name != NULL) {
9950 axis = xmlXPathIsAxisName(name);
9951 if (axis != 0) {
9952 SKIP_BLANKS;
9953 if ((CUR == ':') && (NXT(1) == ':')) {
9954 SKIP(2);
9955 xmlFree(name);
9956 name = NULL;
9957 } else {
9958 /* an element name can conflict with an axis one :-\ */
9959 axis = AXIS_CHILD;
9960 }
9961 } else {
9962 axis = AXIS_CHILD;
9963 }
9964 } else if (CUR == '@') {
9965 NEXT;
9966 axis = AXIS_ATTRIBUTE;
9967 } else {
9968 axis = AXIS_CHILD;
9969 }
9970 }
9971
9972 if (ctxt->error != XPATH_EXPRESSION_OK) {
9973 xmlFree(name);
9974 return;
9975 }
9976
9977 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9978 if (test == 0)
9979 return;
9980
9981 if ((prefix != NULL) && (ctxt->context != NULL) &&
9982 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9983 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9984 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
9985 }
9986 }
9987
9988 op1 = ctxt->comp->last;
9989 ctxt->comp->last = -1;
9990
9991 SKIP_BLANKS;
9992 while (CUR == '[') {
9993 xmlXPathCompPredicate(ctxt, 0);
9994 }
9995
9996 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9997 test, type, (void *)prefix, (void *)name) == -1) {
9998 xmlFree(prefix);
9999 xmlFree(name);
10000 }
10001 }
10002 }
10003
10004 /**
10005 * xmlXPathCompRelativeLocationPath:
10006 * @ctxt: the XPath Parser context
10007 *
10008 * [3] RelativeLocationPath ::= Step
10009 * | RelativeLocationPath '/' Step
10010 * | AbbreviatedRelativeLocationPath
10011 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
10012 *
10013 * Compile a relative location path.
10014 */
10015 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)10016 xmlXPathCompRelativeLocationPath
10017 (xmlXPathParserContextPtr ctxt) {
10018 SKIP_BLANKS;
10019 if ((CUR == '/') && (NXT(1) == '/')) {
10020 SKIP(2);
10021 SKIP_BLANKS;
10022 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10023 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10024 } else if (CUR == '/') {
10025 NEXT;
10026 SKIP_BLANKS;
10027 }
10028 xmlXPathCompStep(ctxt);
10029 CHECK_ERROR;
10030 SKIP_BLANKS;
10031 while (CUR == '/') {
10032 if ((CUR == '/') && (NXT(1) == '/')) {
10033 SKIP(2);
10034 SKIP_BLANKS;
10035 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10036 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10037 xmlXPathCompStep(ctxt);
10038 } else if (CUR == '/') {
10039 NEXT;
10040 SKIP_BLANKS;
10041 xmlXPathCompStep(ctxt);
10042 }
10043 SKIP_BLANKS;
10044 }
10045 }
10046
10047 /**
10048 * xmlXPathCompLocationPath:
10049 * @ctxt: the XPath Parser context
10050 *
10051 * [1] LocationPath ::= RelativeLocationPath
10052 * | AbsoluteLocationPath
10053 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
10054 * | AbbreviatedAbsoluteLocationPath
10055 * [10] AbbreviatedAbsoluteLocationPath ::=
10056 * '//' RelativeLocationPath
10057 *
10058 * Compile a location path
10059 *
10060 * // is short for /descendant-or-self::node()/. For example,
10061 * //para is short for /descendant-or-self::node()/child::para and
10062 * so will select any para element in the document (even a para element
10063 * that is a document element will be selected by //para since the
10064 * document element node is a child of the root node); div//para is
10065 * short for div/descendant-or-self::node()/child::para and so will
10066 * select all para descendants of div children.
10067 */
10068 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)10069 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10070 SKIP_BLANKS;
10071 if (CUR != '/') {
10072 xmlXPathCompRelativeLocationPath(ctxt);
10073 } else {
10074 while (CUR == '/') {
10075 if ((CUR == '/') && (NXT(1) == '/')) {
10076 SKIP(2);
10077 SKIP_BLANKS;
10078 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10079 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10080 xmlXPathCompRelativeLocationPath(ctxt);
10081 } else if (CUR == '/') {
10082 NEXT;
10083 SKIP_BLANKS;
10084 if ((CUR != 0 ) &&
10085 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10086 (CUR == '@') || (CUR == '*')))
10087 xmlXPathCompRelativeLocationPath(ctxt);
10088 }
10089 CHECK_ERROR;
10090 }
10091 }
10092 }
10093
10094 /************************************************************************
10095 * *
10096 * XPath precompiled expression evaluation *
10097 * *
10098 ************************************************************************/
10099
10100 static int
10101 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10102
10103 /**
10104 * xmlXPathNodeSetFilter:
10105 * @ctxt: the XPath Parser context
10106 * @set: the node set to filter
10107 * @filterOpIndex: the index of the predicate/filter op
10108 * @minPos: minimum position in the filtered set (1-based)
10109 * @maxPos: maximum position in the filtered set (1-based)
10110 * @hasNsNodes: true if the node set may contain namespace nodes
10111 *
10112 * Filter a node set, keeping only nodes for which the predicate expression
10113 * matches. Afterwards, keep only nodes between minPos and maxPos in the
10114 * filtered result.
10115 */
10116 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)10117 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10118 xmlNodeSetPtr set,
10119 int filterOpIndex,
10120 int minPos, int maxPos,
10121 int hasNsNodes)
10122 {
10123 xmlXPathContextPtr xpctxt;
10124 xmlNodePtr oldnode;
10125 xmlDocPtr olddoc;
10126 xmlXPathStepOpPtr filterOp;
10127 int oldcs, oldpp;
10128 int i, j, pos;
10129
10130 if ((set == NULL) || (set->nodeNr == 0))
10131 return;
10132
10133 /*
10134 * Check if the node set contains a sufficient number of nodes for
10135 * the requested range.
10136 */
10137 if (set->nodeNr < minPos) {
10138 xmlXPathNodeSetClear(set, hasNsNodes);
10139 return;
10140 }
10141
10142 xpctxt = ctxt->context;
10143 oldnode = xpctxt->node;
10144 olddoc = xpctxt->doc;
10145 oldcs = xpctxt->contextSize;
10146 oldpp = xpctxt->proximityPosition;
10147 filterOp = &ctxt->comp->steps[filterOpIndex];
10148
10149 xpctxt->contextSize = set->nodeNr;
10150
10151 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10152 xmlNodePtr node = set->nodeTab[i];
10153 int res;
10154
10155 xpctxt->node = node;
10156 xpctxt->proximityPosition = i + 1;
10157
10158 /*
10159 * Also set the xpath document in case things like
10160 * key() are evaluated in the predicate.
10161 *
10162 * TODO: Get real doc for namespace nodes.
10163 */
10164 if ((node->type != XML_NAMESPACE_DECL) &&
10165 (node->doc != NULL))
10166 xpctxt->doc = node->doc;
10167
10168 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10169
10170 if (ctxt->error != XPATH_EXPRESSION_OK)
10171 break;
10172 if (res < 0) {
10173 /* Shouldn't happen */
10174 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10175 break;
10176 }
10177
10178 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10179 if (i != j) {
10180 set->nodeTab[j] = node;
10181 set->nodeTab[i] = NULL;
10182 }
10183
10184 j += 1;
10185 } else {
10186 /* Remove the entry from the initial node set. */
10187 set->nodeTab[i] = NULL;
10188 if (node->type == XML_NAMESPACE_DECL)
10189 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10190 }
10191
10192 if (res != 0) {
10193 if (pos == maxPos) {
10194 i += 1;
10195 break;
10196 }
10197
10198 pos += 1;
10199 }
10200 }
10201
10202 /* Free remaining nodes. */
10203 if (hasNsNodes) {
10204 for (; i < set->nodeNr; i++) {
10205 xmlNodePtr node = set->nodeTab[i];
10206 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10207 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10208 }
10209 }
10210
10211 set->nodeNr = j;
10212
10213 /* If too many elements were removed, shrink table to preserve memory. */
10214 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10215 (set->nodeNr < set->nodeMax / 2)) {
10216 xmlNodePtr *tmp;
10217 int nodeMax = set->nodeNr;
10218
10219 if (nodeMax < XML_NODESET_DEFAULT)
10220 nodeMax = XML_NODESET_DEFAULT;
10221 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10222 nodeMax * sizeof(xmlNodePtr));
10223 if (tmp == NULL) {
10224 xmlXPathPErrMemory(ctxt);
10225 } else {
10226 set->nodeTab = tmp;
10227 set->nodeMax = nodeMax;
10228 }
10229 }
10230
10231 xpctxt->node = oldnode;
10232 xpctxt->doc = olddoc;
10233 xpctxt->contextSize = oldcs;
10234 xpctxt->proximityPosition = oldpp;
10235 }
10236
10237 /**
10238 * xmlXPathCompOpEvalPredicate:
10239 * @ctxt: the XPath Parser context
10240 * @op: the predicate op
10241 * @set: the node set to filter
10242 * @minPos: minimum position in the filtered set (1-based)
10243 * @maxPos: maximum position in the filtered set (1-based)
10244 * @hasNsNodes: true if the node set may contain namespace nodes
10245 *
10246 * Filter a node set, keeping only nodes for which the sequence of predicate
10247 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10248 * in the filtered result.
10249 */
10250 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)10251 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10252 xmlXPathStepOpPtr op,
10253 xmlNodeSetPtr set,
10254 int minPos, int maxPos,
10255 int hasNsNodes)
10256 {
10257 if (op->ch1 != -1) {
10258 xmlXPathCompExprPtr comp = ctxt->comp;
10259 /*
10260 * Process inner predicates first.
10261 */
10262 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10263 XP_ERROR(XPATH_INVALID_OPERAND);
10264 }
10265 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10266 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10267 ctxt->context->depth += 1;
10268 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10269 1, set->nodeNr, hasNsNodes);
10270 ctxt->context->depth -= 1;
10271 CHECK_ERROR;
10272 }
10273
10274 if (op->ch2 != -1)
10275 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10276 }
10277
10278 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)10279 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10280 xmlXPathStepOpPtr op,
10281 int *maxPos)
10282 {
10283
10284 xmlXPathStepOpPtr exprOp;
10285
10286 /*
10287 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10288 */
10289
10290 /*
10291 * If not -1, then ch1 will point to:
10292 * 1) For predicates (XPATH_OP_PREDICATE):
10293 * - an inner predicate operator
10294 * 2) For filters (XPATH_OP_FILTER):
10295 * - an inner filter operator OR
10296 * - an expression selecting the node set.
10297 * E.g. "key('a', 'b')" or "(//foo | //bar)".
10298 */
10299 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10300 return(0);
10301
10302 if (op->ch2 != -1) {
10303 exprOp = &ctxt->comp->steps[op->ch2];
10304 } else
10305 return(0);
10306
10307 if ((exprOp != NULL) &&
10308 (exprOp->op == XPATH_OP_VALUE) &&
10309 (exprOp->value4 != NULL) &&
10310 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10311 {
10312 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10313
10314 /*
10315 * We have a "[n]" predicate here.
10316 * TODO: Unfortunately this simplistic test here is not
10317 * able to detect a position() predicate in compound
10318 * expressions like "[@attr = 'a" and position() = 1],
10319 * and even not the usage of position() in
10320 * "[position() = 1]"; thus - obviously - a position-range,
10321 * like it "[position() < 5]", is also not detected.
10322 * Maybe we could rewrite the AST to ease the optimization.
10323 */
10324
10325 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10326 *maxPos = (int) floatval;
10327 if (floatval == (double) *maxPos)
10328 return(1);
10329 }
10330 }
10331 return(0);
10332 }
10333
10334 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)10335 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10336 xmlXPathStepOpPtr op,
10337 xmlNodePtr * first, xmlNodePtr * last,
10338 int toBool)
10339 {
10340
10341 #define XP_TEST_HIT \
10342 if (hasAxisRange != 0) { \
10343 if (++pos == maxPos) { \
10344 if (addNode(seq, cur) < 0) \
10345 xmlXPathPErrMemory(ctxt); \
10346 goto axis_range_end; } \
10347 } else { \
10348 if (addNode(seq, cur) < 0) \
10349 xmlXPathPErrMemory(ctxt); \
10350 if (breakOnFirstHit) goto first_hit; }
10351
10352 #define XP_TEST_HIT_NS \
10353 if (hasAxisRange != 0) { \
10354 if (++pos == maxPos) { \
10355 hasNsNodes = 1; \
10356 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10357 xmlXPathPErrMemory(ctxt); \
10358 goto axis_range_end; } \
10359 } else { \
10360 hasNsNodes = 1; \
10361 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10362 xmlXPathPErrMemory(ctxt); \
10363 if (breakOnFirstHit) goto first_hit; }
10364
10365 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10366 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10367 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10368 const xmlChar *prefix = op->value4;
10369 const xmlChar *name = op->value5;
10370 const xmlChar *URI = NULL;
10371
10372 int total = 0, hasNsNodes = 0;
10373 /* The popped object holding the context nodes */
10374 xmlXPathObjectPtr obj;
10375 /* The set of context nodes for the node tests */
10376 xmlNodeSetPtr contextSeq;
10377 int contextIdx;
10378 xmlNodePtr contextNode;
10379 /* The final resulting node set wrt to all context nodes */
10380 xmlNodeSetPtr outSeq;
10381 /*
10382 * The temporary resulting node set wrt 1 context node.
10383 * Used to feed predicate evaluation.
10384 */
10385 xmlNodeSetPtr seq;
10386 xmlNodePtr cur;
10387 /* First predicate operator */
10388 xmlXPathStepOpPtr predOp;
10389 int maxPos; /* The requested position() (when a "[n]" predicate) */
10390 int hasPredicateRange, hasAxisRange, pos;
10391 int breakOnFirstHit;
10392
10393 xmlXPathTraversalFunction next = NULL;
10394 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10395 xmlXPathNodeSetMergeFunction mergeAndClear;
10396 xmlNodePtr oldContextNode;
10397 xmlXPathContextPtr xpctxt = ctxt->context;
10398
10399
10400 CHECK_TYPE0(XPATH_NODESET);
10401 obj = valuePop(ctxt);
10402 /*
10403 * Setup namespaces.
10404 */
10405 if (prefix != NULL) {
10406 URI = xmlXPathNsLookup(xpctxt, prefix);
10407 if (URI == NULL) {
10408 xmlXPathReleaseObject(xpctxt, obj);
10409 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10410 }
10411 }
10412 /*
10413 * Setup axis.
10414 *
10415 * MAYBE FUTURE TODO: merging optimizations:
10416 * - If the nodes to be traversed wrt to the initial nodes and
10417 * the current axis cannot overlap, then we could avoid searching
10418 * for duplicates during the merge.
10419 * But the question is how/when to evaluate if they cannot overlap.
10420 * Example: if we know that for two initial nodes, the one is
10421 * not in the ancestor-or-self axis of the other, then we could safely
10422 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10423 * the descendant-or-self axis.
10424 */
10425 mergeAndClear = xmlXPathNodeSetMergeAndClear;
10426 switch (axis) {
10427 case AXIS_ANCESTOR:
10428 first = NULL;
10429 next = xmlXPathNextAncestor;
10430 break;
10431 case AXIS_ANCESTOR_OR_SELF:
10432 first = NULL;
10433 next = xmlXPathNextAncestorOrSelf;
10434 break;
10435 case AXIS_ATTRIBUTE:
10436 first = NULL;
10437 last = NULL;
10438 next = xmlXPathNextAttribute;
10439 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10440 break;
10441 case AXIS_CHILD:
10442 last = NULL;
10443 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10444 (type == NODE_TYPE_NODE))
10445 {
10446 /*
10447 * Optimization if an element node type is 'element'.
10448 */
10449 next = xmlXPathNextChildElement;
10450 } else
10451 next = xmlXPathNextChild;
10452 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10453 break;
10454 case AXIS_DESCENDANT:
10455 last = NULL;
10456 next = xmlXPathNextDescendant;
10457 break;
10458 case AXIS_DESCENDANT_OR_SELF:
10459 last = NULL;
10460 next = xmlXPathNextDescendantOrSelf;
10461 break;
10462 case AXIS_FOLLOWING:
10463 last = NULL;
10464 next = xmlXPathNextFollowing;
10465 break;
10466 case AXIS_FOLLOWING_SIBLING:
10467 last = NULL;
10468 next = xmlXPathNextFollowingSibling;
10469 break;
10470 case AXIS_NAMESPACE:
10471 first = NULL;
10472 last = NULL;
10473 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10474 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10475 break;
10476 case AXIS_PARENT:
10477 first = NULL;
10478 next = xmlXPathNextParent;
10479 break;
10480 case AXIS_PRECEDING:
10481 first = NULL;
10482 next = xmlXPathNextPrecedingInternal;
10483 break;
10484 case AXIS_PRECEDING_SIBLING:
10485 first = NULL;
10486 next = xmlXPathNextPrecedingSibling;
10487 break;
10488 case AXIS_SELF:
10489 first = NULL;
10490 last = NULL;
10491 next = xmlXPathNextSelf;
10492 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10493 break;
10494 }
10495
10496 if (next == NULL) {
10497 xmlXPathReleaseObject(xpctxt, obj);
10498 return(0);
10499 }
10500 contextSeq = obj->nodesetval;
10501 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10502 valuePush(ctxt, obj);
10503 return(0);
10504 }
10505 /*
10506 * Predicate optimization ---------------------------------------------
10507 * If this step has a last predicate, which contains a position(),
10508 * then we'll optimize (although not exactly "position()", but only
10509 * the short-hand form, i.e., "[n]".
10510 *
10511 * Example - expression "/foo[parent::bar][1]":
10512 *
10513 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
10514 * ROOT -- op->ch1
10515 * PREDICATE -- op->ch2 (predOp)
10516 * PREDICATE -- predOp->ch1 = [parent::bar]
10517 * SORT
10518 * COLLECT 'parent' 'name' 'node' bar
10519 * NODE
10520 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
10521 *
10522 */
10523 maxPos = 0;
10524 predOp = NULL;
10525 hasPredicateRange = 0;
10526 hasAxisRange = 0;
10527 if (op->ch2 != -1) {
10528 /*
10529 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
10530 */
10531 predOp = &ctxt->comp->steps[op->ch2];
10532 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
10533 if (predOp->ch1 != -1) {
10534 /*
10535 * Use the next inner predicate operator.
10536 */
10537 predOp = &ctxt->comp->steps[predOp->ch1];
10538 hasPredicateRange = 1;
10539 } else {
10540 /*
10541 * There's no other predicate than the [n] predicate.
10542 */
10543 predOp = NULL;
10544 hasAxisRange = 1;
10545 }
10546 }
10547 }
10548 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
10549 /*
10550 * Axis traversal -----------------------------------------------------
10551 */
10552 /*
10553 * 2.3 Node Tests
10554 * - For the attribute axis, the principal node type is attribute.
10555 * - For the namespace axis, the principal node type is namespace.
10556 * - For other axes, the principal node type is element.
10557 *
10558 * A node test * is true for any node of the
10559 * principal node type. For example, child::* will
10560 * select all element children of the context node
10561 */
10562 oldContextNode = xpctxt->node;
10563 addNode = xmlXPathNodeSetAddUnique;
10564 outSeq = NULL;
10565 seq = NULL;
10566 contextNode = NULL;
10567 contextIdx = 0;
10568
10569
10570 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10571 (ctxt->error == XPATH_EXPRESSION_OK)) {
10572 xpctxt->node = contextSeq->nodeTab[contextIdx++];
10573
10574 if (seq == NULL) {
10575 seq = xmlXPathNodeSetCreate(NULL);
10576 if (seq == NULL) {
10577 xmlXPathPErrMemory(ctxt);
10578 total = 0;
10579 goto error;
10580 }
10581 }
10582 /*
10583 * Traverse the axis and test the nodes.
10584 */
10585 pos = 0;
10586 cur = NULL;
10587 hasNsNodes = 0;
10588 do {
10589 if (OP_LIMIT_EXCEEDED(ctxt, 1))
10590 goto error;
10591
10592 cur = next(ctxt, cur);
10593 if (cur == NULL)
10594 break;
10595
10596 /*
10597 * QUESTION TODO: What does the "first" and "last" stuff do?
10598 */
10599 if ((first != NULL) && (*first != NULL)) {
10600 if (*first == cur)
10601 break;
10602 if (((total % 256) == 0) &&
10603 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10604 (xmlXPathCmpNodesExt(*first, cur) >= 0))
10605 #else
10606 (xmlXPathCmpNodes(*first, cur) >= 0))
10607 #endif
10608 {
10609 break;
10610 }
10611 }
10612 if ((last != NULL) && (*last != NULL)) {
10613 if (*last == cur)
10614 break;
10615 if (((total % 256) == 0) &&
10616 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10617 (xmlXPathCmpNodesExt(cur, *last) >= 0))
10618 #else
10619 (xmlXPathCmpNodes(cur, *last) >= 0))
10620 #endif
10621 {
10622 break;
10623 }
10624 }
10625
10626 total++;
10627
10628 switch (test) {
10629 case NODE_TEST_NONE:
10630 total = 0;
10631 goto error;
10632 case NODE_TEST_TYPE:
10633 if (type == NODE_TYPE_NODE) {
10634 switch (cur->type) {
10635 case XML_DOCUMENT_NODE:
10636 case XML_HTML_DOCUMENT_NODE:
10637 case XML_ELEMENT_NODE:
10638 case XML_ATTRIBUTE_NODE:
10639 case XML_PI_NODE:
10640 case XML_COMMENT_NODE:
10641 case XML_CDATA_SECTION_NODE:
10642 case XML_TEXT_NODE:
10643 XP_TEST_HIT
10644 break;
10645 case XML_NAMESPACE_DECL: {
10646 if (axis == AXIS_NAMESPACE) {
10647 XP_TEST_HIT_NS
10648 } else {
10649 hasNsNodes = 1;
10650 XP_TEST_HIT
10651 }
10652 break;
10653 }
10654 default:
10655 break;
10656 }
10657 } else if (cur->type == (xmlElementType) type) {
10658 if (cur->type == XML_NAMESPACE_DECL)
10659 XP_TEST_HIT_NS
10660 else
10661 XP_TEST_HIT
10662 } else if ((type == NODE_TYPE_TEXT) &&
10663 (cur->type == XML_CDATA_SECTION_NODE))
10664 {
10665 XP_TEST_HIT
10666 }
10667 break;
10668 case NODE_TEST_PI:
10669 if ((cur->type == XML_PI_NODE) &&
10670 ((name == NULL) || xmlStrEqual(name, cur->name)))
10671 {
10672 XP_TEST_HIT
10673 }
10674 break;
10675 case NODE_TEST_ALL:
10676 if (axis == AXIS_ATTRIBUTE) {
10677 if (cur->type == XML_ATTRIBUTE_NODE)
10678 {
10679 if (prefix == NULL)
10680 {
10681 XP_TEST_HIT
10682 } else if ((cur->ns != NULL) &&
10683 (xmlStrEqual(URI, cur->ns->href)))
10684 {
10685 XP_TEST_HIT
10686 }
10687 }
10688 } else if (axis == AXIS_NAMESPACE) {
10689 if (cur->type == XML_NAMESPACE_DECL)
10690 {
10691 XP_TEST_HIT_NS
10692 }
10693 } else {
10694 if (cur->type == XML_ELEMENT_NODE) {
10695 if (prefix == NULL)
10696 {
10697 XP_TEST_HIT
10698
10699 } else if ((cur->ns != NULL) &&
10700 (xmlStrEqual(URI, cur->ns->href)))
10701 {
10702 XP_TEST_HIT
10703 }
10704 }
10705 }
10706 break;
10707 case NODE_TEST_NS:{
10708 /* TODO */
10709 break;
10710 }
10711 case NODE_TEST_NAME:
10712 if (axis == AXIS_ATTRIBUTE) {
10713 if (cur->type != XML_ATTRIBUTE_NODE)
10714 break;
10715 } else if (axis == AXIS_NAMESPACE) {
10716 if (cur->type != XML_NAMESPACE_DECL)
10717 break;
10718 } else {
10719 if (cur->type != XML_ELEMENT_NODE)
10720 break;
10721 }
10722 switch (cur->type) {
10723 case XML_ELEMENT_NODE:
10724 if (xmlStrEqual(name, cur->name)) {
10725 if (prefix == NULL) {
10726 if (cur->ns == NULL)
10727 {
10728 XP_TEST_HIT
10729 }
10730 } else {
10731 if ((cur->ns != NULL) &&
10732 (xmlStrEqual(URI, cur->ns->href)))
10733 {
10734 XP_TEST_HIT
10735 }
10736 }
10737 }
10738 break;
10739 case XML_ATTRIBUTE_NODE:{
10740 xmlAttrPtr attr = (xmlAttrPtr) cur;
10741
10742 if (xmlStrEqual(name, attr->name)) {
10743 if (prefix == NULL) {
10744 if ((attr->ns == NULL) ||
10745 (attr->ns->prefix == NULL))
10746 {
10747 XP_TEST_HIT
10748 }
10749 } else {
10750 if ((attr->ns != NULL) &&
10751 (xmlStrEqual(URI,
10752 attr->ns->href)))
10753 {
10754 XP_TEST_HIT
10755 }
10756 }
10757 }
10758 break;
10759 }
10760 case XML_NAMESPACE_DECL:
10761 if (cur->type == XML_NAMESPACE_DECL) {
10762 xmlNsPtr ns = (xmlNsPtr) cur;
10763
10764 if ((ns->prefix != NULL) && (name != NULL)
10765 && (xmlStrEqual(ns->prefix, name)))
10766 {
10767 XP_TEST_HIT_NS
10768 }
10769 }
10770 break;
10771 default:
10772 break;
10773 }
10774 break;
10775 } /* switch(test) */
10776 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10777
10778 goto apply_predicates;
10779
10780 axis_range_end: /* ----------------------------------------------------- */
10781 /*
10782 * We have a "/foo[n]", and position() = n was reached.
10783 * Note that we can have as well "/foo/::parent::foo[1]", so
10784 * a duplicate-aware merge is still needed.
10785 * Merge with the result.
10786 */
10787 if (outSeq == NULL) {
10788 outSeq = seq;
10789 seq = NULL;
10790 } else {
10791 outSeq = mergeAndClear(outSeq, seq);
10792 if (outSeq == NULL)
10793 xmlXPathPErrMemory(ctxt);
10794 }
10795 /*
10796 * Break if only a true/false result was requested.
10797 */
10798 if (toBool)
10799 break;
10800 continue;
10801
10802 first_hit: /* ---------------------------------------------------------- */
10803 /*
10804 * Break if only a true/false result was requested and
10805 * no predicates existed and a node test succeeded.
10806 */
10807 if (outSeq == NULL) {
10808 outSeq = seq;
10809 seq = NULL;
10810 } else {
10811 outSeq = mergeAndClear(outSeq, seq);
10812 if (outSeq == NULL)
10813 xmlXPathPErrMemory(ctxt);
10814 }
10815 break;
10816
10817 apply_predicates: /* --------------------------------------------------- */
10818 if (ctxt->error != XPATH_EXPRESSION_OK)
10819 goto error;
10820
10821 /*
10822 * Apply predicates.
10823 */
10824 if ((predOp != NULL) && (seq->nodeNr > 0)) {
10825 /*
10826 * E.g. when we have a "/foo[some expression][n]".
10827 */
10828 /*
10829 * QUESTION TODO: The old predicate evaluation took into
10830 * account location-sets.
10831 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
10832 * Do we expect such a set here?
10833 * All what I learned now from the evaluation semantics
10834 * does not indicate that a location-set will be processed
10835 * here, so this looks OK.
10836 */
10837 /*
10838 * Iterate over all predicates, starting with the outermost
10839 * predicate.
10840 * TODO: Problem: we cannot execute the inner predicates first
10841 * since we cannot go back *up* the operator tree!
10842 * Options we have:
10843 * 1) Use of recursive functions (like is it currently done
10844 * via xmlXPathCompOpEval())
10845 * 2) Add a predicate evaluation information stack to the
10846 * context struct
10847 * 3) Change the way the operators are linked; we need a
10848 * "parent" field on xmlXPathStepOp
10849 *
10850 * For the moment, I'll try to solve this with a recursive
10851 * function: xmlXPathCompOpEvalPredicate().
10852 */
10853 if (hasPredicateRange != 0)
10854 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10855 hasNsNodes);
10856 else
10857 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10858 hasNsNodes);
10859
10860 if (ctxt->error != XPATH_EXPRESSION_OK) {
10861 total = 0;
10862 goto error;
10863 }
10864 }
10865
10866 if (seq->nodeNr > 0) {
10867 /*
10868 * Add to result set.
10869 */
10870 if (outSeq == NULL) {
10871 outSeq = seq;
10872 seq = NULL;
10873 } else {
10874 outSeq = mergeAndClear(outSeq, seq);
10875 if (outSeq == NULL)
10876 xmlXPathPErrMemory(ctxt);
10877 }
10878
10879 if (toBool)
10880 break;
10881 }
10882 }
10883
10884 error:
10885 if ((obj->boolval) && (obj->user != NULL)) {
10886 /*
10887 * QUESTION TODO: What does this do and why?
10888 * TODO: Do we have to do this also for the "error"
10889 * cleanup further down?
10890 */
10891 ctxt->value->boolval = 1;
10892 ctxt->value->user = obj->user;
10893 obj->user = NULL;
10894 obj->boolval = 0;
10895 }
10896 xmlXPathReleaseObject(xpctxt, obj);
10897
10898 /*
10899 * Ensure we return at least an empty set.
10900 */
10901 if (outSeq == NULL) {
10902 if ((seq != NULL) && (seq->nodeNr == 0)) {
10903 outSeq = seq;
10904 } else {
10905 outSeq = xmlXPathNodeSetCreate(NULL);
10906 if (outSeq == NULL)
10907 xmlXPathPErrMemory(ctxt);
10908 }
10909 }
10910 if ((seq != NULL) && (seq != outSeq)) {
10911 xmlXPathFreeNodeSet(seq);
10912 }
10913 /*
10914 * Hand over the result. Better to push the set also in
10915 * case of errors.
10916 */
10917 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10918 /*
10919 * Reset the context node.
10920 */
10921 xpctxt->node = oldContextNode;
10922 /*
10923 * When traversing the namespace axis in "toBool" mode, it's
10924 * possible that tmpNsList wasn't freed.
10925 */
10926 if (xpctxt->tmpNsList != NULL) {
10927 xmlFree(xpctxt->tmpNsList);
10928 xpctxt->tmpNsList = NULL;
10929 }
10930
10931 return(total);
10932 }
10933
10934 static int
10935 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10936 xmlXPathStepOpPtr op, xmlNodePtr * first);
10937
10938 /**
10939 * xmlXPathCompOpEvalFirst:
10940 * @ctxt: the XPath parser context with the compiled expression
10941 * @op: an XPath compiled operation
10942 * @first: the first elem found so far
10943 *
10944 * Evaluate the Precompiled XPath operation searching only the first
10945 * element in document order
10946 *
10947 * Returns the number of examined objects.
10948 */
10949 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)10950 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10951 xmlXPathStepOpPtr op, xmlNodePtr * first)
10952 {
10953 int total = 0, cur;
10954 xmlXPathCompExprPtr comp;
10955 xmlXPathObjectPtr arg1, arg2;
10956
10957 CHECK_ERROR0;
10958 if (OP_LIMIT_EXCEEDED(ctxt, 1))
10959 return(0);
10960 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10961 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10962 ctxt->context->depth += 1;
10963 comp = ctxt->comp;
10964 switch (op->op) {
10965 case XPATH_OP_END:
10966 break;
10967 case XPATH_OP_UNION:
10968 total =
10969 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10970 first);
10971 CHECK_ERROR0;
10972 if ((ctxt->value != NULL)
10973 && (ctxt->value->type == XPATH_NODESET)
10974 && (ctxt->value->nodesetval != NULL)
10975 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10976 /*
10977 * limit tree traversing to first node in the result
10978 */
10979 /*
10980 * OPTIMIZE TODO: This implicitly sorts
10981 * the result, even if not needed. E.g. if the argument
10982 * of the count() function, no sorting is needed.
10983 * OPTIMIZE TODO: How do we know if the node-list wasn't
10984 * already sorted?
10985 */
10986 if (ctxt->value->nodesetval->nodeNr > 1)
10987 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10988 *first = ctxt->value->nodesetval->nodeTab[0];
10989 }
10990 cur =
10991 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10992 first);
10993 CHECK_ERROR0;
10994
10995 arg2 = valuePop(ctxt);
10996 arg1 = valuePop(ctxt);
10997 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10998 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10999 xmlXPathReleaseObject(ctxt->context, arg1);
11000 xmlXPathReleaseObject(ctxt->context, arg2);
11001 XP_ERROR0(XPATH_INVALID_TYPE);
11002 }
11003 if ((ctxt->context->opLimit != 0) &&
11004 (((arg1->nodesetval != NULL) &&
11005 (xmlXPathCheckOpLimit(ctxt,
11006 arg1->nodesetval->nodeNr) < 0)) ||
11007 ((arg2->nodesetval != NULL) &&
11008 (xmlXPathCheckOpLimit(ctxt,
11009 arg2->nodesetval->nodeNr) < 0)))) {
11010 xmlXPathReleaseObject(ctxt->context, arg1);
11011 xmlXPathReleaseObject(ctxt->context, arg2);
11012 break;
11013 }
11014
11015 if ((arg2->nodesetval != NULL) &&
11016 (arg2->nodesetval->nodeNr != 0)) {
11017 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11018 arg2->nodesetval);
11019 if (arg1->nodesetval == NULL)
11020 xmlXPathPErrMemory(ctxt);
11021 }
11022 valuePush(ctxt, arg1);
11023 xmlXPathReleaseObject(ctxt->context, arg2);
11024 total += cur;
11025 break;
11026 case XPATH_OP_ROOT:
11027 xmlXPathRoot(ctxt);
11028 break;
11029 case XPATH_OP_NODE:
11030 if (op->ch1 != -1)
11031 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11032 CHECK_ERROR0;
11033 if (op->ch2 != -1)
11034 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11035 CHECK_ERROR0;
11036 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11037 ctxt->context->node));
11038 break;
11039 case XPATH_OP_COLLECT:{
11040 if (op->ch1 == -1)
11041 break;
11042
11043 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11044 CHECK_ERROR0;
11045
11046 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11047 break;
11048 }
11049 case XPATH_OP_VALUE:
11050 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11051 break;
11052 case XPATH_OP_SORT:
11053 if (op->ch1 != -1)
11054 total +=
11055 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11056 first);
11057 CHECK_ERROR0;
11058 if ((ctxt->value != NULL)
11059 && (ctxt->value->type == XPATH_NODESET)
11060 && (ctxt->value->nodesetval != NULL)
11061 && (ctxt->value->nodesetval->nodeNr > 1))
11062 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11063 break;
11064 #ifdef XP_OPTIMIZED_FILTER_FIRST
11065 case XPATH_OP_FILTER:
11066 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11067 break;
11068 #endif
11069 default:
11070 total += xmlXPathCompOpEval(ctxt, op);
11071 break;
11072 }
11073
11074 ctxt->context->depth -= 1;
11075 return(total);
11076 }
11077
11078 /**
11079 * xmlXPathCompOpEvalLast:
11080 * @ctxt: the XPath parser context with the compiled expression
11081 * @op: an XPath compiled operation
11082 * @last: the last elem found so far
11083 *
11084 * Evaluate the Precompiled XPath operation searching only the last
11085 * element in document order
11086 *
11087 * Returns the number of nodes traversed
11088 */
11089 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)11090 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11091 xmlNodePtr * last)
11092 {
11093 int total = 0, cur;
11094 xmlXPathCompExprPtr comp;
11095 xmlXPathObjectPtr arg1, arg2;
11096
11097 CHECK_ERROR0;
11098 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11099 return(0);
11100 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11101 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11102 ctxt->context->depth += 1;
11103 comp = ctxt->comp;
11104 switch (op->op) {
11105 case XPATH_OP_END:
11106 break;
11107 case XPATH_OP_UNION:
11108 total =
11109 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11110 CHECK_ERROR0;
11111 if ((ctxt->value != NULL)
11112 && (ctxt->value->type == XPATH_NODESET)
11113 && (ctxt->value->nodesetval != NULL)
11114 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11115 /*
11116 * limit tree traversing to first node in the result
11117 */
11118 if (ctxt->value->nodesetval->nodeNr > 1)
11119 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11120 *last =
11121 ctxt->value->nodesetval->nodeTab[ctxt->value->
11122 nodesetval->nodeNr -
11123 1];
11124 }
11125 cur =
11126 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11127 CHECK_ERROR0;
11128 if ((ctxt->value != NULL)
11129 && (ctxt->value->type == XPATH_NODESET)
11130 && (ctxt->value->nodesetval != NULL)
11131 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11132 }
11133
11134 arg2 = valuePop(ctxt);
11135 arg1 = valuePop(ctxt);
11136 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11137 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11138 xmlXPathReleaseObject(ctxt->context, arg1);
11139 xmlXPathReleaseObject(ctxt->context, arg2);
11140 XP_ERROR0(XPATH_INVALID_TYPE);
11141 }
11142 if ((ctxt->context->opLimit != 0) &&
11143 (((arg1->nodesetval != NULL) &&
11144 (xmlXPathCheckOpLimit(ctxt,
11145 arg1->nodesetval->nodeNr) < 0)) ||
11146 ((arg2->nodesetval != NULL) &&
11147 (xmlXPathCheckOpLimit(ctxt,
11148 arg2->nodesetval->nodeNr) < 0)))) {
11149 xmlXPathReleaseObject(ctxt->context, arg1);
11150 xmlXPathReleaseObject(ctxt->context, arg2);
11151 break;
11152 }
11153
11154 if ((arg2->nodesetval != NULL) &&
11155 (arg2->nodesetval->nodeNr != 0)) {
11156 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11157 arg2->nodesetval);
11158 if (arg1->nodesetval == NULL)
11159 xmlXPathPErrMemory(ctxt);
11160 }
11161 valuePush(ctxt, arg1);
11162 xmlXPathReleaseObject(ctxt->context, arg2);
11163 total += cur;
11164 break;
11165 case XPATH_OP_ROOT:
11166 xmlXPathRoot(ctxt);
11167 break;
11168 case XPATH_OP_NODE:
11169 if (op->ch1 != -1)
11170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11171 CHECK_ERROR0;
11172 if (op->ch2 != -1)
11173 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11174 CHECK_ERROR0;
11175 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11176 ctxt->context->node));
11177 break;
11178 case XPATH_OP_COLLECT:{
11179 if (op->ch1 == -1)
11180 break;
11181
11182 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11183 CHECK_ERROR0;
11184
11185 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11186 break;
11187 }
11188 case XPATH_OP_VALUE:
11189 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11190 break;
11191 case XPATH_OP_SORT:
11192 if (op->ch1 != -1)
11193 total +=
11194 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11195 last);
11196 CHECK_ERROR0;
11197 if ((ctxt->value != NULL)
11198 && (ctxt->value->type == XPATH_NODESET)
11199 && (ctxt->value->nodesetval != NULL)
11200 && (ctxt->value->nodesetval->nodeNr > 1))
11201 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11202 break;
11203 default:
11204 total += xmlXPathCompOpEval(ctxt, op);
11205 break;
11206 }
11207
11208 ctxt->context->depth -= 1;
11209 return (total);
11210 }
11211
11212 #ifdef XP_OPTIMIZED_FILTER_FIRST
11213 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11214 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11215 xmlXPathStepOpPtr op, xmlNodePtr * first)
11216 {
11217 int total = 0;
11218 xmlXPathCompExprPtr comp;
11219 xmlXPathObjectPtr obj;
11220 xmlNodeSetPtr set;
11221
11222 CHECK_ERROR0;
11223 comp = ctxt->comp;
11224 /*
11225 * Optimization for ()[last()] selection i.e. the last elem
11226 */
11227 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11228 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11229 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11230 int f = comp->steps[op->ch2].ch1;
11231
11232 if ((f != -1) &&
11233 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11234 (comp->steps[f].value5 == NULL) &&
11235 (comp->steps[f].value == 0) &&
11236 (comp->steps[f].value4 != NULL) &&
11237 (xmlStrEqual
11238 (comp->steps[f].value4, BAD_CAST "last"))) {
11239 xmlNodePtr last = NULL;
11240
11241 total +=
11242 xmlXPathCompOpEvalLast(ctxt,
11243 &comp->steps[op->ch1],
11244 &last);
11245 CHECK_ERROR0;
11246 /*
11247 * The nodeset should be in document order,
11248 * Keep only the last value
11249 */
11250 if ((ctxt->value != NULL) &&
11251 (ctxt->value->type == XPATH_NODESET) &&
11252 (ctxt->value->nodesetval != NULL) &&
11253 (ctxt->value->nodesetval->nodeTab != NULL) &&
11254 (ctxt->value->nodesetval->nodeNr > 1)) {
11255 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11256 *first = *(ctxt->value->nodesetval->nodeTab);
11257 }
11258 return (total);
11259 }
11260 }
11261
11262 if (op->ch1 != -1)
11263 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11264 CHECK_ERROR0;
11265 if (op->ch2 == -1)
11266 return (total);
11267 if (ctxt->value == NULL)
11268 return (total);
11269
11270 /*
11271 * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11272 * the stack. We have to temporarily remove the nodeset object from the
11273 * stack to avoid freeing it prematurely.
11274 */
11275 CHECK_TYPE0(XPATH_NODESET);
11276 obj = valuePop(ctxt);
11277 set = obj->nodesetval;
11278 if (set != NULL) {
11279 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11280 if (set->nodeNr > 0)
11281 *first = set->nodeTab[0];
11282 }
11283 valuePush(ctxt, obj);
11284
11285 return (total);
11286 }
11287 #endif /* XP_OPTIMIZED_FILTER_FIRST */
11288
11289 /**
11290 * xmlXPathCompOpEval:
11291 * @ctxt: the XPath parser context with the compiled expression
11292 * @op: an XPath compiled operation
11293 *
11294 * Evaluate the Precompiled XPath operation
11295 * Returns the number of nodes traversed
11296 */
11297 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)11298 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11299 {
11300 int total = 0;
11301 int equal, ret;
11302 xmlXPathCompExprPtr comp;
11303 xmlXPathObjectPtr arg1, arg2;
11304
11305 CHECK_ERROR0;
11306 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11307 return(0);
11308 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11309 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11310 ctxt->context->depth += 1;
11311 comp = ctxt->comp;
11312 switch (op->op) {
11313 case XPATH_OP_END:
11314 break;
11315 case XPATH_OP_AND:
11316 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11317 CHECK_ERROR0;
11318 xmlXPathBooleanFunction(ctxt, 1);
11319 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11320 break;
11321 arg2 = valuePop(ctxt);
11322 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11323 if (ctxt->error) {
11324 xmlXPathFreeObject(arg2);
11325 break;
11326 }
11327 xmlXPathBooleanFunction(ctxt, 1);
11328 if (ctxt->value != NULL)
11329 ctxt->value->boolval &= arg2->boolval;
11330 xmlXPathReleaseObject(ctxt->context, arg2);
11331 break;
11332 case XPATH_OP_OR:
11333 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11334 CHECK_ERROR0;
11335 xmlXPathBooleanFunction(ctxt, 1);
11336 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11337 break;
11338 arg2 = valuePop(ctxt);
11339 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11340 if (ctxt->error) {
11341 xmlXPathFreeObject(arg2);
11342 break;
11343 }
11344 xmlXPathBooleanFunction(ctxt, 1);
11345 if (ctxt->value != NULL)
11346 ctxt->value->boolval |= arg2->boolval;
11347 xmlXPathReleaseObject(ctxt->context, arg2);
11348 break;
11349 case XPATH_OP_EQUAL:
11350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11351 CHECK_ERROR0;
11352 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11353 CHECK_ERROR0;
11354 if (op->value)
11355 equal = xmlXPathEqualValues(ctxt);
11356 else
11357 equal = xmlXPathNotEqualValues(ctxt);
11358 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11359 break;
11360 case XPATH_OP_CMP:
11361 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11362 CHECK_ERROR0;
11363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11364 CHECK_ERROR0;
11365 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11366 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11367 break;
11368 case XPATH_OP_PLUS:
11369 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11370 CHECK_ERROR0;
11371 if (op->ch2 != -1) {
11372 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11373 }
11374 CHECK_ERROR0;
11375 if (op->value == 0)
11376 xmlXPathSubValues(ctxt);
11377 else if (op->value == 1)
11378 xmlXPathAddValues(ctxt);
11379 else if (op->value == 2)
11380 xmlXPathValueFlipSign(ctxt);
11381 else if (op->value == 3) {
11382 CAST_TO_NUMBER;
11383 CHECK_TYPE0(XPATH_NUMBER);
11384 }
11385 break;
11386 case XPATH_OP_MULT:
11387 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11388 CHECK_ERROR0;
11389 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11390 CHECK_ERROR0;
11391 if (op->value == 0)
11392 xmlXPathMultValues(ctxt);
11393 else if (op->value == 1)
11394 xmlXPathDivValues(ctxt);
11395 else if (op->value == 2)
11396 xmlXPathModValues(ctxt);
11397 break;
11398 case XPATH_OP_UNION:
11399 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11400 CHECK_ERROR0;
11401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11402 CHECK_ERROR0;
11403
11404 arg2 = valuePop(ctxt);
11405 arg1 = valuePop(ctxt);
11406 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11407 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11408 xmlXPathReleaseObject(ctxt->context, arg1);
11409 xmlXPathReleaseObject(ctxt->context, arg2);
11410 XP_ERROR0(XPATH_INVALID_TYPE);
11411 }
11412 if ((ctxt->context->opLimit != 0) &&
11413 (((arg1->nodesetval != NULL) &&
11414 (xmlXPathCheckOpLimit(ctxt,
11415 arg1->nodesetval->nodeNr) < 0)) ||
11416 ((arg2->nodesetval != NULL) &&
11417 (xmlXPathCheckOpLimit(ctxt,
11418 arg2->nodesetval->nodeNr) < 0)))) {
11419 xmlXPathReleaseObject(ctxt->context, arg1);
11420 xmlXPathReleaseObject(ctxt->context, arg2);
11421 break;
11422 }
11423
11424 if (((arg2->nodesetval != NULL) &&
11425 (arg2->nodesetval->nodeNr != 0)))
11426 {
11427 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11428 arg2->nodesetval);
11429 if (arg1->nodesetval == NULL)
11430 xmlXPathPErrMemory(ctxt);
11431 }
11432
11433 valuePush(ctxt, arg1);
11434 xmlXPathReleaseObject(ctxt->context, arg2);
11435 break;
11436 case XPATH_OP_ROOT:
11437 xmlXPathRoot(ctxt);
11438 break;
11439 case XPATH_OP_NODE:
11440 if (op->ch1 != -1)
11441 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11442 CHECK_ERROR0;
11443 if (op->ch2 != -1)
11444 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11445 CHECK_ERROR0;
11446 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11447 ctxt->context->node));
11448 break;
11449 case XPATH_OP_COLLECT:{
11450 if (op->ch1 == -1)
11451 break;
11452
11453 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11454 CHECK_ERROR0;
11455
11456 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11457 break;
11458 }
11459 case XPATH_OP_VALUE:
11460 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11461 break;
11462 case XPATH_OP_VARIABLE:{
11463 xmlXPathObjectPtr val;
11464
11465 if (op->ch1 != -1)
11466 total +=
11467 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11468 if (op->value5 == NULL) {
11469 val = xmlXPathVariableLookup(ctxt->context, op->value4);
11470 if (val == NULL)
11471 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11472 valuePush(ctxt, val);
11473 } else {
11474 const xmlChar *URI;
11475
11476 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11477 if (URI == NULL) {
11478 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11479 break;
11480 }
11481 val = xmlXPathVariableLookupNS(ctxt->context,
11482 op->value4, URI);
11483 if (val == NULL)
11484 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11485 valuePush(ctxt, val);
11486 }
11487 break;
11488 }
11489 case XPATH_OP_FUNCTION:{
11490 xmlXPathFunction func;
11491 const xmlChar *oldFunc, *oldFuncURI;
11492 int i;
11493 int frame;
11494
11495 frame = ctxt->valueNr;
11496 if (op->ch1 != -1) {
11497 total +=
11498 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11499 if (ctxt->error != XPATH_EXPRESSION_OK)
11500 break;
11501 }
11502 if (ctxt->valueNr < frame + op->value)
11503 XP_ERROR0(XPATH_INVALID_OPERAND);
11504 for (i = 0; i < op->value; i++) {
11505 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
11506 XP_ERROR0(XPATH_INVALID_OPERAND);
11507 }
11508 if (op->cache != NULL)
11509 func = op->cache;
11510 else {
11511 const xmlChar *URI = NULL;
11512
11513 if (op->value5 == NULL)
11514 func =
11515 xmlXPathFunctionLookup(ctxt->context,
11516 op->value4);
11517 else {
11518 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11519 if (URI == NULL)
11520 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11521 func = xmlXPathFunctionLookupNS(ctxt->context,
11522 op->value4, URI);
11523 }
11524 if (func == NULL)
11525 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
11526 op->cache = func;
11527 op->cacheURI = (void *) URI;
11528 }
11529 oldFunc = ctxt->context->function;
11530 oldFuncURI = ctxt->context->functionURI;
11531 ctxt->context->function = op->value4;
11532 ctxt->context->functionURI = op->cacheURI;
11533 func(ctxt, op->value);
11534 ctxt->context->function = oldFunc;
11535 ctxt->context->functionURI = oldFuncURI;
11536 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11537 (ctxt->valueNr != frame + 1))
11538 XP_ERROR0(XPATH_STACK_ERROR);
11539 break;
11540 }
11541 case XPATH_OP_ARG:
11542 if (op->ch1 != -1) {
11543 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11544 CHECK_ERROR0;
11545 }
11546 if (op->ch2 != -1) {
11547 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11548 CHECK_ERROR0;
11549 }
11550 break;
11551 case XPATH_OP_PREDICATE:
11552 case XPATH_OP_FILTER:{
11553 xmlXPathObjectPtr obj;
11554 xmlNodeSetPtr set;
11555
11556 /*
11557 * Optimization for ()[1] selection i.e. the first elem
11558 */
11559 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11560 #ifdef XP_OPTIMIZED_FILTER_FIRST
11561 /*
11562 * FILTER TODO: Can we assume that the inner processing
11563 * will result in an ordered list if we have an
11564 * XPATH_OP_FILTER?
11565 * What about an additional field or flag on
11566 * xmlXPathObject like @sorted ? This way we wouldn't need
11567 * to assume anything, so it would be more robust and
11568 * easier to optimize.
11569 */
11570 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11571 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11572 #else
11573 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11574 #endif
11575 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11576 xmlXPathObjectPtr val;
11577
11578 val = comp->steps[op->ch2].value4;
11579 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11580 (val->floatval == 1.0)) {
11581 xmlNodePtr first = NULL;
11582
11583 total +=
11584 xmlXPathCompOpEvalFirst(ctxt,
11585 &comp->steps[op->ch1],
11586 &first);
11587 CHECK_ERROR0;
11588 /*
11589 * The nodeset should be in document order,
11590 * Keep only the first value
11591 */
11592 if ((ctxt->value != NULL) &&
11593 (ctxt->value->type == XPATH_NODESET) &&
11594 (ctxt->value->nodesetval != NULL) &&
11595 (ctxt->value->nodesetval->nodeNr > 1))
11596 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11597 1, 1);
11598 break;
11599 }
11600 }
11601 /*
11602 * Optimization for ()[last()] selection i.e. the last elem
11603 */
11604 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11605 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11606 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11607 int f = comp->steps[op->ch2].ch1;
11608
11609 if ((f != -1) &&
11610 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11611 (comp->steps[f].value5 == NULL) &&
11612 (comp->steps[f].value == 0) &&
11613 (comp->steps[f].value4 != NULL) &&
11614 (xmlStrEqual
11615 (comp->steps[f].value4, BAD_CAST "last"))) {
11616 xmlNodePtr last = NULL;
11617
11618 total +=
11619 xmlXPathCompOpEvalLast(ctxt,
11620 &comp->steps[op->ch1],
11621 &last);
11622 CHECK_ERROR0;
11623 /*
11624 * The nodeset should be in document order,
11625 * Keep only the last value
11626 */
11627 if ((ctxt->value != NULL) &&
11628 (ctxt->value->type == XPATH_NODESET) &&
11629 (ctxt->value->nodesetval != NULL) &&
11630 (ctxt->value->nodesetval->nodeTab != NULL) &&
11631 (ctxt->value->nodesetval->nodeNr > 1))
11632 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11633 break;
11634 }
11635 }
11636 /*
11637 * Process inner predicates first.
11638 * Example "index[parent::book][1]":
11639 * ...
11640 * PREDICATE <-- we are here "[1]"
11641 * PREDICATE <-- process "[parent::book]" first
11642 * SORT
11643 * COLLECT 'parent' 'name' 'node' book
11644 * NODE
11645 * ELEM Object is a number : 1
11646 */
11647 if (op->ch1 != -1)
11648 total +=
11649 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11650 CHECK_ERROR0;
11651 if (op->ch2 == -1)
11652 break;
11653 if (ctxt->value == NULL)
11654 break;
11655
11656 /*
11657 * In case of errors, xmlXPathNodeSetFilter can pop additional
11658 * nodes from the stack. We have to temporarily remove the
11659 * nodeset object from the stack to avoid freeing it
11660 * prematurely.
11661 */
11662 CHECK_TYPE0(XPATH_NODESET);
11663 obj = valuePop(ctxt);
11664 set = obj->nodesetval;
11665 if (set != NULL)
11666 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11667 1, set->nodeNr, 1);
11668 valuePush(ctxt, obj);
11669 break;
11670 }
11671 case XPATH_OP_SORT:
11672 if (op->ch1 != -1)
11673 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11674 CHECK_ERROR0;
11675 if ((ctxt->value != NULL) &&
11676 (ctxt->value->type == XPATH_NODESET) &&
11677 (ctxt->value->nodesetval != NULL) &&
11678 (ctxt->value->nodesetval->nodeNr > 1))
11679 {
11680 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11681 }
11682 break;
11683 default:
11684 XP_ERROR0(XPATH_INVALID_OPERAND);
11685 break;
11686 }
11687
11688 ctxt->context->depth -= 1;
11689 return (total);
11690 }
11691
11692 /**
11693 * xmlXPathCompOpEvalToBoolean:
11694 * @ctxt: the XPath parser context
11695 *
11696 * Evaluates if the expression evaluates to true.
11697 *
11698 * Returns 1 if true, 0 if false and -1 on API or internal errors.
11699 */
11700 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)11701 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
11702 xmlXPathStepOpPtr op,
11703 int isPredicate)
11704 {
11705 xmlXPathObjectPtr resObj = NULL;
11706
11707 start:
11708 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11709 return(0);
11710 /* comp = ctxt->comp; */
11711 switch (op->op) {
11712 case XPATH_OP_END:
11713 return (0);
11714 case XPATH_OP_VALUE:
11715 resObj = (xmlXPathObjectPtr) op->value4;
11716 if (isPredicate)
11717 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11718 return(xmlXPathCastToBoolean(resObj));
11719 case XPATH_OP_SORT:
11720 /*
11721 * We don't need sorting for boolean results. Skip this one.
11722 */
11723 if (op->ch1 != -1) {
11724 op = &ctxt->comp->steps[op->ch1];
11725 goto start;
11726 }
11727 return(0);
11728 case XPATH_OP_COLLECT:
11729 if (op->ch1 == -1)
11730 return(0);
11731
11732 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11733 if (ctxt->error != XPATH_EXPRESSION_OK)
11734 return(-1);
11735
11736 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11737 if (ctxt->error != XPATH_EXPRESSION_OK)
11738 return(-1);
11739
11740 resObj = valuePop(ctxt);
11741 if (resObj == NULL)
11742 return(-1);
11743 break;
11744 default:
11745 /*
11746 * Fallback to call xmlXPathCompOpEval().
11747 */
11748 xmlXPathCompOpEval(ctxt, op);
11749 if (ctxt->error != XPATH_EXPRESSION_OK)
11750 return(-1);
11751
11752 resObj = valuePop(ctxt);
11753 if (resObj == NULL)
11754 return(-1);
11755 break;
11756 }
11757
11758 if (resObj) {
11759 int res;
11760
11761 if (resObj->type == XPATH_BOOLEAN) {
11762 res = resObj->boolval;
11763 } else if (isPredicate) {
11764 /*
11765 * For predicates a result of type "number" is handled
11766 * differently:
11767 * SPEC XPath 1.0:
11768 * "If the result is a number, the result will be converted
11769 * to true if the number is equal to the context position
11770 * and will be converted to false otherwise;"
11771 */
11772 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11773 } else {
11774 res = xmlXPathCastToBoolean(resObj);
11775 }
11776 xmlXPathReleaseObject(ctxt->context, resObj);
11777 return(res);
11778 }
11779
11780 return(0);
11781 }
11782
11783 #ifdef XPATH_STREAMING
11784 /**
11785 * xmlXPathRunStreamEval:
11786 * @pctxt: the XPath parser context with the compiled expression
11787 *
11788 * Evaluate the Precompiled Streamable XPath expression in the given context.
11789 */
11790 static int
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)11791 xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
11792 xmlXPathObjectPtr *resultSeq, int toBool)
11793 {
11794 int max_depth, min_depth;
11795 int from_root;
11796 int ret, depth;
11797 int eval_all_nodes;
11798 xmlNodePtr cur = NULL, limit = NULL;
11799 xmlStreamCtxtPtr patstream = NULL;
11800 xmlXPathContextPtr ctxt = pctxt->context;
11801
11802 if ((ctxt == NULL) || (comp == NULL))
11803 return(-1);
11804 max_depth = xmlPatternMaxDepth(comp);
11805 if (max_depth == -1)
11806 return(-1);
11807 if (max_depth == -2)
11808 max_depth = 10000;
11809 min_depth = xmlPatternMinDepth(comp);
11810 if (min_depth == -1)
11811 return(-1);
11812 from_root = xmlPatternFromRoot(comp);
11813 if (from_root < 0)
11814 return(-1);
11815
11816 if (! toBool) {
11817 if (resultSeq == NULL)
11818 return(-1);
11819 *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
11820 if (*resultSeq == NULL)
11821 return(-1);
11822 }
11823
11824 /*
11825 * handle the special cases of "/" amd "." being matched
11826 */
11827 if (min_depth == 0) {
11828 int res;
11829
11830 if (from_root) {
11831 /* Select "/" */
11832 if (toBool)
11833 return(1);
11834 res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11835 (xmlNodePtr) ctxt->doc);
11836 } else {
11837 /* Select "self::node()" */
11838 if (toBool)
11839 return(1);
11840 res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11841 ctxt->node);
11842 }
11843
11844 if (res < 0)
11845 xmlXPathPErrMemory(pctxt);
11846 }
11847 if (max_depth == 0) {
11848 return(0);
11849 }
11850
11851 if (from_root) {
11852 cur = (xmlNodePtr)ctxt->doc;
11853 } else if (ctxt->node != NULL) {
11854 switch (ctxt->node->type) {
11855 case XML_ELEMENT_NODE:
11856 case XML_DOCUMENT_NODE:
11857 case XML_DOCUMENT_FRAG_NODE:
11858 case XML_HTML_DOCUMENT_NODE:
11859 cur = ctxt->node;
11860 break;
11861 case XML_ATTRIBUTE_NODE:
11862 case XML_TEXT_NODE:
11863 case XML_CDATA_SECTION_NODE:
11864 case XML_ENTITY_REF_NODE:
11865 case XML_ENTITY_NODE:
11866 case XML_PI_NODE:
11867 case XML_COMMENT_NODE:
11868 case XML_NOTATION_NODE:
11869 case XML_DTD_NODE:
11870 case XML_DOCUMENT_TYPE_NODE:
11871 case XML_ELEMENT_DECL:
11872 case XML_ATTRIBUTE_DECL:
11873 case XML_ENTITY_DECL:
11874 case XML_NAMESPACE_DECL:
11875 case XML_XINCLUDE_START:
11876 case XML_XINCLUDE_END:
11877 break;
11878 }
11879 limit = cur;
11880 }
11881 if (cur == NULL) {
11882 return(0);
11883 }
11884
11885 patstream = xmlPatternGetStreamCtxt(comp);
11886 if (patstream == NULL) {
11887 xmlXPathPErrMemory(pctxt);
11888 return(-1);
11889 }
11890
11891 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11892
11893 if (from_root) {
11894 ret = xmlStreamPush(patstream, NULL, NULL);
11895 if (ret < 0) {
11896 } else if (ret == 1) {
11897 if (toBool)
11898 goto return_1;
11899 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
11900 xmlXPathPErrMemory(pctxt);
11901 }
11902 }
11903 depth = 0;
11904 goto scan_children;
11905 next_node:
11906 do {
11907 if (ctxt->opLimit != 0) {
11908 if (ctxt->opCount >= ctxt->opLimit) {
11909 xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
11910 xmlFreeStreamCtxt(patstream);
11911 return(-1);
11912 }
11913 ctxt->opCount++;
11914 }
11915
11916 switch (cur->type) {
11917 case XML_ELEMENT_NODE:
11918 case XML_TEXT_NODE:
11919 case XML_CDATA_SECTION_NODE:
11920 case XML_COMMENT_NODE:
11921 case XML_PI_NODE:
11922 if (cur->type == XML_ELEMENT_NODE) {
11923 ret = xmlStreamPush(patstream, cur->name,
11924 (cur->ns ? cur->ns->href : NULL));
11925 } else if (eval_all_nodes)
11926 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11927 else
11928 break;
11929
11930 if (ret < 0) {
11931 xmlXPathPErrMemory(pctxt);
11932 } else if (ret == 1) {
11933 if (toBool)
11934 goto return_1;
11935 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11936 cur) < 0)
11937 xmlXPathPErrMemory(pctxt);
11938 }
11939 if ((cur->children == NULL) || (depth >= max_depth)) {
11940 ret = xmlStreamPop(patstream);
11941 while (cur->next != NULL) {
11942 cur = cur->next;
11943 if ((cur->type != XML_ENTITY_DECL) &&
11944 (cur->type != XML_DTD_NODE))
11945 goto next_node;
11946 }
11947 }
11948 default:
11949 break;
11950 }
11951
11952 scan_children:
11953 if (cur->type == XML_NAMESPACE_DECL) break;
11954 if ((cur->children != NULL) && (depth < max_depth)) {
11955 /*
11956 * Do not descend on entities declarations
11957 */
11958 if (cur->children->type != XML_ENTITY_DECL) {
11959 cur = cur->children;
11960 depth++;
11961 /*
11962 * Skip DTDs
11963 */
11964 if (cur->type != XML_DTD_NODE)
11965 continue;
11966 }
11967 }
11968
11969 if (cur == limit)
11970 break;
11971
11972 while (cur->next != NULL) {
11973 cur = cur->next;
11974 if ((cur->type != XML_ENTITY_DECL) &&
11975 (cur->type != XML_DTD_NODE))
11976 goto next_node;
11977 }
11978
11979 do {
11980 cur = cur->parent;
11981 depth--;
11982 if ((cur == NULL) || (cur == limit) ||
11983 (cur->type == XML_DOCUMENT_NODE))
11984 goto done;
11985 if (cur->type == XML_ELEMENT_NODE) {
11986 ret = xmlStreamPop(patstream);
11987 } else if ((eval_all_nodes) &&
11988 ((cur->type == XML_TEXT_NODE) ||
11989 (cur->type == XML_CDATA_SECTION_NODE) ||
11990 (cur->type == XML_COMMENT_NODE) ||
11991 (cur->type == XML_PI_NODE)))
11992 {
11993 ret = xmlStreamPop(patstream);
11994 }
11995 if (cur->next != NULL) {
11996 cur = cur->next;
11997 break;
11998 }
11999 } while (cur != NULL);
12000
12001 } while ((cur != NULL) && (depth >= 0));
12002
12003 done:
12004
12005 if (patstream)
12006 xmlFreeStreamCtxt(patstream);
12007 return(0);
12008
12009 return_1:
12010 if (patstream)
12011 xmlFreeStreamCtxt(patstream);
12012 return(1);
12013 }
12014 #endif /* XPATH_STREAMING */
12015
12016 /**
12017 * xmlXPathRunEval:
12018 * @ctxt: the XPath parser context with the compiled expression
12019 * @toBool: evaluate to a boolean result
12020 *
12021 * Evaluate the Precompiled XPath expression in the given context.
12022 */
12023 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)12024 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12025 {
12026 xmlXPathCompExprPtr comp;
12027 int oldDepth;
12028
12029 if ((ctxt == NULL) || (ctxt->comp == NULL))
12030 return(-1);
12031
12032 if (ctxt->valueTab == NULL) {
12033 /* Allocate the value stack */
12034 ctxt->valueTab = (xmlXPathObjectPtr *)
12035 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12036 if (ctxt->valueTab == NULL) {
12037 xmlXPathPErrMemory(ctxt);
12038 return(-1);
12039 }
12040 ctxt->valueNr = 0;
12041 ctxt->valueMax = 10;
12042 ctxt->value = NULL;
12043 }
12044 #ifdef XPATH_STREAMING
12045 if (ctxt->comp->stream) {
12046 int res;
12047
12048 if (toBool) {
12049 /*
12050 * Evaluation to boolean result.
12051 */
12052 res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12053 if (res != -1)
12054 return(res);
12055 } else {
12056 xmlXPathObjectPtr resObj = NULL;
12057
12058 /*
12059 * Evaluation to a sequence.
12060 */
12061 res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12062
12063 if ((res != -1) && (resObj != NULL)) {
12064 valuePush(ctxt, resObj);
12065 return(0);
12066 }
12067 if (resObj != NULL)
12068 xmlXPathReleaseObject(ctxt->context, resObj);
12069 }
12070 /*
12071 * QUESTION TODO: This falls back to normal XPath evaluation
12072 * if res == -1. Is this intended?
12073 */
12074 }
12075 #endif
12076 comp = ctxt->comp;
12077 if (comp->last < 0) {
12078 xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12079 return(-1);
12080 }
12081 oldDepth = ctxt->context->depth;
12082 if (toBool)
12083 return(xmlXPathCompOpEvalToBoolean(ctxt,
12084 &comp->steps[comp->last], 0));
12085 else
12086 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12087 ctxt->context->depth = oldDepth;
12088
12089 return(0);
12090 }
12091
12092 /************************************************************************
12093 * *
12094 * Public interfaces *
12095 * *
12096 ************************************************************************/
12097
12098 /**
12099 * xmlXPathEvalPredicate:
12100 * @ctxt: the XPath context
12101 * @res: the Predicate Expression evaluation result
12102 *
12103 * Evaluate a predicate result for the current node.
12104 * A PredicateExpr is evaluated by evaluating the Expr and converting
12105 * the result to a boolean. If the result is a number, the result will
12106 * be converted to true if the number is equal to the position of the
12107 * context node in the context node list (as returned by the position
12108 * function) and will be converted to false otherwise; if the result
12109 * is not a number, then the result will be converted as if by a call
12110 * to the boolean function.
12111 *
12112 * Returns 1 if predicate is true, 0 otherwise
12113 */
12114 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)12115 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12116 if ((ctxt == NULL) || (res == NULL)) return(0);
12117 switch (res->type) {
12118 case XPATH_BOOLEAN:
12119 return(res->boolval);
12120 case XPATH_NUMBER:
12121 return(res->floatval == ctxt->proximityPosition);
12122 case XPATH_NODESET:
12123 case XPATH_XSLT_TREE:
12124 if (res->nodesetval == NULL)
12125 return(0);
12126 return(res->nodesetval->nodeNr != 0);
12127 case XPATH_STRING:
12128 return((res->stringval != NULL) &&
12129 (xmlStrlen(res->stringval) != 0));
12130 default:
12131 break;
12132 }
12133 return(0);
12134 }
12135
12136 /**
12137 * xmlXPathEvaluatePredicateResult:
12138 * @ctxt: the XPath Parser context
12139 * @res: the Predicate Expression evaluation result
12140 *
12141 * Evaluate a predicate result for the current node.
12142 * A PredicateExpr is evaluated by evaluating the Expr and converting
12143 * the result to a boolean. If the result is a number, the result will
12144 * be converted to true if the number is equal to the position of the
12145 * context node in the context node list (as returned by the position
12146 * function) and will be converted to false otherwise; if the result
12147 * is not a number, then the result will be converted as if by a call
12148 * to the boolean function.
12149 *
12150 * Returns 1 if predicate is true, 0 otherwise
12151 */
12152 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)12153 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12154 xmlXPathObjectPtr res) {
12155 if ((ctxt == NULL) || (res == NULL)) return(0);
12156 switch (res->type) {
12157 case XPATH_BOOLEAN:
12158 return(res->boolval);
12159 case XPATH_NUMBER:
12160 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12161 return((res->floatval == ctxt->context->proximityPosition) &&
12162 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12163 #else
12164 return(res->floatval == ctxt->context->proximityPosition);
12165 #endif
12166 case XPATH_NODESET:
12167 case XPATH_XSLT_TREE:
12168 if (res->nodesetval == NULL)
12169 return(0);
12170 return(res->nodesetval->nodeNr != 0);
12171 case XPATH_STRING:
12172 return((res->stringval != NULL) && (res->stringval[0] != 0));
12173 default:
12174 break;
12175 }
12176 return(0);
12177 }
12178
12179 #ifdef XPATH_STREAMING
12180 /**
12181 * xmlXPathTryStreamCompile:
12182 * @ctxt: an XPath context
12183 * @str: the XPath expression
12184 *
12185 * Try to compile the XPath expression as a streamable subset.
12186 *
12187 * Returns the compiled expression or NULL if failed to compile.
12188 */
12189 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12190 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12191 /*
12192 * Optimization: use streaming patterns when the XPath expression can
12193 * be compiled to a stream lookup
12194 */
12195 xmlPatternPtr stream;
12196 xmlXPathCompExprPtr comp;
12197 xmlDictPtr dict = NULL;
12198 const xmlChar **namespaces = NULL;
12199 xmlNsPtr ns;
12200 int i, j;
12201
12202 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12203 (!xmlStrchr(str, '@'))) {
12204 const xmlChar *tmp;
12205 int res;
12206
12207 /*
12208 * We don't try to handle expressions using the verbose axis
12209 * specifiers ("::"), just the simplified form at this point.
12210 * Additionally, if there is no list of namespaces available and
12211 * there's a ":" in the expression, indicating a prefixed QName,
12212 * then we won't try to compile either. xmlPatterncompile() needs
12213 * to have a list of namespaces at compilation time in order to
12214 * compile prefixed name tests.
12215 */
12216 tmp = xmlStrchr(str, ':');
12217 if ((tmp != NULL) &&
12218 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12219 return(NULL);
12220
12221 if (ctxt != NULL) {
12222 dict = ctxt->dict;
12223 if (ctxt->nsNr > 0) {
12224 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12225 if (namespaces == NULL) {
12226 xmlXPathErrMemory(ctxt);
12227 return(NULL);
12228 }
12229 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12230 ns = ctxt->namespaces[j];
12231 namespaces[i++] = ns->href;
12232 namespaces[i++] = ns->prefix;
12233 }
12234 namespaces[i++] = NULL;
12235 namespaces[i] = NULL;
12236 }
12237 }
12238
12239 res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12240 &stream);
12241 if (namespaces != NULL) {
12242 xmlFree((xmlChar **)namespaces);
12243 }
12244 if (res < 0) {
12245 xmlXPathErrMemory(ctxt);
12246 return(NULL);
12247 }
12248 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12249 comp = xmlXPathNewCompExpr();
12250 if (comp == NULL) {
12251 xmlXPathErrMemory(ctxt);
12252 xmlFreePattern(stream);
12253 return(NULL);
12254 }
12255 comp->stream = stream;
12256 comp->dict = dict;
12257 if (comp->dict)
12258 xmlDictReference(comp->dict);
12259 return(comp);
12260 }
12261 xmlFreePattern(stream);
12262 }
12263 return(NULL);
12264 }
12265 #endif /* XPATH_STREAMING */
12266
12267 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)12268 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12269 xmlXPathStepOpPtr op)
12270 {
12271 xmlXPathCompExprPtr comp = pctxt->comp;
12272 xmlXPathContextPtr ctxt;
12273
12274 /*
12275 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12276 * internal representation.
12277 */
12278
12279 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12280 (op->ch1 != -1) &&
12281 (op->ch2 == -1 /* no predicate */))
12282 {
12283 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12284
12285 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12286 ((xmlXPathAxisVal) prevop->value ==
12287 AXIS_DESCENDANT_OR_SELF) &&
12288 (prevop->ch2 == -1) &&
12289 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12290 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12291 {
12292 /*
12293 * This is a "descendant-or-self::node()" without predicates.
12294 * Try to eliminate it.
12295 */
12296
12297 switch ((xmlXPathAxisVal) op->value) {
12298 case AXIS_CHILD:
12299 case AXIS_DESCENDANT:
12300 /*
12301 * Convert "descendant-or-self::node()/child::" or
12302 * "descendant-or-self::node()/descendant::" to
12303 * "descendant::"
12304 */
12305 op->ch1 = prevop->ch1;
12306 op->value = AXIS_DESCENDANT;
12307 break;
12308 case AXIS_SELF:
12309 case AXIS_DESCENDANT_OR_SELF:
12310 /*
12311 * Convert "descendant-or-self::node()/self::" or
12312 * "descendant-or-self::node()/descendant-or-self::" to
12313 * to "descendant-or-self::"
12314 */
12315 op->ch1 = prevop->ch1;
12316 op->value = AXIS_DESCENDANT_OR_SELF;
12317 break;
12318 default:
12319 break;
12320 }
12321 }
12322 }
12323
12324 /* OP_VALUE has invalid ch1. */
12325 if (op->op == XPATH_OP_VALUE)
12326 return;
12327
12328 /* Recurse */
12329 ctxt = pctxt->context;
12330 if (ctxt != NULL) {
12331 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
12332 return;
12333 ctxt->depth += 1;
12334 }
12335 if (op->ch1 != -1)
12336 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
12337 if (op->ch2 != -1)
12338 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
12339 if (ctxt != NULL)
12340 ctxt->depth -= 1;
12341 }
12342
12343 /**
12344 * xmlXPathCtxtCompile:
12345 * @ctxt: an XPath context
12346 * @str: the XPath expression
12347 *
12348 * Compile an XPath expression
12349 *
12350 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12351 * the caller has to free the object.
12352 */
12353 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12354 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12355 xmlXPathParserContextPtr pctxt;
12356 xmlXPathContextPtr tmpctxt = NULL;
12357 xmlXPathCompExprPtr comp;
12358 int oldDepth = 0;
12359
12360 #ifdef XPATH_STREAMING
12361 comp = xmlXPathTryStreamCompile(ctxt, str);
12362 if (comp != NULL)
12363 return(comp);
12364 #endif
12365
12366 xmlInitParser();
12367
12368 /*
12369 * We need an xmlXPathContext for the depth check.
12370 */
12371 if (ctxt == NULL) {
12372 tmpctxt = xmlXPathNewContext(NULL);
12373 if (tmpctxt == NULL)
12374 return(NULL);
12375 ctxt = tmpctxt;
12376 }
12377
12378 pctxt = xmlXPathNewParserContext(str, ctxt);
12379 if (pctxt == NULL) {
12380 if (tmpctxt != NULL)
12381 xmlXPathFreeContext(tmpctxt);
12382 return NULL;
12383 }
12384
12385 oldDepth = ctxt->depth;
12386 xmlXPathCompileExpr(pctxt, 1);
12387 ctxt->depth = oldDepth;
12388
12389 if( pctxt->error != XPATH_EXPRESSION_OK )
12390 {
12391 xmlXPathFreeParserContext(pctxt);
12392 if (tmpctxt != NULL)
12393 xmlXPathFreeContext(tmpctxt);
12394 return(NULL);
12395 }
12396
12397 if (*pctxt->cur != 0) {
12398 /*
12399 * aleksey: in some cases this line prints *second* error message
12400 * (see bug #78858) and probably this should be fixed.
12401 * However, we are not sure that all error messages are printed
12402 * out in other places. It's not critical so we leave it as-is for now
12403 */
12404 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12405 comp = NULL;
12406 } else {
12407 comp = pctxt->comp;
12408 if ((comp->nbStep > 1) && (comp->last >= 0)) {
12409 if (ctxt != NULL)
12410 oldDepth = ctxt->depth;
12411 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
12412 if (ctxt != NULL)
12413 ctxt->depth = oldDepth;
12414 }
12415 pctxt->comp = NULL;
12416 }
12417 xmlXPathFreeParserContext(pctxt);
12418 if (tmpctxt != NULL)
12419 xmlXPathFreeContext(tmpctxt);
12420
12421 if (comp != NULL) {
12422 comp->expr = xmlStrdup(str);
12423 }
12424 return(comp);
12425 }
12426
12427 /**
12428 * xmlXPathCompile:
12429 * @str: the XPath expression
12430 *
12431 * Compile an XPath expression
12432 *
12433 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12434 * the caller has to free the object.
12435 */
12436 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)12437 xmlXPathCompile(const xmlChar *str) {
12438 return(xmlXPathCtxtCompile(NULL, str));
12439 }
12440
12441 /**
12442 * xmlXPathCompiledEvalInternal:
12443 * @comp: the compiled XPath expression
12444 * @ctxt: the XPath context
12445 * @resObj: the resulting XPath object or NULL
12446 * @toBool: 1 if only a boolean result is requested
12447 *
12448 * Evaluate the Precompiled XPath expression in the given context.
12449 * The caller has to free @resObj.
12450 *
12451 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12452 * the caller has to free the object.
12453 */
12454 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)12455 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
12456 xmlXPathContextPtr ctxt,
12457 xmlXPathObjectPtr *resObjPtr,
12458 int toBool)
12459 {
12460 xmlXPathParserContextPtr pctxt;
12461 xmlXPathObjectPtr resObj = NULL;
12462 int res;
12463
12464 if (comp == NULL)
12465 return(-1);
12466 xmlInitParser();
12467
12468 xmlResetError(&ctxt->lastError);
12469
12470 pctxt = xmlXPathCompParserContext(comp, ctxt);
12471 if (pctxt == NULL)
12472 return(-1);
12473 res = xmlXPathRunEval(pctxt, toBool);
12474
12475 if (pctxt->error == XPATH_EXPRESSION_OK) {
12476 if (pctxt->valueNr != ((toBool) ? 0 : 1))
12477 xmlXPathErr(pctxt, XPATH_STACK_ERROR);
12478 else if (!toBool)
12479 resObj = valuePop(pctxt);
12480 }
12481
12482 if (resObjPtr)
12483 *resObjPtr = resObj;
12484 else
12485 xmlXPathReleaseObject(ctxt, resObj);
12486
12487 pctxt->comp = NULL;
12488 xmlXPathFreeParserContext(pctxt);
12489
12490 return(res);
12491 }
12492
12493 /**
12494 * xmlXPathCompiledEval:
12495 * @comp: the compiled XPath expression
12496 * @ctx: the XPath context
12497 *
12498 * Evaluate the Precompiled XPath expression in the given context.
12499 *
12500 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12501 * the caller has to free the object.
12502 */
12503 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)12504 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
12505 {
12506 xmlXPathObjectPtr res = NULL;
12507
12508 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
12509 return(res);
12510 }
12511
12512 /**
12513 * xmlXPathCompiledEvalToBoolean:
12514 * @comp: the compiled XPath expression
12515 * @ctxt: the XPath context
12516 *
12517 * Applies the XPath boolean() function on the result of the given
12518 * compiled expression.
12519 *
12520 * Returns 1 if the expression evaluated to true, 0 if to false and
12521 * -1 in API and internal errors.
12522 */
12523 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)12524 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
12525 xmlXPathContextPtr ctxt)
12526 {
12527 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
12528 }
12529
12530 /**
12531 * xmlXPathEvalExpr:
12532 * @ctxt: the XPath Parser context
12533 *
12534 * DEPRECATED: Internal function, don't use.
12535 *
12536 * Parse and evaluate an XPath expression in the given context,
12537 * then push the result on the context stack
12538 */
12539 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)12540 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
12541 #ifdef XPATH_STREAMING
12542 xmlXPathCompExprPtr comp;
12543 #endif
12544 int oldDepth = 0;
12545
12546 if ((ctxt == NULL) || (ctxt->context == NULL))
12547 return;
12548 if (ctxt->context->lastError.code != 0)
12549 return;
12550
12551 #ifdef XPATH_STREAMING
12552 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
12553 if ((comp == NULL) &&
12554 (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
12555 xmlXPathPErrMemory(ctxt);
12556 return;
12557 }
12558 if (comp != NULL) {
12559 if (ctxt->comp != NULL)
12560 xmlXPathFreeCompExpr(ctxt->comp);
12561 ctxt->comp = comp;
12562 } else
12563 #endif
12564 {
12565 if (ctxt->context != NULL)
12566 oldDepth = ctxt->context->depth;
12567 xmlXPathCompileExpr(ctxt, 1);
12568 if (ctxt->context != NULL)
12569 ctxt->context->depth = oldDepth;
12570 CHECK_ERROR;
12571
12572 /* Check for trailing characters. */
12573 if (*ctxt->cur != 0)
12574 XP_ERROR(XPATH_EXPR_ERROR);
12575
12576 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12577 if (ctxt->context != NULL)
12578 oldDepth = ctxt->context->depth;
12579 xmlXPathOptimizeExpression(ctxt,
12580 &ctxt->comp->steps[ctxt->comp->last]);
12581 if (ctxt->context != NULL)
12582 ctxt->context->depth = oldDepth;
12583 }
12584 }
12585
12586 xmlXPathRunEval(ctxt, 0);
12587 }
12588
12589 /**
12590 * xmlXPathEval:
12591 * @str: the XPath expression
12592 * @ctx: the XPath context
12593 *
12594 * Evaluate the XPath Location Path in the given context.
12595 *
12596 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12597 * the caller has to free the object.
12598 */
12599 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)12600 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
12601 xmlXPathParserContextPtr ctxt;
12602 xmlXPathObjectPtr res;
12603
12604 if (ctx == NULL)
12605 return(NULL);
12606
12607 xmlInitParser();
12608
12609 xmlResetError(&ctx->lastError);
12610
12611 ctxt = xmlXPathNewParserContext(str, ctx);
12612 if (ctxt == NULL)
12613 return NULL;
12614 xmlXPathEvalExpr(ctxt);
12615
12616 if (ctxt->error != XPATH_EXPRESSION_OK) {
12617 res = NULL;
12618 } else if (ctxt->valueNr != 1) {
12619 xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12620 res = NULL;
12621 } else {
12622 res = valuePop(ctxt);
12623 }
12624
12625 xmlXPathFreeParserContext(ctxt);
12626 return(res);
12627 }
12628
12629 /**
12630 * xmlXPathSetContextNode:
12631 * @node: the node to to use as the context node
12632 * @ctx: the XPath context
12633 *
12634 * Sets 'node' as the context node. The node must be in the same
12635 * document as that associated with the context.
12636 *
12637 * Returns -1 in case of error or 0 if successful
12638 */
12639 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)12640 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
12641 if ((node == NULL) || (ctx == NULL))
12642 return(-1);
12643
12644 if (node->doc == ctx->doc) {
12645 ctx->node = node;
12646 return(0);
12647 }
12648 return(-1);
12649 }
12650
12651 /**
12652 * xmlXPathNodeEval:
12653 * @node: the node to to use as the context node
12654 * @str: the XPath expression
12655 * @ctx: the XPath context
12656 *
12657 * Evaluate the XPath Location Path in the given context. The node 'node'
12658 * is set as the context node. The context node is not restored.
12659 *
12660 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12661 * the caller has to free the object.
12662 */
12663 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)12664 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
12665 if (str == NULL)
12666 return(NULL);
12667 if (xmlXPathSetContextNode(node, ctx) < 0)
12668 return(NULL);
12669 return(xmlXPathEval(str, ctx));
12670 }
12671
12672 /**
12673 * xmlXPathEvalExpression:
12674 * @str: the XPath expression
12675 * @ctxt: the XPath context
12676 *
12677 * Alias for xmlXPathEval().
12678 *
12679 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12680 * the caller has to free the object.
12681 */
12682 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)12683 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
12684 return(xmlXPathEval(str, ctxt));
12685 }
12686
12687 /************************************************************************
12688 * *
12689 * Extra functions not pertaining to the XPath spec *
12690 * *
12691 ************************************************************************/
12692 /**
12693 * xmlXPathEscapeUriFunction:
12694 * @ctxt: the XPath Parser context
12695 * @nargs: the number of arguments
12696 *
12697 * Implement the escape-uri() XPath function
12698 * string escape-uri(string $str, bool $escape-reserved)
12699 *
12700 * This function applies the URI escaping rules defined in section 2 of [RFC
12701 * 2396] to the string supplied as $uri-part, which typically represents all
12702 * or part of a URI. The effect of the function is to replace any special
12703 * character in the string by an escape sequence of the form %xx%yy...,
12704 * where xxyy... is the hexadecimal representation of the octets used to
12705 * represent the character in UTF-8.
12706 *
12707 * The set of characters that are escaped depends on the setting of the
12708 * boolean argument $escape-reserved.
12709 *
12710 * If $escape-reserved is true, all characters are escaped other than lower
12711 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
12712 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
12713 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
12714 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
12715 * A-F).
12716 *
12717 * If $escape-reserved is false, the behavior differs in that characters
12718 * referred to in [RFC 2396] as reserved characters are not escaped. These
12719 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
12720 *
12721 * [RFC 2396] does not define whether escaped URIs should use lower case or
12722 * upper case for hexadecimal digits. To ensure that escaped URIs can be
12723 * compared using string comparison functions, this function must always use
12724 * the upper-case letters A-F.
12725 *
12726 * Generally, $escape-reserved should be set to true when escaping a string
12727 * that is to form a single part of a URI, and to false when escaping an
12728 * entire URI or URI reference.
12729 *
12730 * In the case of non-ascii characters, the string is encoded according to
12731 * utf-8 and then converted according to RFC 2396.
12732 *
12733 * Examples
12734 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
12735 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
12736 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
12737 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
12738 *
12739 */
12740 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)12741 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
12742 xmlXPathObjectPtr str;
12743 int escape_reserved;
12744 xmlBufPtr target;
12745 xmlChar *cptr;
12746 xmlChar escape[4];
12747
12748 CHECK_ARITY(2);
12749
12750 escape_reserved = xmlXPathPopBoolean(ctxt);
12751
12752 CAST_TO_STRING;
12753 str = valuePop(ctxt);
12754
12755 target = xmlBufCreate(50);
12756
12757 escape[0] = '%';
12758 escape[3] = 0;
12759
12760 if (target) {
12761 for (cptr = str->stringval; *cptr; cptr++) {
12762 if ((*cptr >= 'A' && *cptr <= 'Z') ||
12763 (*cptr >= 'a' && *cptr <= 'z') ||
12764 (*cptr >= '0' && *cptr <= '9') ||
12765 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
12766 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
12767 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
12768 (*cptr == '%' &&
12769 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
12770 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
12771 (cptr[1] >= '0' && cptr[1] <= '9')) &&
12772 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
12773 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
12774 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
12775 (!escape_reserved &&
12776 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
12777 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
12778 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
12779 *cptr == ','))) {
12780 xmlBufAdd(target, cptr, 1);
12781 } else {
12782 if ((*cptr >> 4) < 10)
12783 escape[1] = '0' + (*cptr >> 4);
12784 else
12785 escape[1] = 'A' - 10 + (*cptr >> 4);
12786 if ((*cptr & 0xF) < 10)
12787 escape[2] = '0' + (*cptr & 0xF);
12788 else
12789 escape[2] = 'A' - 10 + (*cptr & 0xF);
12790
12791 xmlBufAdd(target, &escape[0], 3);
12792 }
12793 }
12794 }
12795 valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
12796 xmlBufFree(target);
12797 xmlXPathReleaseObject(ctxt->context, str);
12798 }
12799
12800 /**
12801 * xmlXPathRegisterAllFunctions:
12802 * @ctxt: the XPath context
12803 *
12804 * Registers all default XPath functions in this context
12805 */
12806 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)12807 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
12808 {
12809 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
12810 xmlXPathBooleanFunction);
12811 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
12812 xmlXPathCeilingFunction);
12813 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
12814 xmlXPathCountFunction);
12815 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
12816 xmlXPathConcatFunction);
12817 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
12818 xmlXPathContainsFunction);
12819 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
12820 xmlXPathIdFunction);
12821 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
12822 xmlXPathFalseFunction);
12823 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
12824 xmlXPathFloorFunction);
12825 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
12826 xmlXPathLastFunction);
12827 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
12828 xmlXPathLangFunction);
12829 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
12830 xmlXPathLocalNameFunction);
12831 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
12832 xmlXPathNotFunction);
12833 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
12834 xmlXPathNameFunction);
12835 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
12836 xmlXPathNamespaceURIFunction);
12837 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
12838 xmlXPathNormalizeFunction);
12839 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
12840 xmlXPathNumberFunction);
12841 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
12842 xmlXPathPositionFunction);
12843 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
12844 xmlXPathRoundFunction);
12845 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
12846 xmlXPathStringFunction);
12847 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
12848 xmlXPathStringLengthFunction);
12849 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
12850 xmlXPathStartsWithFunction);
12851 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
12852 xmlXPathSubstringFunction);
12853 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
12854 xmlXPathSubstringBeforeFunction);
12855 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
12856 xmlXPathSubstringAfterFunction);
12857 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
12858 xmlXPathSumFunction);
12859 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
12860 xmlXPathTrueFunction);
12861 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
12862 xmlXPathTranslateFunction);
12863
12864 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
12865 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
12866 xmlXPathEscapeUriFunction);
12867 }
12868
12869 #endif /* LIBXML_XPATH_ENABLED */
12870