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_XPTR_LOCS_ENABLED
39 #include <libxml/xpointer.h>
40 #endif
41 #ifdef LIBXML_DEBUG_ENABLED
42 #include <libxml/debugXML.h>
43 #endif
44 #include <libxml/xmlerror.h>
45 #include <libxml/threads.h>
46 #ifdef LIBXML_PATTERN_ENABLED
47 #include <libxml/pattern.h>
48 #endif
49
50 #include "private/buf.h"
51 #include "private/error.h"
52 #include "private/xpath.h"
53
54 /* Disabled for now */
55 #if 0
56 #ifdef LIBXML_PATTERN_ENABLED
57 #define XPATH_STREAMING
58 #endif
59 #endif
60
61 /**
62 * WITH_TIM_SORT:
63 *
64 * Use the Timsort algorithm provided in timsort.h to sort
65 * nodeset as this is a great improvement over the old Shell sort
66 * used in xmlXPathNodeSetSort()
67 */
68 #define WITH_TIM_SORT
69
70 /*
71 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
72 * If defined, this will use xmlXPathCmpNodesExt() instead of
73 * xmlXPathCmpNodes(). The new function is optimized comparison of
74 * non-element nodes; actually it will speed up comparison only if
75 * xmlXPathOrderDocElems() was called in order to index the elements of
76 * a tree in document order; Libxslt does such an indexing, thus it will
77 * benefit from this optimization.
78 */
79 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
80
81 /*
82 * XP_OPTIMIZED_FILTER_FIRST:
83 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
84 * in a way, that it stop evaluation at the first node.
85 */
86 #define XP_OPTIMIZED_FILTER_FIRST
87
88 /*
89 * XPATH_MAX_STEPS:
90 * when compiling an XPath expression we arbitrary limit the maximum
91 * number of step operation in the compiled expression. 1000000 is
92 * an insanely large value which should never be reached under normal
93 * circumstances
94 */
95 #define XPATH_MAX_STEPS 1000000
96
97 /*
98 * XPATH_MAX_STACK_DEPTH:
99 * when evaluating an XPath expression we arbitrary limit the maximum
100 * number of object allowed to be pushed on the stack. 1000000 is
101 * an insanely large value which should never be reached under normal
102 * circumstances
103 */
104 #define XPATH_MAX_STACK_DEPTH 1000000
105
106 /*
107 * XPATH_MAX_NODESET_LENGTH:
108 * when evaluating an XPath expression nodesets are created and we
109 * arbitrary limit the maximum length of those node set. 10000000 is
110 * an insanely large value which should never be reached under normal
111 * circumstances, one would first need to construct an in memory tree
112 * with more than 10 millions nodes.
113 */
114 #define XPATH_MAX_NODESET_LENGTH 10000000
115
116 /*
117 * XPATH_MAX_RECRUSION_DEPTH:
118 * Maximum amount of nested functions calls when parsing or evaluating
119 * expressions
120 */
121 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
122 #define XPATH_MAX_RECURSION_DEPTH 500
123 #elif defined(_WIN32)
124 /* Windows typically limits stack size to 1MB. */
125 #define XPATH_MAX_RECURSION_DEPTH 1000
126 #else
127 #define XPATH_MAX_RECURSION_DEPTH 5000
128 #endif
129
130 /*
131 * TODO:
132 * There are a few spots where some tests are done which depend upon ascii
133 * data. These should be enhanced for full UTF8 support (see particularly
134 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
135 */
136
137 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
138
139 /************************************************************************
140 * *
141 * Floating point stuff *
142 * *
143 ************************************************************************/
144
145 double xmlXPathNAN = 0.0;
146 double xmlXPathPINF = 0.0;
147 double xmlXPathNINF = 0.0;
148
149 /**
150 * xmlXPathInit:
151 *
152 * DEPRECATED: Alias for xmlInitParser.
153 */
154 void
xmlXPathInit(void)155 xmlXPathInit(void) {
156 xmlInitParser();
157 }
158
159 /**
160 * xmlInitXPathInternal:
161 *
162 * Initialize the XPath environment
163 */
164 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
165 void
xmlInitXPathInternal(void)166 xmlInitXPathInternal(void) {
167 #if defined(NAN) && defined(INFINITY)
168 xmlXPathNAN = NAN;
169 xmlXPathPINF = INFINITY;
170 xmlXPathNINF = -INFINITY;
171 #else
172 /* MSVC doesn't allow division by zero in constant expressions. */
173 double zero = 0.0;
174 xmlXPathNAN = 0.0 / zero;
175 xmlXPathPINF = 1.0 / zero;
176 xmlXPathNINF = -xmlXPathPINF;
177 #endif
178 }
179
180 /**
181 * xmlXPathIsNaN:
182 * @val: a double value
183 *
184 * Checks whether a double is a NaN.
185 *
186 * Returns 1 if the value is a NaN, 0 otherwise
187 */
188 int
xmlXPathIsNaN(double val)189 xmlXPathIsNaN(double val) {
190 #ifdef isnan
191 return isnan(val);
192 #else
193 return !(val == val);
194 #endif
195 }
196
197 /**
198 * xmlXPathIsInf:
199 * @val: a double value
200 *
201 * Checks whether a double is an infinity.
202 *
203 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
204 */
205 int
xmlXPathIsInf(double val)206 xmlXPathIsInf(double val) {
207 #ifdef isinf
208 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
209 #else
210 if (val >= xmlXPathPINF)
211 return 1;
212 if (val <= -xmlXPathPINF)
213 return -1;
214 return 0;
215 #endif
216 }
217
218 #endif /* SCHEMAS or XPATH */
219
220 #ifdef LIBXML_XPATH_ENABLED
221
222 /*
223 * TODO: when compatibility allows remove all "fake node libxslt" strings
224 * the test should just be name[0] = ' '
225 */
226
227 static xmlNs xmlXPathXMLNamespaceStruct = {
228 NULL,
229 XML_NAMESPACE_DECL,
230 XML_XML_NAMESPACE,
231 BAD_CAST "xml",
232 NULL,
233 NULL
234 };
235 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
236 #ifndef LIBXML_THREAD_ENABLED
237 /*
238 * Optimizer is disabled only when threaded apps are detected while
239 * the library ain't compiled for thread safety.
240 */
241 static int xmlXPathDisableOptimizer = 0;
242 #endif
243
244 static void
245 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
246
247 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
248 /**
249 * xmlXPathCmpNodesExt:
250 * @node1: the first node
251 * @node2: the second node
252 *
253 * Compare two nodes w.r.t document order.
254 * This one is optimized for handling of non-element nodes.
255 *
256 * Returns -2 in case of error 1 if first point < second point, 0 if
257 * it's the same node, -1 otherwise
258 */
259 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)260 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
261 int depth1, depth2;
262 int misc = 0, precedence1 = 0, precedence2 = 0;
263 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
264 xmlNodePtr cur, root;
265 ptrdiff_t l1, l2;
266
267 if ((node1 == NULL) || (node2 == NULL))
268 return(-2);
269
270 if (node1 == node2)
271 return(0);
272
273 /*
274 * a couple of optimizations which will avoid computations in most cases
275 */
276 switch (node1->type) {
277 case XML_ELEMENT_NODE:
278 if (node2->type == XML_ELEMENT_NODE) {
279 if ((0 > (ptrdiff_t) node1->content) &&
280 (0 > (ptrdiff_t) node2->content) &&
281 (node1->doc == node2->doc))
282 {
283 l1 = -((ptrdiff_t) node1->content);
284 l2 = -((ptrdiff_t) node2->content);
285 if (l1 < l2)
286 return(1);
287 if (l1 > l2)
288 return(-1);
289 } else
290 goto turtle_comparison;
291 }
292 break;
293 case XML_ATTRIBUTE_NODE:
294 precedence1 = 1; /* element is owner */
295 miscNode1 = node1;
296 node1 = node1->parent;
297 misc = 1;
298 break;
299 case XML_TEXT_NODE:
300 case XML_CDATA_SECTION_NODE:
301 case XML_COMMENT_NODE:
302 case XML_PI_NODE: {
303 miscNode1 = node1;
304 /*
305 * Find nearest element node.
306 */
307 if (node1->prev != NULL) {
308 do {
309 node1 = node1->prev;
310 if (node1->type == XML_ELEMENT_NODE) {
311 precedence1 = 3; /* element in prev-sibl axis */
312 break;
313 }
314 if (node1->prev == NULL) {
315 precedence1 = 2; /* element is parent */
316 /*
317 * URGENT TODO: Are there any cases, where the
318 * parent of such a node is not an element node?
319 */
320 node1 = node1->parent;
321 break;
322 }
323 } while (1);
324 } else {
325 precedence1 = 2; /* element is parent */
326 node1 = node1->parent;
327 }
328 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
329 (0 <= (ptrdiff_t) node1->content)) {
330 /*
331 * Fallback for whatever case.
332 */
333 node1 = miscNode1;
334 precedence1 = 0;
335 } else
336 misc = 1;
337 }
338 break;
339 case XML_NAMESPACE_DECL:
340 /*
341 * TODO: why do we return 1 for namespace nodes?
342 */
343 return(1);
344 default:
345 break;
346 }
347 switch (node2->type) {
348 case XML_ELEMENT_NODE:
349 break;
350 case XML_ATTRIBUTE_NODE:
351 precedence2 = 1; /* element is owner */
352 miscNode2 = node2;
353 node2 = node2->parent;
354 misc = 1;
355 break;
356 case XML_TEXT_NODE:
357 case XML_CDATA_SECTION_NODE:
358 case XML_COMMENT_NODE:
359 case XML_PI_NODE: {
360 miscNode2 = node2;
361 if (node2->prev != NULL) {
362 do {
363 node2 = node2->prev;
364 if (node2->type == XML_ELEMENT_NODE) {
365 precedence2 = 3; /* element in prev-sibl axis */
366 break;
367 }
368 if (node2->prev == NULL) {
369 precedence2 = 2; /* element is parent */
370 node2 = node2->parent;
371 break;
372 }
373 } while (1);
374 } else {
375 precedence2 = 2; /* element is parent */
376 node2 = node2->parent;
377 }
378 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
379 (0 <= (ptrdiff_t) node2->content))
380 {
381 node2 = miscNode2;
382 precedence2 = 0;
383 } else
384 misc = 1;
385 }
386 break;
387 case XML_NAMESPACE_DECL:
388 return(1);
389 default:
390 break;
391 }
392 if (misc) {
393 if (node1 == node2) {
394 if (precedence1 == precedence2) {
395 /*
396 * The ugly case; but normally there aren't many
397 * adjacent non-element nodes around.
398 */
399 cur = miscNode2->prev;
400 while (cur != NULL) {
401 if (cur == miscNode1)
402 return(1);
403 if (cur->type == XML_ELEMENT_NODE)
404 return(-1);
405 cur = cur->prev;
406 }
407 return (-1);
408 } else {
409 /*
410 * Evaluate based on higher precedence wrt to the element.
411 * TODO: This assumes attributes are sorted before content.
412 * Is this 100% correct?
413 */
414 if (precedence1 < precedence2)
415 return(1);
416 else
417 return(-1);
418 }
419 }
420 /*
421 * Special case: One of the helper-elements is contained by the other.
422 * <foo>
423 * <node2>
424 * <node1>Text-1(precedence1 == 2)</node1>
425 * </node2>
426 * Text-6(precedence2 == 3)
427 * </foo>
428 */
429 if ((precedence2 == 3) && (precedence1 > 1)) {
430 cur = node1->parent;
431 while (cur) {
432 if (cur == node2)
433 return(1);
434 cur = cur->parent;
435 }
436 }
437 if ((precedence1 == 3) && (precedence2 > 1)) {
438 cur = node2->parent;
439 while (cur) {
440 if (cur == node1)
441 return(-1);
442 cur = cur->parent;
443 }
444 }
445 }
446
447 /*
448 * Speedup using document order if available.
449 */
450 if ((node1->type == XML_ELEMENT_NODE) &&
451 (node2->type == XML_ELEMENT_NODE) &&
452 (0 > (ptrdiff_t) node1->content) &&
453 (0 > (ptrdiff_t) node2->content) &&
454 (node1->doc == node2->doc)) {
455
456 l1 = -((ptrdiff_t) node1->content);
457 l2 = -((ptrdiff_t) node2->content);
458 if (l1 < l2)
459 return(1);
460 if (l1 > l2)
461 return(-1);
462 }
463
464 turtle_comparison:
465
466 if (node1 == node2->prev)
467 return(1);
468 if (node1 == node2->next)
469 return(-1);
470 /*
471 * compute depth to root
472 */
473 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
474 if (cur->parent == node1)
475 return(1);
476 depth2++;
477 }
478 root = cur;
479 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
480 if (cur->parent == node2)
481 return(-1);
482 depth1++;
483 }
484 /*
485 * Distinct document (or distinct entities :-( ) case.
486 */
487 if (root != cur) {
488 return(-2);
489 }
490 /*
491 * get the nearest common ancestor.
492 */
493 while (depth1 > depth2) {
494 depth1--;
495 node1 = node1->parent;
496 }
497 while (depth2 > depth1) {
498 depth2--;
499 node2 = node2->parent;
500 }
501 while (node1->parent != node2->parent) {
502 node1 = node1->parent;
503 node2 = node2->parent;
504 /* should not happen but just in case ... */
505 if ((node1 == NULL) || (node2 == NULL))
506 return(-2);
507 }
508 /*
509 * Find who's first.
510 */
511 if (node1 == node2->prev)
512 return(1);
513 if (node1 == node2->next)
514 return(-1);
515 /*
516 * Speedup using document order if available.
517 */
518 if ((node1->type == XML_ELEMENT_NODE) &&
519 (node2->type == XML_ELEMENT_NODE) &&
520 (0 > (ptrdiff_t) node1->content) &&
521 (0 > (ptrdiff_t) node2->content) &&
522 (node1->doc == node2->doc)) {
523
524 l1 = -((ptrdiff_t) node1->content);
525 l2 = -((ptrdiff_t) node2->content);
526 if (l1 < l2)
527 return(1);
528 if (l1 > l2)
529 return(-1);
530 }
531
532 for (cur = node1->next;cur != NULL;cur = cur->next)
533 if (cur == node2)
534 return(1);
535 return(-1); /* assume there is no sibling list corruption */
536 }
537 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
538
539 /*
540 * Wrapper for the Timsort algorithm from timsort.h
541 */
542 #ifdef WITH_TIM_SORT
543 #define SORT_NAME libxml_domnode
544 #define SORT_TYPE xmlNodePtr
545 /**
546 * wrap_cmp:
547 * @x: a node
548 * @y: another node
549 *
550 * Comparison function for the Timsort implementation
551 *
552 * Returns -2 in case of error -1 if first point < second point, 0 if
553 * it's the same node, +1 otherwise
554 */
555 static
556 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
557 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)558 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
559 {
560 int res = xmlXPathCmpNodesExt(x, y);
561 return res == -2 ? res : -res;
562 }
563 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)564 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
565 {
566 int res = xmlXPathCmpNodes(x, y);
567 return res == -2 ? res : -res;
568 }
569 #endif
570 #define SORT_CMP(x, y) (wrap_cmp(x, y))
571 #include "timsort.h"
572 #endif /* WITH_TIM_SORT */
573
574 /************************************************************************
575 * *
576 * Error handling routines *
577 * *
578 ************************************************************************/
579
580 /**
581 * XP_ERRORNULL:
582 * @X: the error code
583 *
584 * Macro to raise an XPath error and return NULL.
585 */
586 #define XP_ERRORNULL(X) \
587 { xmlXPathErr(ctxt, X); return(NULL); }
588
589 /*
590 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
591 */
592 static const char* const xmlXPathErrorMessages[] = {
593 "Ok\n",
594 "Number encoding\n",
595 "Unfinished literal\n",
596 "Start of literal\n",
597 "Expected $ for variable reference\n",
598 "Undefined variable\n",
599 "Invalid predicate\n",
600 "Invalid expression\n",
601 "Missing closing curly brace\n",
602 "Unregistered function\n",
603 "Invalid operand\n",
604 "Invalid type\n",
605 "Invalid number of arguments\n",
606 "Invalid context size\n",
607 "Invalid context position\n",
608 "Memory allocation error\n",
609 "Syntax error\n",
610 "Resource error\n",
611 "Sub resource error\n",
612 "Undefined namespace prefix\n",
613 "Encoding error\n",
614 "Char out of XML range\n",
615 "Invalid or incomplete context\n",
616 "Stack usage error\n",
617 "Forbidden variable\n",
618 "Operation limit exceeded\n",
619 "Recursion limit exceeded\n",
620 "?? Unknown error ??\n" /* Must be last in the list! */
621 };
622 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
623 sizeof(xmlXPathErrorMessages[0])) - 1)
624 /**
625 * xmlXPathErrMemory:
626 * @ctxt: an XPath context
627 * @extra: extra information
628 *
629 * Handle a memory allocation failure.
630 */
631 void
xmlXPathErrMemory(xmlXPathContextPtr ctxt)632 xmlXPathErrMemory(xmlXPathContextPtr ctxt)
633 {
634 if (ctxt == NULL)
635 return;
636 xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
637 &ctxt->lastError);
638 }
639
640 /**
641 * xmlXPathPErrMemory:
642 * @ctxt: an XPath parser context
643 * @extra: extra information
644 *
645 * Handle a memory allocation failure.
646 */
647 void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)648 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
649 {
650 if (ctxt == NULL)
651 return;
652 ctxt->error = XPATH_MEMORY_ERROR;
653 xmlXPathErrMemory(ctxt->context);
654 }
655
656 /**
657 * xmlXPathErr:
658 * @ctxt: a XPath parser context
659 * @error: the error code
660 *
661 * Handle an XPath error
662 */
663 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int code)664 xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
665 {
666 xmlStructuredErrorFunc schannel = NULL;
667 xmlGenericErrorFunc channel = NULL;
668 void *data = NULL;
669 xmlNodePtr node = NULL;
670 int res;
671
672 if (ctxt == NULL)
673 return;
674 if ((code < 0) || (code > MAXERRNO))
675 code = MAXERRNO;
676 /* Only report the first error */
677 if (ctxt->error != 0)
678 return;
679
680 ctxt->error = code;
681
682 if (ctxt->context != NULL) {
683 xmlErrorPtr err = &ctxt->context->lastError;
684
685 /* Don't overwrite memory error. */
686 if (err->code == XML_ERR_NO_MEMORY)
687 return;
688
689 /* cleanup current last error */
690 xmlResetError(err);
691
692 err->domain = XML_FROM_XPATH;
693 err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
694 err->level = XML_ERR_ERROR;
695 if (ctxt->base != NULL) {
696 err->str1 = (char *) xmlStrdup(ctxt->base);
697 if (err->str1 == NULL) {
698 xmlXPathPErrMemory(ctxt);
699 return;
700 }
701 }
702 err->int1 = ctxt->cur - ctxt->base;
703 err->node = ctxt->context->debugNode;
704
705 schannel = ctxt->context->error;
706 data = ctxt->context->userData;
707 node = ctxt->context->debugNode;
708 }
709
710 if (schannel == NULL) {
711 channel = xmlGenericError;
712 data = xmlGenericErrorContext;
713 }
714
715 res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
716 code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
717 XML_ERR_ERROR, NULL, 0,
718 (const char *) ctxt->base, NULL, NULL,
719 ctxt->cur - ctxt->base, 0,
720 "%s", xmlXPathErrorMessages[code]);
721 if (res < 0)
722 xmlXPathPErrMemory(ctxt);
723 }
724
725 /**
726 * xmlXPatherror:
727 * @ctxt: the XPath Parser context
728 * @file: the file name
729 * @line: the line number
730 * @no: the error number
731 *
732 * Formats an error message.
733 */
734 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)735 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
736 int line ATTRIBUTE_UNUSED, int no) {
737 xmlXPathErr(ctxt, no);
738 }
739
740 /**
741 * xmlXPathCheckOpLimit:
742 * @ctxt: the XPath Parser context
743 * @opCount: the number of operations to be added
744 *
745 * Adds opCount to the running total of operations and returns -1 if the
746 * operation limit is exceeded. Returns 0 otherwise.
747 */
748 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)749 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
750 xmlXPathContextPtr xpctxt = ctxt->context;
751
752 if ((opCount > xpctxt->opLimit) ||
753 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
754 xpctxt->opCount = xpctxt->opLimit;
755 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
756 return(-1);
757 }
758
759 xpctxt->opCount += opCount;
760 return(0);
761 }
762
763 #define OP_LIMIT_EXCEEDED(ctxt, n) \
764 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
765
766 /************************************************************************
767 * *
768 * Parser Types *
769 * *
770 ************************************************************************/
771
772 /*
773 * Types are private:
774 */
775
776 typedef enum {
777 XPATH_OP_END=0,
778 XPATH_OP_AND,
779 XPATH_OP_OR,
780 XPATH_OP_EQUAL,
781 XPATH_OP_CMP,
782 XPATH_OP_PLUS,
783 XPATH_OP_MULT,
784 XPATH_OP_UNION,
785 XPATH_OP_ROOT,
786 XPATH_OP_NODE,
787 XPATH_OP_COLLECT,
788 XPATH_OP_VALUE, /* 11 */
789 XPATH_OP_VARIABLE,
790 XPATH_OP_FUNCTION,
791 XPATH_OP_ARG,
792 XPATH_OP_PREDICATE,
793 XPATH_OP_FILTER, /* 16 */
794 XPATH_OP_SORT /* 17 */
795 #ifdef LIBXML_XPTR_LOCS_ENABLED
796 ,XPATH_OP_RANGETO
797 #endif
798 } xmlXPathOp;
799
800 typedef enum {
801 AXIS_ANCESTOR = 1,
802 AXIS_ANCESTOR_OR_SELF,
803 AXIS_ATTRIBUTE,
804 AXIS_CHILD,
805 AXIS_DESCENDANT,
806 AXIS_DESCENDANT_OR_SELF,
807 AXIS_FOLLOWING,
808 AXIS_FOLLOWING_SIBLING,
809 AXIS_NAMESPACE,
810 AXIS_PARENT,
811 AXIS_PRECEDING,
812 AXIS_PRECEDING_SIBLING,
813 AXIS_SELF
814 } xmlXPathAxisVal;
815
816 typedef enum {
817 NODE_TEST_NONE = 0,
818 NODE_TEST_TYPE = 1,
819 NODE_TEST_PI = 2,
820 NODE_TEST_ALL = 3,
821 NODE_TEST_NS = 4,
822 NODE_TEST_NAME = 5
823 } xmlXPathTestVal;
824
825 typedef enum {
826 NODE_TYPE_NODE = 0,
827 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
828 NODE_TYPE_TEXT = XML_TEXT_NODE,
829 NODE_TYPE_PI = XML_PI_NODE
830 } xmlXPathTypeVal;
831
832 typedef struct _xmlXPathStepOp xmlXPathStepOp;
833 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
834 struct _xmlXPathStepOp {
835 xmlXPathOp op; /* The identifier of the operation */
836 int ch1; /* First child */
837 int ch2; /* Second child */
838 int value;
839 int value2;
840 int value3;
841 void *value4;
842 void *value5;
843 xmlXPathFunction cache;
844 void *cacheURI;
845 };
846
847 struct _xmlXPathCompExpr {
848 int nbStep; /* Number of steps in this expression */
849 int maxStep; /* Maximum number of steps allocated */
850 xmlXPathStepOp *steps; /* ops for computation of this expression */
851 int last; /* index of last step in expression */
852 xmlChar *expr; /* the expression being computed */
853 xmlDictPtr dict; /* the dictionary to use if any */
854 #ifdef XPATH_STREAMING
855 xmlPatternPtr stream;
856 #endif
857 };
858
859 /************************************************************************
860 * *
861 * Forward declarations *
862 * *
863 ************************************************************************/
864
865 static void
866 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
867 static int
868 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
869 xmlXPathStepOpPtr op, xmlNodePtr *first);
870 static int
871 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
872 xmlXPathStepOpPtr op,
873 int isPredicate);
874 static void
875 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
876
877 /************************************************************************
878 * *
879 * Parser Type functions *
880 * *
881 ************************************************************************/
882
883 /**
884 * xmlXPathNewCompExpr:
885 *
886 * Create a new Xpath component
887 *
888 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
889 */
890 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)891 xmlXPathNewCompExpr(void) {
892 xmlXPathCompExprPtr cur;
893
894 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
895 if (cur == NULL)
896 return(NULL);
897 memset(cur, 0, sizeof(xmlXPathCompExpr));
898 cur->maxStep = 10;
899 cur->nbStep = 0;
900 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
901 sizeof(xmlXPathStepOp));
902 if (cur->steps == NULL) {
903 xmlFree(cur);
904 return(NULL);
905 }
906 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
907 cur->last = -1;
908 return(cur);
909 }
910
911 /**
912 * xmlXPathFreeCompExpr:
913 * @comp: an XPATH comp
914 *
915 * Free up the memory allocated by @comp
916 */
917 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)918 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
919 {
920 xmlXPathStepOpPtr op;
921 int i;
922
923 if (comp == NULL)
924 return;
925 if (comp->dict == NULL) {
926 for (i = 0; i < comp->nbStep; i++) {
927 op = &comp->steps[i];
928 if (op->value4 != NULL) {
929 if (op->op == XPATH_OP_VALUE)
930 xmlXPathFreeObject(op->value4);
931 else
932 xmlFree(op->value4);
933 }
934 if (op->value5 != NULL)
935 xmlFree(op->value5);
936 }
937 } else {
938 for (i = 0; i < comp->nbStep; i++) {
939 op = &comp->steps[i];
940 if (op->value4 != NULL) {
941 if (op->op == XPATH_OP_VALUE)
942 xmlXPathFreeObject(op->value4);
943 }
944 }
945 xmlDictFree(comp->dict);
946 }
947 if (comp->steps != NULL) {
948 xmlFree(comp->steps);
949 }
950 #ifdef XPATH_STREAMING
951 if (comp->stream != NULL) {
952 xmlFreePatternList(comp->stream);
953 }
954 #endif
955 if (comp->expr != NULL) {
956 xmlFree(comp->expr);
957 }
958
959 xmlFree(comp);
960 }
961
962 /**
963 * xmlXPathCompExprAdd:
964 * @comp: the compiled expression
965 * @ch1: first child index
966 * @ch2: second child index
967 * @op: an op
968 * @value: the first int value
969 * @value2: the second int value
970 * @value3: the third int value
971 * @value4: the first string value
972 * @value5: the second string value
973 *
974 * Add a step to an XPath Compiled Expression
975 *
976 * Returns -1 in case of failure, the index otherwise
977 */
978 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)979 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
980 xmlXPathOp op, int value,
981 int value2, int value3, void *value4, void *value5) {
982 xmlXPathCompExprPtr comp = ctxt->comp;
983 if (comp->nbStep >= comp->maxStep) {
984 xmlXPathStepOp *real;
985
986 if (comp->maxStep >= XPATH_MAX_STEPS) {
987 xmlXPathPErrMemory(ctxt);
988 return(-1);
989 }
990 comp->maxStep *= 2;
991 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
992 comp->maxStep * sizeof(xmlXPathStepOp));
993 if (real == NULL) {
994 comp->maxStep /= 2;
995 xmlXPathPErrMemory(ctxt);
996 return(-1);
997 }
998 comp->steps = real;
999 }
1000 comp->last = comp->nbStep;
1001 comp->steps[comp->nbStep].ch1 = ch1;
1002 comp->steps[comp->nbStep].ch2 = ch2;
1003 comp->steps[comp->nbStep].op = op;
1004 comp->steps[comp->nbStep].value = value;
1005 comp->steps[comp->nbStep].value2 = value2;
1006 comp->steps[comp->nbStep].value3 = value3;
1007 if ((comp->dict != NULL) &&
1008 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1009 (op == XPATH_OP_COLLECT))) {
1010 if (value4 != NULL) {
1011 comp->steps[comp->nbStep].value4 = (xmlChar *)
1012 (void *)xmlDictLookup(comp->dict, value4, -1);
1013 xmlFree(value4);
1014 } else
1015 comp->steps[comp->nbStep].value4 = NULL;
1016 if (value5 != NULL) {
1017 comp->steps[comp->nbStep].value5 = (xmlChar *)
1018 (void *)xmlDictLookup(comp->dict, value5, -1);
1019 xmlFree(value5);
1020 } else
1021 comp->steps[comp->nbStep].value5 = NULL;
1022 } else {
1023 comp->steps[comp->nbStep].value4 = value4;
1024 comp->steps[comp->nbStep].value5 = value5;
1025 }
1026 comp->steps[comp->nbStep].cache = NULL;
1027 return(comp->nbStep++);
1028 }
1029
1030 /**
1031 * xmlXPathCompSwap:
1032 * @comp: the compiled expression
1033 * @op: operation index
1034 *
1035 * Swaps 2 operations in the compiled expression
1036 */
1037 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1038 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1039 int tmp;
1040
1041 #ifndef LIBXML_THREAD_ENABLED
1042 /*
1043 * Since this manipulates possibly shared variables, this is
1044 * disabled if one detects that the library is used in a multithreaded
1045 * application
1046 */
1047 if (xmlXPathDisableOptimizer)
1048 return;
1049 #endif
1050
1051 tmp = op->ch1;
1052 op->ch1 = op->ch2;
1053 op->ch2 = tmp;
1054 }
1055
1056 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1057 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1058 (op), (val), (val2), (val3), (val4), (val5))
1059 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1060 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1061 (op), (val), (val2), (val3), (val4), (val5))
1062
1063 #define PUSH_LEAVE_EXPR(op, val, val2) \
1064 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1065
1066 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1067 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1068
1069 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1070 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1071 (val), (val2), 0 ,NULL ,NULL)
1072
1073 /************************************************************************
1074 * *
1075 * XPath object cache structures *
1076 * *
1077 ************************************************************************/
1078
1079 /* #define XP_DEFAULT_CACHE_ON */
1080
1081 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1082 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1083 struct _xmlXPathContextCache {
1084 xmlXPathObjectPtr nodesetObjs; /* stringval points to next */
1085 xmlXPathObjectPtr miscObjs; /* stringval points to next */
1086 int numNodeset;
1087 int maxNodeset;
1088 int numMisc;
1089 int maxMisc;
1090 };
1091
1092 /************************************************************************
1093 * *
1094 * Debugging related functions *
1095 * *
1096 ************************************************************************/
1097
1098 #ifdef LIBXML_DEBUG_ENABLED
1099 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1100 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1101 int i;
1102 char shift[100];
1103
1104 for (i = 0;((i < depth) && (i < 25));i++)
1105 shift[2 * i] = shift[2 * i + 1] = ' ';
1106 shift[2 * i] = shift[2 * i + 1] = 0;
1107 if (cur == NULL) {
1108 fprintf(output, "%s", shift);
1109 fprintf(output, "Node is NULL !\n");
1110 return;
1111
1112 }
1113
1114 if ((cur->type == XML_DOCUMENT_NODE) ||
1115 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1116 fprintf(output, "%s", shift);
1117 fprintf(output, " /\n");
1118 } else if (cur->type == XML_ATTRIBUTE_NODE)
1119 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1120 else
1121 xmlDebugDumpOneNode(output, cur, depth);
1122 }
1123 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1124 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1125 xmlNodePtr tmp;
1126 int i;
1127 char shift[100];
1128
1129 for (i = 0;((i < depth) && (i < 25));i++)
1130 shift[2 * i] = shift[2 * i + 1] = ' ';
1131 shift[2 * i] = shift[2 * i + 1] = 0;
1132 if (cur == NULL) {
1133 fprintf(output, "%s", shift);
1134 fprintf(output, "Node is NULL !\n");
1135 return;
1136
1137 }
1138
1139 while (cur != NULL) {
1140 tmp = cur;
1141 cur = cur->next;
1142 xmlDebugDumpOneNode(output, tmp, depth);
1143 }
1144 }
1145
1146 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1147 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1148 int i;
1149 char shift[100];
1150
1151 for (i = 0;((i < depth) && (i < 25));i++)
1152 shift[2 * i] = shift[2 * i + 1] = ' ';
1153 shift[2 * i] = shift[2 * i + 1] = 0;
1154
1155 if (cur == NULL) {
1156 fprintf(output, "%s", shift);
1157 fprintf(output, "NodeSet is NULL !\n");
1158 return;
1159
1160 }
1161
1162 if (cur != NULL) {
1163 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1164 for (i = 0;i < cur->nodeNr;i++) {
1165 fprintf(output, "%s", shift);
1166 fprintf(output, "%d", i + 1);
1167 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1168 }
1169 }
1170 }
1171
1172 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1173 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1174 int i;
1175 char shift[100];
1176
1177 for (i = 0;((i < depth) && (i < 25));i++)
1178 shift[2 * i] = shift[2 * i + 1] = ' ';
1179 shift[2 * i] = shift[2 * i + 1] = 0;
1180
1181 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1182 fprintf(output, "%s", shift);
1183 fprintf(output, "Value Tree is NULL !\n");
1184 return;
1185
1186 }
1187
1188 fprintf(output, "%s", shift);
1189 fprintf(output, "%d", i + 1);
1190 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1191 }
1192 #if defined(LIBXML_XPTR_LOCS_ENABLED)
1193 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1194 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1195 int i;
1196 char shift[100];
1197
1198 for (i = 0;((i < depth) && (i < 25));i++)
1199 shift[2 * i] = shift[2 * i + 1] = ' ';
1200 shift[2 * i] = shift[2 * i + 1] = 0;
1201
1202 if (cur == NULL) {
1203 fprintf(output, "%s", shift);
1204 fprintf(output, "LocationSet is NULL !\n");
1205 return;
1206
1207 }
1208
1209 for (i = 0;i < cur->locNr;i++) {
1210 fprintf(output, "%s", shift);
1211 fprintf(output, "%d : ", i + 1);
1212 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1213 }
1214 }
1215 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1216
1217 /**
1218 * xmlXPathDebugDumpObject:
1219 * @output: the FILE * to dump the output
1220 * @cur: the object to inspect
1221 * @depth: indentation level
1222 *
1223 * Dump the content of the object for debugging purposes
1224 */
1225 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1226 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1227 int i;
1228 char shift[100];
1229
1230 if (output == NULL) return;
1231
1232 for (i = 0;((i < depth) && (i < 25));i++)
1233 shift[2 * i] = shift[2 * i + 1] = ' ';
1234 shift[2 * i] = shift[2 * i + 1] = 0;
1235
1236
1237 fprintf(output, "%s", shift);
1238
1239 if (cur == NULL) {
1240 fprintf(output, "Object is empty (NULL)\n");
1241 return;
1242 }
1243 switch(cur->type) {
1244 case XPATH_UNDEFINED:
1245 fprintf(output, "Object is uninitialized\n");
1246 break;
1247 case XPATH_NODESET:
1248 fprintf(output, "Object is a Node Set :\n");
1249 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250 break;
1251 case XPATH_XSLT_TREE:
1252 fprintf(output, "Object is an XSLT value tree :\n");
1253 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254 break;
1255 case XPATH_BOOLEAN:
1256 fprintf(output, "Object is a Boolean : ");
1257 if (cur->boolval) fprintf(output, "true\n");
1258 else fprintf(output, "false\n");
1259 break;
1260 case XPATH_NUMBER:
1261 switch (xmlXPathIsInf(cur->floatval)) {
1262 case 1:
1263 fprintf(output, "Object is a number : Infinity\n");
1264 break;
1265 case -1:
1266 fprintf(output, "Object is a number : -Infinity\n");
1267 break;
1268 default:
1269 if (xmlXPathIsNaN(cur->floatval)) {
1270 fprintf(output, "Object is a number : NaN\n");
1271 } else if (cur->floatval == 0) {
1272 /* Omit sign for negative zero. */
1273 fprintf(output, "Object is a number : 0\n");
1274 } else {
1275 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276 }
1277 }
1278 break;
1279 case XPATH_STRING:
1280 fprintf(output, "Object is a string : ");
1281 xmlDebugDumpString(output, cur->stringval);
1282 fprintf(output, "\n");
1283 break;
1284 #ifdef LIBXML_XPTR_LOCS_ENABLED
1285 case XPATH_POINT:
1286 fprintf(output, "Object is a point : index %d in node", cur->index);
1287 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1288 fprintf(output, "\n");
1289 break;
1290 case XPATH_RANGE:
1291 if ((cur->user2 == NULL) ||
1292 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1293 fprintf(output, "Object is a collapsed range :\n");
1294 fprintf(output, "%s", shift);
1295 if (cur->index >= 0)
1296 fprintf(output, "index %d in ", cur->index);
1297 fprintf(output, "node\n");
1298 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1299 depth + 1);
1300 } else {
1301 fprintf(output, "Object is a range :\n");
1302 fprintf(output, "%s", shift);
1303 fprintf(output, "From ");
1304 if (cur->index >= 0)
1305 fprintf(output, "index %d in ", cur->index);
1306 fprintf(output, "node\n");
1307 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1308 depth + 1);
1309 fprintf(output, "%s", shift);
1310 fprintf(output, "To ");
1311 if (cur->index2 >= 0)
1312 fprintf(output, "index %d in ", cur->index2);
1313 fprintf(output, "node\n");
1314 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1315 depth + 1);
1316 fprintf(output, "\n");
1317 }
1318 break;
1319 case XPATH_LOCATIONSET:
1320 fprintf(output, "Object is a Location Set:\n");
1321 xmlXPathDebugDumpLocationSet(output,
1322 (xmlLocationSetPtr) cur->user, depth);
1323 break;
1324 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1325 case XPATH_USERS:
1326 fprintf(output, "Object is user defined\n");
1327 break;
1328 }
1329 }
1330
1331 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1332 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1333 xmlXPathStepOpPtr op, int depth) {
1334 int i;
1335 char shift[100];
1336
1337 for (i = 0;((i < depth) && (i < 25));i++)
1338 shift[2 * i] = shift[2 * i + 1] = ' ';
1339 shift[2 * i] = shift[2 * i + 1] = 0;
1340
1341 fprintf(output, "%s", shift);
1342 if (op == NULL) {
1343 fprintf(output, "Step is NULL\n");
1344 return;
1345 }
1346 switch (op->op) {
1347 case XPATH_OP_END:
1348 fprintf(output, "END"); break;
1349 case XPATH_OP_AND:
1350 fprintf(output, "AND"); break;
1351 case XPATH_OP_OR:
1352 fprintf(output, "OR"); break;
1353 case XPATH_OP_EQUAL:
1354 if (op->value)
1355 fprintf(output, "EQUAL =");
1356 else
1357 fprintf(output, "EQUAL !=");
1358 break;
1359 case XPATH_OP_CMP:
1360 if (op->value)
1361 fprintf(output, "CMP <");
1362 else
1363 fprintf(output, "CMP >");
1364 if (!op->value2)
1365 fprintf(output, "=");
1366 break;
1367 case XPATH_OP_PLUS:
1368 if (op->value == 0)
1369 fprintf(output, "PLUS -");
1370 else if (op->value == 1)
1371 fprintf(output, "PLUS +");
1372 else if (op->value == 2)
1373 fprintf(output, "PLUS unary -");
1374 else if (op->value == 3)
1375 fprintf(output, "PLUS unary - -");
1376 break;
1377 case XPATH_OP_MULT:
1378 if (op->value == 0)
1379 fprintf(output, "MULT *");
1380 else if (op->value == 1)
1381 fprintf(output, "MULT div");
1382 else
1383 fprintf(output, "MULT mod");
1384 break;
1385 case XPATH_OP_UNION:
1386 fprintf(output, "UNION"); break;
1387 case XPATH_OP_ROOT:
1388 fprintf(output, "ROOT"); break;
1389 case XPATH_OP_NODE:
1390 fprintf(output, "NODE"); break;
1391 case XPATH_OP_SORT:
1392 fprintf(output, "SORT"); break;
1393 case XPATH_OP_COLLECT: {
1394 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1395 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1396 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1397 const xmlChar *prefix = op->value4;
1398 const xmlChar *name = op->value5;
1399
1400 fprintf(output, "COLLECT ");
1401 switch (axis) {
1402 case AXIS_ANCESTOR:
1403 fprintf(output, " 'ancestors' "); break;
1404 case AXIS_ANCESTOR_OR_SELF:
1405 fprintf(output, " 'ancestors-or-self' "); break;
1406 case AXIS_ATTRIBUTE:
1407 fprintf(output, " 'attributes' "); break;
1408 case AXIS_CHILD:
1409 fprintf(output, " 'child' "); break;
1410 case AXIS_DESCENDANT:
1411 fprintf(output, " 'descendant' "); break;
1412 case AXIS_DESCENDANT_OR_SELF:
1413 fprintf(output, " 'descendant-or-self' "); break;
1414 case AXIS_FOLLOWING:
1415 fprintf(output, " 'following' "); break;
1416 case AXIS_FOLLOWING_SIBLING:
1417 fprintf(output, " 'following-siblings' "); break;
1418 case AXIS_NAMESPACE:
1419 fprintf(output, " 'namespace' "); break;
1420 case AXIS_PARENT:
1421 fprintf(output, " 'parent' "); break;
1422 case AXIS_PRECEDING:
1423 fprintf(output, " 'preceding' "); break;
1424 case AXIS_PRECEDING_SIBLING:
1425 fprintf(output, " 'preceding-sibling' "); break;
1426 case AXIS_SELF:
1427 fprintf(output, " 'self' "); break;
1428 }
1429 switch (test) {
1430 case NODE_TEST_NONE:
1431 fprintf(output, "'none' "); break;
1432 case NODE_TEST_TYPE:
1433 fprintf(output, "'type' "); break;
1434 case NODE_TEST_PI:
1435 fprintf(output, "'PI' "); break;
1436 case NODE_TEST_ALL:
1437 fprintf(output, "'all' "); break;
1438 case NODE_TEST_NS:
1439 fprintf(output, "'namespace' "); break;
1440 case NODE_TEST_NAME:
1441 fprintf(output, "'name' "); break;
1442 }
1443 switch (type) {
1444 case NODE_TYPE_NODE:
1445 fprintf(output, "'node' "); break;
1446 case NODE_TYPE_COMMENT:
1447 fprintf(output, "'comment' "); break;
1448 case NODE_TYPE_TEXT:
1449 fprintf(output, "'text' "); break;
1450 case NODE_TYPE_PI:
1451 fprintf(output, "'PI' "); break;
1452 }
1453 if (prefix != NULL)
1454 fprintf(output, "%s:", prefix);
1455 if (name != NULL)
1456 fprintf(output, "%s", (const char *) name);
1457 break;
1458
1459 }
1460 case XPATH_OP_VALUE: {
1461 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1462
1463 fprintf(output, "ELEM ");
1464 xmlXPathDebugDumpObject(output, object, 0);
1465 goto finish;
1466 }
1467 case XPATH_OP_VARIABLE: {
1468 const xmlChar *prefix = op->value5;
1469 const xmlChar *name = op->value4;
1470
1471 if (prefix != NULL)
1472 fprintf(output, "VARIABLE %s:%s", prefix, name);
1473 else
1474 fprintf(output, "VARIABLE %s", name);
1475 break;
1476 }
1477 case XPATH_OP_FUNCTION: {
1478 int nbargs = op->value;
1479 const xmlChar *prefix = op->value5;
1480 const xmlChar *name = op->value4;
1481
1482 if (prefix != NULL)
1483 fprintf(output, "FUNCTION %s:%s(%d args)",
1484 prefix, name, nbargs);
1485 else
1486 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1487 break;
1488 }
1489 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1490 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1491 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1492 #ifdef LIBXML_XPTR_LOCS_ENABLED
1493 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1494 #endif
1495 default:
1496 fprintf(output, "UNKNOWN %d\n", op->op); return;
1497 }
1498 fprintf(output, "\n");
1499 finish:
1500 if (op->ch1 >= 0)
1501 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1502 if (op->ch2 >= 0)
1503 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1504 }
1505
1506 /**
1507 * xmlXPathDebugDumpCompExpr:
1508 * @output: the FILE * for the output
1509 * @comp: the precompiled XPath expression
1510 * @depth: the indentation level.
1511 *
1512 * Dumps the tree of the compiled XPath expression.
1513 */
1514 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1515 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1516 int depth) {
1517 int i;
1518 char shift[100];
1519
1520 if ((output == NULL) || (comp == NULL)) return;
1521
1522 for (i = 0;((i < depth) && (i < 25));i++)
1523 shift[2 * i] = shift[2 * i + 1] = ' ';
1524 shift[2 * i] = shift[2 * i + 1] = 0;
1525
1526 fprintf(output, "%s", shift);
1527
1528 #ifdef XPATH_STREAMING
1529 if (comp->stream) {
1530 fprintf(output, "Streaming Expression\n");
1531 } else
1532 #endif
1533 {
1534 fprintf(output, "Compiled Expression : %d elements\n",
1535 comp->nbStep);
1536 i = comp->last;
1537 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1538 }
1539 }
1540
1541 #endif /* LIBXML_DEBUG_ENABLED */
1542
1543 /************************************************************************
1544 * *
1545 * XPath object caching *
1546 * *
1547 ************************************************************************/
1548
1549 /**
1550 * xmlXPathNewCache:
1551 *
1552 * Create a new object cache
1553 *
1554 * Returns the xmlXPathCache just allocated.
1555 */
1556 static xmlXPathContextCachePtr
xmlXPathNewCache(void)1557 xmlXPathNewCache(void)
1558 {
1559 xmlXPathContextCachePtr ret;
1560
1561 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1562 if (ret == NULL)
1563 return(NULL);
1564 memset(ret, 0 , sizeof(xmlXPathContextCache));
1565 ret->maxNodeset = 100;
1566 ret->maxMisc = 100;
1567 return(ret);
1568 }
1569
1570 static void
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)1571 xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1572 {
1573 while (list != NULL) {
1574 xmlXPathObjectPtr next;
1575
1576 next = (void *) list->stringval;
1577
1578 if (list->nodesetval != NULL) {
1579 if (list->nodesetval->nodeTab != NULL)
1580 xmlFree(list->nodesetval->nodeTab);
1581 xmlFree(list->nodesetval);
1582 }
1583 xmlFree(list);
1584
1585 list = next;
1586 }
1587 }
1588
1589 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)1590 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1591 {
1592 if (cache == NULL)
1593 return;
1594 if (cache->nodesetObjs)
1595 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1596 if (cache->miscObjs)
1597 xmlXPathCacheFreeObjectList(cache->miscObjs);
1598 xmlFree(cache);
1599 }
1600
1601 /**
1602 * xmlXPathContextSetCache:
1603 *
1604 * @ctxt: the XPath context
1605 * @active: enables/disables (creates/frees) the cache
1606 * @value: a value with semantics dependent on @options
1607 * @options: options (currently only the value 0 is used)
1608 *
1609 * Creates/frees an object cache on the XPath context.
1610 * If activates XPath objects (xmlXPathObject) will be cached internally
1611 * to be reused.
1612 * @options:
1613 * 0: This will set the XPath object caching:
1614 * @value:
1615 * This will set the maximum number of XPath objects
1616 * to be cached per slot
1617 * There are two slots for node-set and misc objects.
1618 * Use <0 for the default number (100).
1619 * Other values for @options have currently no effect.
1620 *
1621 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1622 */
1623 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)1624 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1625 int active,
1626 int value,
1627 int options)
1628 {
1629 if (ctxt == NULL)
1630 return(-1);
1631 if (active) {
1632 xmlXPathContextCachePtr cache;
1633
1634 if (ctxt->cache == NULL) {
1635 ctxt->cache = xmlXPathNewCache();
1636 if (ctxt->cache == NULL) {
1637 xmlXPathErrMemory(ctxt);
1638 return(-1);
1639 }
1640 }
1641 cache = (xmlXPathContextCachePtr) ctxt->cache;
1642 if (options == 0) {
1643 if (value < 0)
1644 value = 100;
1645 cache->maxNodeset = value;
1646 cache->maxMisc = value;
1647 }
1648 } else if (ctxt->cache != NULL) {
1649 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1650 ctxt->cache = NULL;
1651 }
1652 return(0);
1653 }
1654
1655 /**
1656 * xmlXPathCacheWrapNodeSet:
1657 * @pctxt: the XPath context
1658 * @val: the NodePtr value
1659 *
1660 * This is the cached version of xmlXPathWrapNodeSet().
1661 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1662 *
1663 * Returns the created or reused object.
1664 *
1665 * In case of error the node set is destroyed and NULL is returned.
1666 */
1667 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt,xmlNodeSetPtr val)1668 xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1669 {
1670 xmlXPathObjectPtr ret;
1671 xmlXPathContextPtr ctxt = pctxt->context;
1672
1673 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1674 xmlXPathContextCachePtr cache =
1675 (xmlXPathContextCachePtr) ctxt->cache;
1676
1677 if (cache->miscObjs != NULL) {
1678 ret = cache->miscObjs;
1679 cache->miscObjs = (void *) ret->stringval;
1680 cache->numMisc -= 1;
1681 ret->stringval = NULL;
1682 ret->type = XPATH_NODESET;
1683 ret->nodesetval = val;
1684 return(ret);
1685 }
1686 }
1687
1688 ret = xmlXPathWrapNodeSet(val);
1689 if (ret == NULL)
1690 xmlXPathPErrMemory(pctxt);
1691 return(ret);
1692 }
1693
1694 /**
1695 * xmlXPathCacheWrapString:
1696 * @pctxt the XPath context
1697 * @val: the xmlChar * value
1698 *
1699 * This is the cached version of xmlXPathWrapString().
1700 * Wraps the @val string into an XPath object.
1701 *
1702 * Returns the created or reused object.
1703 */
1704 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt,xmlChar * val)1705 xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1706 {
1707 xmlXPathObjectPtr ret;
1708 xmlXPathContextPtr ctxt = pctxt->context;
1709
1710 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1711 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1712
1713 if (cache->miscObjs != NULL) {
1714 ret = cache->miscObjs;
1715 cache->miscObjs = (void *) ret->stringval;
1716 cache->numMisc -= 1;
1717 ret->type = XPATH_STRING;
1718 ret->stringval = val;
1719 return(ret);
1720 }
1721 }
1722
1723 ret = xmlXPathWrapString(val);
1724 if (ret == NULL)
1725 xmlXPathPErrMemory(pctxt);
1726 return(ret);
1727 }
1728
1729 /**
1730 * xmlXPathCacheNewNodeSet:
1731 * @pctxt the XPath context
1732 * @val: the NodePtr value
1733 *
1734 * This is the cached version of xmlXPathNewNodeSet().
1735 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1736 * it with the single Node @val
1737 *
1738 * Returns the created or reused object.
1739 */
1740 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt,xmlNodePtr val)1741 xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1742 {
1743 xmlXPathObjectPtr ret;
1744 xmlXPathContextPtr ctxt = pctxt->context;
1745
1746 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1747 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1748
1749 if (cache->nodesetObjs != NULL) {
1750 /*
1751 * Use the nodeset-cache.
1752 */
1753 ret = cache->nodesetObjs;
1754 cache->nodesetObjs = (void *) ret->stringval;
1755 cache->numNodeset -= 1;
1756 ret->stringval = NULL;
1757 ret->type = XPATH_NODESET;
1758 ret->boolval = 0;
1759 if (val) {
1760 if ((ret->nodesetval->nodeMax == 0) ||
1761 (val->type == XML_NAMESPACE_DECL))
1762 {
1763 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1764 xmlXPathPErrMemory(pctxt);
1765 } else {
1766 ret->nodesetval->nodeTab[0] = val;
1767 ret->nodesetval->nodeNr = 1;
1768 }
1769 }
1770 return(ret);
1771 } else if (cache->miscObjs != NULL) {
1772 xmlNodeSetPtr set;
1773 /*
1774 * Fallback to misc-cache.
1775 */
1776
1777 set = xmlXPathNodeSetCreate(val);
1778 if (set == NULL) {
1779 xmlXPathPErrMemory(pctxt);
1780 return(NULL);
1781 }
1782
1783 ret = cache->miscObjs;
1784 cache->miscObjs = (void *) ret->stringval;
1785 cache->numMisc -= 1;
1786 ret->stringval = NULL;
1787 ret->type = XPATH_NODESET;
1788 ret->boolval = 0;
1789 ret->nodesetval = set;
1790 return(ret);
1791 }
1792 }
1793 ret = xmlXPathNewNodeSet(val);
1794 if (ret == NULL)
1795 xmlXPathPErrMemory(pctxt);
1796 return(ret);
1797 }
1798
1799 /**
1800 * xmlXPathCacheNewString:
1801 * @pctxt the XPath context
1802 * @val: the xmlChar * value
1803 *
1804 * This is the cached version of xmlXPathNewString().
1805 * Acquire an xmlXPathObjectPtr of type string and of value @val
1806 *
1807 * Returns the created or reused object.
1808 */
1809 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt,const xmlChar * val)1810 xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1811 {
1812 xmlXPathObjectPtr ret;
1813 xmlXPathContextPtr ctxt = pctxt->context;
1814
1815 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1816 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1817
1818 if (cache->miscObjs != NULL) {
1819 xmlChar *copy;
1820
1821 if (val == NULL)
1822 val = BAD_CAST "";
1823 copy = xmlStrdup(val);
1824 if (copy == NULL) {
1825 xmlXPathPErrMemory(pctxt);
1826 return(NULL);
1827 }
1828
1829 ret = cache->miscObjs;
1830 cache->miscObjs = (void *) ret->stringval;
1831 cache->numMisc -= 1;
1832 ret->type = XPATH_STRING;
1833 ret->stringval = copy;
1834 return(ret);
1835 }
1836 }
1837
1838 ret = xmlXPathNewString(val);
1839 if (ret == NULL)
1840 xmlXPathPErrMemory(pctxt);
1841 return(ret);
1842 }
1843
1844 /**
1845 * xmlXPathCacheNewCString:
1846 * @pctxt the XPath context
1847 * @val: the char * value
1848 *
1849 * This is the cached version of xmlXPathNewCString().
1850 * Acquire an xmlXPathObjectPtr of type string and of value @val
1851 *
1852 * Returns the created or reused object.
1853 */
1854 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt,const char * val)1855 xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1856 {
1857 return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1858 }
1859
1860 /**
1861 * xmlXPathCacheNewBoolean:
1862 * @pctxt the XPath context
1863 * @val: the boolean value
1864 *
1865 * This is the cached version of xmlXPathNewBoolean().
1866 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1867 *
1868 * Returns the created or reused object.
1869 */
1870 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt,int val)1871 xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1872 {
1873 xmlXPathObjectPtr ret;
1874 xmlXPathContextPtr ctxt = pctxt->context;
1875
1876 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1877 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1878
1879 if (cache->miscObjs != NULL) {
1880 ret = cache->miscObjs;
1881 cache->miscObjs = (void *) ret->stringval;
1882 cache->numMisc -= 1;
1883 ret->stringval = NULL;
1884 ret->type = XPATH_BOOLEAN;
1885 ret->boolval = (val != 0);
1886 return(ret);
1887 }
1888 }
1889
1890 ret = xmlXPathNewBoolean(val);
1891 if (ret == NULL)
1892 xmlXPathPErrMemory(pctxt);
1893 return(ret);
1894 }
1895
1896 /**
1897 * xmlXPathCacheNewFloat:
1898 * @pctxt the XPath context
1899 * @val: the double value
1900 *
1901 * This is the cached version of xmlXPathNewFloat().
1902 * Acquires an xmlXPathObjectPtr of type double and of value @val
1903 *
1904 * Returns the created or reused object.
1905 */
1906 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt,double val)1907 xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1908 {
1909 xmlXPathObjectPtr ret;
1910 xmlXPathContextPtr ctxt = pctxt->context;
1911
1912 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1913 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1914
1915 if (cache->miscObjs != NULL) {
1916 ret = cache->miscObjs;
1917 cache->miscObjs = (void *) ret->stringval;
1918 cache->numMisc -= 1;
1919 ret->stringval = NULL;
1920 ret->type = XPATH_NUMBER;
1921 ret->floatval = val;
1922 return(ret);
1923 }
1924 }
1925
1926 ret = xmlXPathNewFloat(val);
1927 if (ret == NULL)
1928 xmlXPathPErrMemory(pctxt);
1929 return(ret);
1930 }
1931
1932 /**
1933 * xmlXPathCacheObjectCopy:
1934 * @pctxt the XPath context
1935 * @val: the original object
1936 *
1937 * This is the cached version of xmlXPathObjectCopy().
1938 * Acquire a copy of a given object
1939 *
1940 * Returns a created or reused created object.
1941 */
1942 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt,xmlXPathObjectPtr val)1943 xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1944 {
1945 xmlXPathObjectPtr ret;
1946 xmlXPathContextPtr ctxt = pctxt->context;
1947
1948 if (val == NULL)
1949 return(NULL);
1950
1951 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1952 switch (val->type) {
1953 case XPATH_NODESET: {
1954 xmlNodeSetPtr set;
1955
1956 set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1957 if (set == NULL) {
1958 xmlXPathPErrMemory(pctxt);
1959 return(NULL);
1960 }
1961 return(xmlXPathCacheWrapNodeSet(pctxt, set));
1962 }
1963 case XPATH_STRING:
1964 return(xmlXPathCacheNewString(pctxt, val->stringval));
1965 case XPATH_BOOLEAN:
1966 return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1967 case XPATH_NUMBER:
1968 return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1969 default:
1970 break;
1971 }
1972 }
1973 ret = xmlXPathObjectCopy(val);
1974 if (ret == NULL)
1975 xmlXPathPErrMemory(pctxt);
1976 return(ret);
1977 }
1978
1979 /************************************************************************
1980 * *
1981 * Parser stacks related functions and macros *
1982 * *
1983 ************************************************************************/
1984
1985 /**
1986 * xmlXPathCastToNumberInternal:
1987 * @ctxt: parser context
1988 * @val: an XPath object
1989 *
1990 * Converts an XPath object to its number value
1991 *
1992 * Returns the number value
1993 */
1994 static double
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr val)1995 xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1996 xmlXPathObjectPtr val) {
1997 double ret = 0.0;
1998
1999 if (val == NULL)
2000 return(xmlXPathNAN);
2001 switch (val->type) {
2002 case XPATH_UNDEFINED:
2003 ret = xmlXPathNAN;
2004 break;
2005 case XPATH_NODESET:
2006 case XPATH_XSLT_TREE: {
2007 xmlChar *str;
2008
2009 str = xmlXPathCastNodeSetToString(val->nodesetval);
2010 if (str == NULL) {
2011 xmlXPathPErrMemory(ctxt);
2012 ret = xmlXPathNAN;
2013 } else {
2014 ret = xmlXPathCastStringToNumber(str);
2015 xmlFree(str);
2016 }
2017 break;
2018 }
2019 case XPATH_STRING:
2020 ret = xmlXPathCastStringToNumber(val->stringval);
2021 break;
2022 case XPATH_NUMBER:
2023 ret = val->floatval;
2024 break;
2025 case XPATH_BOOLEAN:
2026 ret = xmlXPathCastBooleanToNumber(val->boolval);
2027 break;
2028 case XPATH_USERS:
2029 #ifdef LIBXML_XPTR_LOCS_ENABLED
2030 case XPATH_POINT:
2031 case XPATH_RANGE:
2032 case XPATH_LOCATIONSET:
2033 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2034 /* TODO */
2035 ret = xmlXPathNAN;
2036 break;
2037 }
2038 return(ret);
2039 }
2040
2041 /**
2042 * valuePop:
2043 * @ctxt: an XPath evaluation context
2044 *
2045 * Pops the top XPath object from the value stack
2046 *
2047 * Returns the XPath object just removed
2048 */
2049 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2050 valuePop(xmlXPathParserContextPtr ctxt)
2051 {
2052 xmlXPathObjectPtr ret;
2053
2054 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2055 return (NULL);
2056
2057 ctxt->valueNr--;
2058 if (ctxt->valueNr > 0)
2059 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2060 else
2061 ctxt->value = NULL;
2062 ret = ctxt->valueTab[ctxt->valueNr];
2063 ctxt->valueTab[ctxt->valueNr] = NULL;
2064 return (ret);
2065 }
2066 /**
2067 * valuePush:
2068 * @ctxt: an XPath evaluation context
2069 * @value: the XPath object
2070 *
2071 * Pushes a new XPath object on top of the value stack. If value is NULL,
2072 * a memory error is recorded in the parser context.
2073 *
2074 * Returns the number of items on the value stack, or -1 in case of error.
2075 *
2076 * The object is destroyed in case of error.
2077 */
2078 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2079 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2080 {
2081 if (ctxt == NULL) return(-1);
2082 if (value == NULL) {
2083 /*
2084 * A NULL value typically indicates that a memory allocation failed.
2085 */
2086 xmlXPathPErrMemory(ctxt);
2087 return(-1);
2088 }
2089 if (ctxt->valueNr >= ctxt->valueMax) {
2090 xmlXPathObjectPtr *tmp;
2091
2092 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2093 xmlXPathPErrMemory(ctxt);
2094 xmlXPathFreeObject(value);
2095 return (-1);
2096 }
2097 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2098 2 * ctxt->valueMax *
2099 sizeof(ctxt->valueTab[0]));
2100 if (tmp == NULL) {
2101 xmlXPathPErrMemory(ctxt);
2102 xmlXPathFreeObject(value);
2103 return (-1);
2104 }
2105 ctxt->valueMax *= 2;
2106 ctxt->valueTab = tmp;
2107 }
2108 ctxt->valueTab[ctxt->valueNr] = value;
2109 ctxt->value = value;
2110 return (ctxt->valueNr++);
2111 }
2112
2113 /**
2114 * xmlXPathPopBoolean:
2115 * @ctxt: an XPath parser context
2116 *
2117 * Pops a boolean from the stack, handling conversion if needed.
2118 * Check error with #xmlXPathCheckError.
2119 *
2120 * Returns the boolean
2121 */
2122 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2123 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2124 xmlXPathObjectPtr obj;
2125 int ret;
2126
2127 obj = valuePop(ctxt);
2128 if (obj == NULL) {
2129 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2130 return(0);
2131 }
2132 if (obj->type != XPATH_BOOLEAN)
2133 ret = xmlXPathCastToBoolean(obj);
2134 else
2135 ret = obj->boolval;
2136 xmlXPathReleaseObject(ctxt->context, obj);
2137 return(ret);
2138 }
2139
2140 /**
2141 * xmlXPathPopNumber:
2142 * @ctxt: an XPath parser context
2143 *
2144 * Pops a number from the stack, handling conversion if needed.
2145 * Check error with #xmlXPathCheckError.
2146 *
2147 * Returns the number
2148 */
2149 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2150 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2151 xmlXPathObjectPtr obj;
2152 double ret;
2153
2154 obj = valuePop(ctxt);
2155 if (obj == NULL) {
2156 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2157 return(0);
2158 }
2159 if (obj->type != XPATH_NUMBER)
2160 ret = xmlXPathCastToNumberInternal(ctxt, obj);
2161 else
2162 ret = obj->floatval;
2163 xmlXPathReleaseObject(ctxt->context, obj);
2164 return(ret);
2165 }
2166
2167 /**
2168 * xmlXPathPopString:
2169 * @ctxt: an XPath parser context
2170 *
2171 * Pops a string from the stack, handling conversion if needed.
2172 * Check error with #xmlXPathCheckError.
2173 *
2174 * Returns the string
2175 */
2176 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2177 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2178 xmlXPathObjectPtr obj;
2179 xmlChar * ret;
2180
2181 obj = valuePop(ctxt);
2182 if (obj == NULL) {
2183 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2184 return(NULL);
2185 }
2186 ret = xmlXPathCastToString(obj);
2187 if (ret == NULL)
2188 xmlXPathPErrMemory(ctxt);
2189 xmlXPathReleaseObject(ctxt->context, obj);
2190 return(ret);
2191 }
2192
2193 /**
2194 * xmlXPathPopNodeSet:
2195 * @ctxt: an XPath parser context
2196 *
2197 * Pops a node-set from the stack, handling conversion if needed.
2198 * Check error with #xmlXPathCheckError.
2199 *
2200 * Returns the node-set
2201 */
2202 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2203 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2204 xmlXPathObjectPtr obj;
2205 xmlNodeSetPtr ret;
2206
2207 if (ctxt == NULL) return(NULL);
2208 if (ctxt->value == NULL) {
2209 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2210 return(NULL);
2211 }
2212 if (!xmlXPathStackIsNodeSet(ctxt)) {
2213 xmlXPathSetTypeError(ctxt);
2214 return(NULL);
2215 }
2216 obj = valuePop(ctxt);
2217 ret = obj->nodesetval;
2218 #if 0
2219 /* to fix memory leak of not clearing obj->user */
2220 if (obj->boolval && obj->user != NULL)
2221 xmlFreeNodeList((xmlNodePtr) obj->user);
2222 #endif
2223 obj->nodesetval = NULL;
2224 xmlXPathReleaseObject(ctxt->context, obj);
2225 return(ret);
2226 }
2227
2228 /**
2229 * xmlXPathPopExternal:
2230 * @ctxt: an XPath parser context
2231 *
2232 * Pops an external object from the stack, handling conversion if needed.
2233 * Check error with #xmlXPathCheckError.
2234 *
2235 * Returns the object
2236 */
2237 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)2238 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2239 xmlXPathObjectPtr obj;
2240 void * ret;
2241
2242 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2243 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2244 return(NULL);
2245 }
2246 if (ctxt->value->type != XPATH_USERS) {
2247 xmlXPathSetTypeError(ctxt);
2248 return(NULL);
2249 }
2250 obj = valuePop(ctxt);
2251 ret = obj->user;
2252 obj->user = NULL;
2253 xmlXPathReleaseObject(ctxt->context, obj);
2254 return(ret);
2255 }
2256
2257 /*
2258 * Macros for accessing the content. Those should be used only by the parser,
2259 * and not exported.
2260 *
2261 * Dirty macros, i.e. one need to make assumption on the context to use them
2262 *
2263 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2264 * CUR returns the current xmlChar value, i.e. a 8 bit value
2265 * in ISO-Latin or UTF-8.
2266 * This should be used internally by the parser
2267 * only to compare to ASCII values otherwise it would break when
2268 * running with UTF-8 encoding.
2269 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2270 * to compare on ASCII based substring.
2271 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2272 * strings within the parser.
2273 * CURRENT Returns the current char value, with the full decoding of
2274 * UTF-8 if we are using this mode. It returns an int.
2275 * NEXT Skip to the next character, this does the proper decoding
2276 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2277 * It returns the pointer to the current xmlChar.
2278 */
2279
2280 #define CUR (*ctxt->cur)
2281 #define SKIP(val) ctxt->cur += (val)
2282 #define NXT(val) ctxt->cur[(val)]
2283 #define CUR_PTR ctxt->cur
2284 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2285
2286 #define COPY_BUF(l,b,i,v) \
2287 if (l == 1) b[i++] = v; \
2288 else i += xmlCopyChar(l,&b[i],v)
2289
2290 #define NEXTL(l) ctxt->cur += l
2291
2292 #define SKIP_BLANKS \
2293 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2294
2295 #define CURRENT (*ctxt->cur)
2296 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2297
2298
2299 #ifndef DBL_DIG
2300 #define DBL_DIG 16
2301 #endif
2302 #ifndef DBL_EPSILON
2303 #define DBL_EPSILON 1E-9
2304 #endif
2305
2306 #define UPPER_DOUBLE 1E9
2307 #define LOWER_DOUBLE 1E-5
2308 #define LOWER_DOUBLE_EXP 5
2309
2310 #define INTEGER_DIGITS DBL_DIG
2311 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2312 #define EXPONENT_DIGITS (3 + 2)
2313
2314 /**
2315 * xmlXPathFormatNumber:
2316 * @number: number to format
2317 * @buffer: output buffer
2318 * @buffersize: size of output buffer
2319 *
2320 * Convert the number into a string representation.
2321 */
2322 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)2323 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2324 {
2325 switch (xmlXPathIsInf(number)) {
2326 case 1:
2327 if (buffersize > (int)sizeof("Infinity"))
2328 snprintf(buffer, buffersize, "Infinity");
2329 break;
2330 case -1:
2331 if (buffersize > (int)sizeof("-Infinity"))
2332 snprintf(buffer, buffersize, "-Infinity");
2333 break;
2334 default:
2335 if (xmlXPathIsNaN(number)) {
2336 if (buffersize > (int)sizeof("NaN"))
2337 snprintf(buffer, buffersize, "NaN");
2338 } else if (number == 0) {
2339 /* Omit sign for negative zero. */
2340 snprintf(buffer, buffersize, "0");
2341 } else if ((number > INT_MIN) && (number < INT_MAX) &&
2342 (number == (int) number)) {
2343 char work[30];
2344 char *ptr, *cur;
2345 int value = (int) number;
2346
2347 ptr = &buffer[0];
2348 if (value == 0) {
2349 *ptr++ = '0';
2350 } else {
2351 snprintf(work, 29, "%d", value);
2352 cur = &work[0];
2353 while ((*cur) && (ptr - buffer < buffersize)) {
2354 *ptr++ = *cur++;
2355 }
2356 }
2357 if (ptr - buffer < buffersize) {
2358 *ptr = 0;
2359 } else if (buffersize > 0) {
2360 ptr--;
2361 *ptr = 0;
2362 }
2363 } else {
2364 /*
2365 For the dimension of work,
2366 DBL_DIG is number of significant digits
2367 EXPONENT is only needed for "scientific notation"
2368 3 is sign, decimal point, and terminating zero
2369 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2370 Note that this dimension is slightly (a few characters)
2371 larger than actually necessary.
2372 */
2373 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2374 int integer_place, fraction_place;
2375 char *ptr;
2376 char *after_fraction;
2377 double absolute_value;
2378 int size;
2379
2380 absolute_value = fabs(number);
2381
2382 /*
2383 * First choose format - scientific or regular floating point.
2384 * In either case, result is in work, and after_fraction points
2385 * just past the fractional part.
2386 */
2387 if ( ((absolute_value > UPPER_DOUBLE) ||
2388 (absolute_value < LOWER_DOUBLE)) &&
2389 (absolute_value != 0.0) ) {
2390 /* Use scientific notation */
2391 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2392 fraction_place = DBL_DIG - 1;
2393 size = snprintf(work, sizeof(work),"%*.*e",
2394 integer_place, fraction_place, number);
2395 while ((size > 0) && (work[size] != 'e')) size--;
2396
2397 }
2398 else {
2399 /* Use regular notation */
2400 if (absolute_value > 0.0) {
2401 integer_place = (int)log10(absolute_value);
2402 if (integer_place > 0)
2403 fraction_place = DBL_DIG - integer_place - 1;
2404 else
2405 fraction_place = DBL_DIG - integer_place;
2406 } else {
2407 fraction_place = 1;
2408 }
2409 size = snprintf(work, sizeof(work), "%0.*f",
2410 fraction_place, number);
2411 }
2412
2413 /* Remove leading spaces sometimes inserted by snprintf */
2414 while (work[0] == ' ') {
2415 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2416 size--;
2417 }
2418
2419 /* Remove fractional trailing zeroes */
2420 after_fraction = work + size;
2421 ptr = after_fraction;
2422 while (*(--ptr) == '0')
2423 ;
2424 if (*ptr != '.')
2425 ptr++;
2426 while ((*ptr++ = *after_fraction++) != 0);
2427
2428 /* Finally copy result back to caller */
2429 size = strlen(work) + 1;
2430 if (size > buffersize) {
2431 work[buffersize - 1] = 0;
2432 size = buffersize;
2433 }
2434 memmove(buffer, work, size);
2435 }
2436 break;
2437 }
2438 }
2439
2440
2441 /************************************************************************
2442 * *
2443 * Routines to handle NodeSets *
2444 * *
2445 ************************************************************************/
2446
2447 /**
2448 * xmlXPathOrderDocElems:
2449 * @doc: an input document
2450 *
2451 * Call this routine to speed up XPath computation on static documents.
2452 * This stamps all the element nodes with the document order
2453 * Like for line information, the order is kept in the element->content
2454 * field, the value stored is actually - the node number (starting at -1)
2455 * to be able to differentiate from line numbers.
2456 *
2457 * Returns the number of elements found in the document or -1 in case
2458 * of error.
2459 */
2460 long
xmlXPathOrderDocElems(xmlDocPtr doc)2461 xmlXPathOrderDocElems(xmlDocPtr doc) {
2462 ptrdiff_t count = 0;
2463 xmlNodePtr cur;
2464
2465 if (doc == NULL)
2466 return(-1);
2467 cur = doc->children;
2468 while (cur != NULL) {
2469 if (cur->type == XML_ELEMENT_NODE) {
2470 cur->content = (void *) (-(++count));
2471 if (cur->children != NULL) {
2472 cur = cur->children;
2473 continue;
2474 }
2475 }
2476 if (cur->next != NULL) {
2477 cur = cur->next;
2478 continue;
2479 }
2480 do {
2481 cur = cur->parent;
2482 if (cur == NULL)
2483 break;
2484 if (cur == (xmlNodePtr) doc) {
2485 cur = NULL;
2486 break;
2487 }
2488 if (cur->next != NULL) {
2489 cur = cur->next;
2490 break;
2491 }
2492 } while (cur != NULL);
2493 }
2494 return(count);
2495 }
2496
2497 /**
2498 * xmlXPathCmpNodes:
2499 * @node1: the first node
2500 * @node2: the second node
2501 *
2502 * Compare two nodes w.r.t document order
2503 *
2504 * Returns -2 in case of error 1 if first point < second point, 0 if
2505 * it's the same node, -1 otherwise
2506 */
2507 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)2508 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2509 int depth1, depth2;
2510 int attr1 = 0, attr2 = 0;
2511 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2512 xmlNodePtr cur, root;
2513
2514 if ((node1 == NULL) || (node2 == NULL))
2515 return(-2);
2516 /*
2517 * a couple of optimizations which will avoid computations in most cases
2518 */
2519 if (node1 == node2) /* trivial case */
2520 return(0);
2521 if (node1->type == XML_ATTRIBUTE_NODE) {
2522 attr1 = 1;
2523 attrNode1 = node1;
2524 node1 = node1->parent;
2525 }
2526 if (node2->type == XML_ATTRIBUTE_NODE) {
2527 attr2 = 1;
2528 attrNode2 = node2;
2529 node2 = node2->parent;
2530 }
2531 if (node1 == node2) {
2532 if (attr1 == attr2) {
2533 /* not required, but we keep attributes in order */
2534 if (attr1 != 0) {
2535 cur = attrNode2->prev;
2536 while (cur != NULL) {
2537 if (cur == attrNode1)
2538 return (1);
2539 cur = cur->prev;
2540 }
2541 return (-1);
2542 }
2543 return(0);
2544 }
2545 if (attr2 == 1)
2546 return(1);
2547 return(-1);
2548 }
2549 if ((node1->type == XML_NAMESPACE_DECL) ||
2550 (node2->type == XML_NAMESPACE_DECL))
2551 return(1);
2552 if (node1 == node2->prev)
2553 return(1);
2554 if (node1 == node2->next)
2555 return(-1);
2556
2557 /*
2558 * Speedup using document order if available.
2559 */
2560 if ((node1->type == XML_ELEMENT_NODE) &&
2561 (node2->type == XML_ELEMENT_NODE) &&
2562 (0 > (ptrdiff_t) node1->content) &&
2563 (0 > (ptrdiff_t) node2->content) &&
2564 (node1->doc == node2->doc)) {
2565 ptrdiff_t l1, l2;
2566
2567 l1 = -((ptrdiff_t) node1->content);
2568 l2 = -((ptrdiff_t) node2->content);
2569 if (l1 < l2)
2570 return(1);
2571 if (l1 > l2)
2572 return(-1);
2573 }
2574
2575 /*
2576 * compute depth to root
2577 */
2578 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2579 if (cur->parent == node1)
2580 return(1);
2581 depth2++;
2582 }
2583 root = cur;
2584 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2585 if (cur->parent == node2)
2586 return(-1);
2587 depth1++;
2588 }
2589 /*
2590 * Distinct document (or distinct entities :-( ) case.
2591 */
2592 if (root != cur) {
2593 return(-2);
2594 }
2595 /*
2596 * get the nearest common ancestor.
2597 */
2598 while (depth1 > depth2) {
2599 depth1--;
2600 node1 = node1->parent;
2601 }
2602 while (depth2 > depth1) {
2603 depth2--;
2604 node2 = node2->parent;
2605 }
2606 while (node1->parent != node2->parent) {
2607 node1 = node1->parent;
2608 node2 = node2->parent;
2609 /* should not happen but just in case ... */
2610 if ((node1 == NULL) || (node2 == NULL))
2611 return(-2);
2612 }
2613 /*
2614 * Find who's first.
2615 */
2616 if (node1 == node2->prev)
2617 return(1);
2618 if (node1 == node2->next)
2619 return(-1);
2620 /*
2621 * Speedup using document order if available.
2622 */
2623 if ((node1->type == XML_ELEMENT_NODE) &&
2624 (node2->type == XML_ELEMENT_NODE) &&
2625 (0 > (ptrdiff_t) node1->content) &&
2626 (0 > (ptrdiff_t) node2->content) &&
2627 (node1->doc == node2->doc)) {
2628 ptrdiff_t l1, l2;
2629
2630 l1 = -((ptrdiff_t) node1->content);
2631 l2 = -((ptrdiff_t) node2->content);
2632 if (l1 < l2)
2633 return(1);
2634 if (l1 > l2)
2635 return(-1);
2636 }
2637
2638 for (cur = node1->next;cur != NULL;cur = cur->next)
2639 if (cur == node2)
2640 return(1);
2641 return(-1); /* assume there is no sibling list corruption */
2642 }
2643
2644 /**
2645 * xmlXPathNodeSetSort:
2646 * @set: the node set
2647 *
2648 * Sort the node set in document order
2649 */
2650 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)2651 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2652 #ifndef WITH_TIM_SORT
2653 int i, j, incr, len;
2654 xmlNodePtr tmp;
2655 #endif
2656
2657 if (set == NULL)
2658 return;
2659
2660 #ifndef WITH_TIM_SORT
2661 /*
2662 * Use the old Shell's sort implementation to sort the node-set
2663 * Timsort ought to be quite faster
2664 */
2665 len = set->nodeNr;
2666 for (incr = len / 2; incr > 0; incr /= 2) {
2667 for (i = incr; i < len; i++) {
2668 j = i - incr;
2669 while (j >= 0) {
2670 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2671 if (xmlXPathCmpNodesExt(set->nodeTab[j],
2672 set->nodeTab[j + incr]) == -1)
2673 #else
2674 if (xmlXPathCmpNodes(set->nodeTab[j],
2675 set->nodeTab[j + incr]) == -1)
2676 #endif
2677 {
2678 tmp = set->nodeTab[j];
2679 set->nodeTab[j] = set->nodeTab[j + incr];
2680 set->nodeTab[j + incr] = tmp;
2681 j -= incr;
2682 } else
2683 break;
2684 }
2685 }
2686 }
2687 #else /* WITH_TIM_SORT */
2688 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2689 #endif /* WITH_TIM_SORT */
2690 }
2691
2692 #define XML_NODESET_DEFAULT 10
2693 /**
2694 * xmlXPathNodeSetDupNs:
2695 * @node: the parent node of the namespace XPath node
2696 * @ns: the libxml namespace declaration node.
2697 *
2698 * Namespace node in libxml don't match the XPath semantic. In a node set
2699 * the namespace nodes are duplicated and the next pointer is set to the
2700 * parent node in the XPath semantic.
2701 *
2702 * Returns the newly created object.
2703 */
2704 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)2705 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2706 xmlNsPtr cur;
2707
2708 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2709 return(NULL);
2710 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2711 return((xmlNodePtr) ns);
2712
2713 /*
2714 * Allocate a new Namespace and fill the fields.
2715 */
2716 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2717 if (cur == NULL)
2718 return(NULL);
2719 memset(cur, 0, sizeof(xmlNs));
2720 cur->type = XML_NAMESPACE_DECL;
2721 if (ns->href != NULL) {
2722 cur->href = xmlStrdup(ns->href);
2723 if (cur->href == NULL) {
2724 xmlFree(cur);
2725 return(NULL);
2726 }
2727 }
2728 if (ns->prefix != NULL) {
2729 cur->prefix = xmlStrdup(ns->prefix);
2730 if (cur->prefix == NULL) {
2731 xmlFree((xmlChar *) cur->href);
2732 xmlFree(cur);
2733 return(NULL);
2734 }
2735 }
2736 cur->next = (xmlNsPtr) node;
2737 return((xmlNodePtr) cur);
2738 }
2739
2740 /**
2741 * xmlXPathNodeSetFreeNs:
2742 * @ns: the XPath namespace node found in a nodeset.
2743 *
2744 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2745 * the namespace nodes are duplicated and the next pointer is set to the
2746 * parent node in the XPath semantic. Check if such a node needs to be freed
2747 */
2748 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)2749 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2750 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2751 return;
2752
2753 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2754 if (ns->href != NULL)
2755 xmlFree((xmlChar *)ns->href);
2756 if (ns->prefix != NULL)
2757 xmlFree((xmlChar *)ns->prefix);
2758 xmlFree(ns);
2759 }
2760 }
2761
2762 /**
2763 * xmlXPathNodeSetCreate:
2764 * @val: an initial xmlNodePtr, or NULL
2765 *
2766 * Create a new xmlNodeSetPtr of type double and of value @val
2767 *
2768 * Returns the newly created object.
2769 */
2770 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)2771 xmlXPathNodeSetCreate(xmlNodePtr val) {
2772 xmlNodeSetPtr ret;
2773
2774 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2775 if (ret == NULL)
2776 return(NULL);
2777 memset(ret, 0 , sizeof(xmlNodeSet));
2778 if (val != NULL) {
2779 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2780 sizeof(xmlNodePtr));
2781 if (ret->nodeTab == NULL) {
2782 xmlFree(ret);
2783 return(NULL);
2784 }
2785 memset(ret->nodeTab, 0 ,
2786 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2787 ret->nodeMax = XML_NODESET_DEFAULT;
2788 if (val->type == XML_NAMESPACE_DECL) {
2789 xmlNsPtr ns = (xmlNsPtr) val;
2790 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2791
2792 if (nsNode == NULL) {
2793 xmlXPathFreeNodeSet(ret);
2794 return(NULL);
2795 }
2796 ret->nodeTab[ret->nodeNr++] = nsNode;
2797 } else
2798 ret->nodeTab[ret->nodeNr++] = val;
2799 }
2800 return(ret);
2801 }
2802
2803 /**
2804 * xmlXPathNodeSetContains:
2805 * @cur: the node-set
2806 * @val: the node
2807 *
2808 * checks whether @cur contains @val
2809 *
2810 * Returns true (1) if @cur contains @val, false (0) otherwise
2811 */
2812 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)2813 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2814 int i;
2815
2816 if ((cur == NULL) || (val == NULL)) return(0);
2817 if (val->type == XML_NAMESPACE_DECL) {
2818 for (i = 0; i < cur->nodeNr; i++) {
2819 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2820 xmlNsPtr ns1, ns2;
2821
2822 ns1 = (xmlNsPtr) val;
2823 ns2 = (xmlNsPtr) cur->nodeTab[i];
2824 if (ns1 == ns2)
2825 return(1);
2826 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2827 (xmlStrEqual(ns1->prefix, ns2->prefix)))
2828 return(1);
2829 }
2830 }
2831 } else {
2832 for (i = 0; i < cur->nodeNr; i++) {
2833 if (cur->nodeTab[i] == val)
2834 return(1);
2835 }
2836 }
2837 return(0);
2838 }
2839
2840 /**
2841 * xmlXPathNodeSetAddNs:
2842 * @cur: the initial node set
2843 * @node: the hosting node
2844 * @ns: a the namespace node
2845 *
2846 * add a new namespace node to an existing NodeSet
2847 *
2848 * Returns 0 in case of success and -1 in case of error
2849 */
2850 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)2851 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2852 int i;
2853 xmlNodePtr nsNode;
2854
2855 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2856 (ns->type != XML_NAMESPACE_DECL) ||
2857 (node->type != XML_ELEMENT_NODE))
2858 return(-1);
2859
2860 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2861 /*
2862 * prevent duplicates
2863 */
2864 for (i = 0;i < cur->nodeNr;i++) {
2865 if ((cur->nodeTab[i] != NULL) &&
2866 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2867 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2868 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2869 return(0);
2870 }
2871
2872 /*
2873 * grow the nodeTab if needed
2874 */
2875 if (cur->nodeMax == 0) {
2876 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2877 sizeof(xmlNodePtr));
2878 if (cur->nodeTab == NULL)
2879 return(-1);
2880 memset(cur->nodeTab, 0 ,
2881 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2882 cur->nodeMax = XML_NODESET_DEFAULT;
2883 } else if (cur->nodeNr == cur->nodeMax) {
2884 xmlNodePtr *temp;
2885
2886 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2887 return(-1);
2888 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2889 sizeof(xmlNodePtr));
2890 if (temp == NULL)
2891 return(-1);
2892 cur->nodeMax *= 2;
2893 cur->nodeTab = temp;
2894 }
2895 nsNode = xmlXPathNodeSetDupNs(node, ns);
2896 if(nsNode == NULL)
2897 return(-1);
2898 cur->nodeTab[cur->nodeNr++] = nsNode;
2899 return(0);
2900 }
2901
2902 /**
2903 * xmlXPathNodeSetAdd:
2904 * @cur: the initial node set
2905 * @val: a new xmlNodePtr
2906 *
2907 * add a new xmlNodePtr to an existing NodeSet
2908 *
2909 * Returns 0 in case of success, and -1 in case of error
2910 */
2911 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)2912 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2913 int i;
2914
2915 if ((cur == NULL) || (val == NULL)) return(-1);
2916
2917 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2918 /*
2919 * prevent duplicates
2920 */
2921 for (i = 0;i < cur->nodeNr;i++)
2922 if (cur->nodeTab[i] == val) return(0);
2923
2924 /*
2925 * grow the nodeTab if needed
2926 */
2927 if (cur->nodeMax == 0) {
2928 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2929 sizeof(xmlNodePtr));
2930 if (cur->nodeTab == NULL)
2931 return(-1);
2932 memset(cur->nodeTab, 0 ,
2933 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2934 cur->nodeMax = XML_NODESET_DEFAULT;
2935 } else if (cur->nodeNr == cur->nodeMax) {
2936 xmlNodePtr *temp;
2937
2938 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2939 return(-1);
2940 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2941 sizeof(xmlNodePtr));
2942 if (temp == NULL)
2943 return(-1);
2944 cur->nodeMax *= 2;
2945 cur->nodeTab = temp;
2946 }
2947 if (val->type == XML_NAMESPACE_DECL) {
2948 xmlNsPtr ns = (xmlNsPtr) val;
2949 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2950
2951 if (nsNode == NULL)
2952 return(-1);
2953 cur->nodeTab[cur->nodeNr++] = nsNode;
2954 } else
2955 cur->nodeTab[cur->nodeNr++] = val;
2956 return(0);
2957 }
2958
2959 /**
2960 * xmlXPathNodeSetAddUnique:
2961 * @cur: the initial node set
2962 * @val: a new xmlNodePtr
2963 *
2964 * add a new xmlNodePtr to an existing NodeSet, optimized version
2965 * when we are sure the node is not already in the set.
2966 *
2967 * Returns 0 in case of success and -1 in case of failure
2968 */
2969 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)2970 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2971 if ((cur == NULL) || (val == NULL)) return(-1);
2972
2973 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2974 /*
2975 * grow the nodeTab if needed
2976 */
2977 if (cur->nodeMax == 0) {
2978 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2979 sizeof(xmlNodePtr));
2980 if (cur->nodeTab == NULL)
2981 return(-1);
2982 memset(cur->nodeTab, 0 ,
2983 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2984 cur->nodeMax = XML_NODESET_DEFAULT;
2985 } else if (cur->nodeNr == cur->nodeMax) {
2986 xmlNodePtr *temp;
2987
2988 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2989 return(-1);
2990 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2991 sizeof(xmlNodePtr));
2992 if (temp == NULL)
2993 return(-1);
2994 cur->nodeTab = temp;
2995 cur->nodeMax *= 2;
2996 }
2997 if (val->type == XML_NAMESPACE_DECL) {
2998 xmlNsPtr ns = (xmlNsPtr) val;
2999 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3000
3001 if (nsNode == NULL)
3002 return(-1);
3003 cur->nodeTab[cur->nodeNr++] = nsNode;
3004 } else
3005 cur->nodeTab[cur->nodeNr++] = val;
3006 return(0);
3007 }
3008
3009 /**
3010 * xmlXPathNodeSetMerge:
3011 * @val1: the first NodeSet or NULL
3012 * @val2: the second NodeSet
3013 *
3014 * Merges two nodesets, all nodes from @val2 are added to @val1
3015 * if @val1 is NULL, a new set is created and copied from @val2
3016 *
3017 * Returns @val1 once extended or NULL in case of error.
3018 *
3019 * Frees @val1 in case of error.
3020 */
3021 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3022 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3023 int i, j, initNr, skip;
3024 xmlNodePtr n1, n2;
3025
3026 if (val1 == NULL) {
3027 val1 = xmlXPathNodeSetCreate(NULL);
3028 if (val1 == NULL)
3029 return (NULL);
3030 }
3031 if (val2 == NULL)
3032 return(val1);
3033
3034 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3035 initNr = val1->nodeNr;
3036
3037 for (i = 0;i < val2->nodeNr;i++) {
3038 n2 = val2->nodeTab[i];
3039 /*
3040 * check against duplicates
3041 */
3042 skip = 0;
3043 for (j = 0; j < initNr; j++) {
3044 n1 = val1->nodeTab[j];
3045 if (n1 == n2) {
3046 skip = 1;
3047 break;
3048 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3049 (n2->type == XML_NAMESPACE_DECL)) {
3050 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3051 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3052 ((xmlNsPtr) n2)->prefix)))
3053 {
3054 skip = 1;
3055 break;
3056 }
3057 }
3058 }
3059 if (skip)
3060 continue;
3061
3062 /*
3063 * grow the nodeTab if needed
3064 */
3065 if (val1->nodeMax == 0) {
3066 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3067 sizeof(xmlNodePtr));
3068 if (val1->nodeTab == NULL)
3069 goto error;
3070 memset(val1->nodeTab, 0 ,
3071 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3072 val1->nodeMax = XML_NODESET_DEFAULT;
3073 } else if (val1->nodeNr == val1->nodeMax) {
3074 xmlNodePtr *temp;
3075
3076 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3077 goto error;
3078 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3079 sizeof(xmlNodePtr));
3080 if (temp == NULL)
3081 goto error;
3082 val1->nodeTab = temp;
3083 val1->nodeMax *= 2;
3084 }
3085 if (n2->type == XML_NAMESPACE_DECL) {
3086 xmlNsPtr ns = (xmlNsPtr) n2;
3087 xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3088
3089 if (nsNode == NULL)
3090 goto error;
3091 val1->nodeTab[val1->nodeNr++] = nsNode;
3092 } else
3093 val1->nodeTab[val1->nodeNr++] = n2;
3094 }
3095
3096 return(val1);
3097
3098 error:
3099 xmlXPathFreeNodeSet(val1);
3100 return(NULL);
3101 }
3102
3103
3104 /**
3105 * xmlXPathNodeSetMergeAndClear:
3106 * @set1: the first NodeSet or NULL
3107 * @set2: the second NodeSet
3108 *
3109 * Merges two nodesets, all nodes from @set2 are added to @set1.
3110 * Checks for duplicate nodes. Clears set2.
3111 *
3112 * Returns @set1 once extended or NULL in case of error.
3113 *
3114 * Frees @set1 in case of error.
3115 */
3116 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3117 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3118 {
3119 {
3120 int i, j, initNbSet1;
3121 xmlNodePtr n1, n2;
3122
3123 initNbSet1 = set1->nodeNr;
3124 for (i = 0;i < set2->nodeNr;i++) {
3125 n2 = set2->nodeTab[i];
3126 /*
3127 * Skip duplicates.
3128 */
3129 for (j = 0; j < initNbSet1; j++) {
3130 n1 = set1->nodeTab[j];
3131 if (n1 == n2) {
3132 goto skip_node;
3133 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3134 (n2->type == XML_NAMESPACE_DECL))
3135 {
3136 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3137 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3138 ((xmlNsPtr) n2)->prefix)))
3139 {
3140 /*
3141 * Free the namespace node.
3142 */
3143 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3144 goto skip_node;
3145 }
3146 }
3147 }
3148 /*
3149 * grow the nodeTab if needed
3150 */
3151 if (set1->nodeMax == 0) {
3152 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3153 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3154 if (set1->nodeTab == NULL)
3155 goto error;
3156 memset(set1->nodeTab, 0,
3157 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3158 set1->nodeMax = XML_NODESET_DEFAULT;
3159 } else if (set1->nodeNr >= set1->nodeMax) {
3160 xmlNodePtr *temp;
3161
3162 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3163 goto error;
3164 temp = (xmlNodePtr *) xmlRealloc(
3165 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3166 if (temp == NULL)
3167 goto error;
3168 set1->nodeTab = temp;
3169 set1->nodeMax *= 2;
3170 }
3171 set1->nodeTab[set1->nodeNr++] = n2;
3172 skip_node:
3173 set2->nodeTab[i] = NULL;
3174 }
3175 }
3176 set2->nodeNr = 0;
3177 return(set1);
3178
3179 error:
3180 xmlXPathFreeNodeSet(set1);
3181 xmlXPathNodeSetClear(set2, 1);
3182 return(NULL);
3183 }
3184
3185 /**
3186 * xmlXPathNodeSetMergeAndClearNoDupls:
3187 * @set1: the first NodeSet or NULL
3188 * @set2: the second NodeSet
3189 *
3190 * Merges two nodesets, all nodes from @set2 are added to @set1.
3191 * Doesn't check for duplicate nodes. Clears set2.
3192 *
3193 * Returns @set1 once extended or NULL in case of error.
3194 *
3195 * Frees @set1 in case of error.
3196 */
3197 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3198 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3199 {
3200 {
3201 int i;
3202 xmlNodePtr n2;
3203
3204 for (i = 0;i < set2->nodeNr;i++) {
3205 n2 = set2->nodeTab[i];
3206 if (set1->nodeMax == 0) {
3207 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3208 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3209 if (set1->nodeTab == NULL)
3210 goto error;
3211 memset(set1->nodeTab, 0,
3212 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3213 set1->nodeMax = XML_NODESET_DEFAULT;
3214 } else if (set1->nodeNr >= set1->nodeMax) {
3215 xmlNodePtr *temp;
3216
3217 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3218 goto error;
3219 temp = (xmlNodePtr *) xmlRealloc(
3220 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3221 if (temp == NULL)
3222 goto error;
3223 set1->nodeTab = temp;
3224 set1->nodeMax *= 2;
3225 }
3226 set1->nodeTab[set1->nodeNr++] = n2;
3227 set2->nodeTab[i] = NULL;
3228 }
3229 }
3230 set2->nodeNr = 0;
3231 return(set1);
3232
3233 error:
3234 xmlXPathFreeNodeSet(set1);
3235 xmlXPathNodeSetClear(set2, 1);
3236 return(NULL);
3237 }
3238
3239 /**
3240 * xmlXPathNodeSetDel:
3241 * @cur: the initial node set
3242 * @val: an xmlNodePtr
3243 *
3244 * Removes an xmlNodePtr from an existing NodeSet
3245 */
3246 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)3247 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3248 int i;
3249
3250 if (cur == NULL) return;
3251 if (val == NULL) return;
3252
3253 /*
3254 * find node in nodeTab
3255 */
3256 for (i = 0;i < cur->nodeNr;i++)
3257 if (cur->nodeTab[i] == val) break;
3258
3259 if (i >= cur->nodeNr) { /* not found */
3260 return;
3261 }
3262 if ((cur->nodeTab[i] != NULL) &&
3263 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3264 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3265 cur->nodeNr--;
3266 for (;i < cur->nodeNr;i++)
3267 cur->nodeTab[i] = cur->nodeTab[i + 1];
3268 cur->nodeTab[cur->nodeNr] = NULL;
3269 }
3270
3271 /**
3272 * xmlXPathNodeSetRemove:
3273 * @cur: the initial node set
3274 * @val: the index to remove
3275 *
3276 * Removes an entry from an existing NodeSet list.
3277 */
3278 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)3279 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3280 if (cur == NULL) return;
3281 if (val >= cur->nodeNr) return;
3282 if ((cur->nodeTab[val] != NULL) &&
3283 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3284 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3285 cur->nodeNr--;
3286 for (;val < cur->nodeNr;val++)
3287 cur->nodeTab[val] = cur->nodeTab[val + 1];
3288 cur->nodeTab[cur->nodeNr] = NULL;
3289 }
3290
3291 /**
3292 * xmlXPathFreeNodeSet:
3293 * @obj: the xmlNodeSetPtr to free
3294 *
3295 * Free the NodeSet compound (not the actual nodes !).
3296 */
3297 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)3298 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3299 if (obj == NULL) return;
3300 if (obj->nodeTab != NULL) {
3301 int i;
3302
3303 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3304 for (i = 0;i < obj->nodeNr;i++)
3305 if ((obj->nodeTab[i] != NULL) &&
3306 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3307 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3308 xmlFree(obj->nodeTab);
3309 }
3310 xmlFree(obj);
3311 }
3312
3313 /**
3314 * xmlXPathNodeSetClearFromPos:
3315 * @set: the node set to be cleared
3316 * @pos: the start position to clear from
3317 *
3318 * Clears the list from temporary XPath objects (e.g. namespace nodes
3319 * are feed) starting with the entry at @pos, but does *not* free the list
3320 * itself. Sets the length of the list to @pos.
3321 */
3322 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)3323 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3324 {
3325 if ((set == NULL) || (pos >= set->nodeNr))
3326 return;
3327 else if ((hasNsNodes)) {
3328 int i;
3329 xmlNodePtr node;
3330
3331 for (i = pos; i < set->nodeNr; i++) {
3332 node = set->nodeTab[i];
3333 if ((node != NULL) &&
3334 (node->type == XML_NAMESPACE_DECL))
3335 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3336 }
3337 }
3338 set->nodeNr = pos;
3339 }
3340
3341 /**
3342 * xmlXPathNodeSetClear:
3343 * @set: the node set to clear
3344 *
3345 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3346 * are feed), but does *not* free the list itself. Sets the length of the
3347 * list to 0.
3348 */
3349 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)3350 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3351 {
3352 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3353 }
3354
3355 /**
3356 * xmlXPathNodeSetKeepLast:
3357 * @set: the node set to be cleared
3358 *
3359 * Move the last node to the first position and clear temporary XPath objects
3360 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3361 * to 1.
3362 */
3363 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)3364 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3365 {
3366 int i;
3367 xmlNodePtr node;
3368
3369 if ((set == NULL) || (set->nodeNr <= 1))
3370 return;
3371 for (i = 0; i < set->nodeNr - 1; i++) {
3372 node = set->nodeTab[i];
3373 if ((node != NULL) &&
3374 (node->type == XML_NAMESPACE_DECL))
3375 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3376 }
3377 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3378 set->nodeNr = 1;
3379 }
3380
3381 /**
3382 * xmlXPathNewNodeSet:
3383 * @val: the NodePtr value
3384 *
3385 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3386 * it with the single Node @val
3387 *
3388 * Returns the newly created object.
3389 */
3390 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)3391 xmlXPathNewNodeSet(xmlNodePtr val) {
3392 xmlXPathObjectPtr ret;
3393
3394 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3395 if (ret == NULL)
3396 return(NULL);
3397 memset(ret, 0 , sizeof(xmlXPathObject));
3398 ret->type = XPATH_NODESET;
3399 ret->boolval = 0;
3400 ret->nodesetval = xmlXPathNodeSetCreate(val);
3401 if (ret->nodesetval == NULL) {
3402 xmlFree(ret);
3403 return(NULL);
3404 }
3405 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3406 return(ret);
3407 }
3408
3409 /**
3410 * xmlXPathNewValueTree:
3411 * @val: the NodePtr value
3412 *
3413 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3414 * it with the tree root @val
3415 *
3416 * Returns the newly created object.
3417 */
3418 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)3419 xmlXPathNewValueTree(xmlNodePtr val) {
3420 xmlXPathObjectPtr ret;
3421
3422 ret = xmlXPathNewNodeSet(val);
3423 if (ret == NULL)
3424 return(NULL);
3425 ret->type = XPATH_XSLT_TREE;
3426
3427 return(ret);
3428 }
3429
3430 /**
3431 * xmlXPathNewNodeSetList:
3432 * @val: an existing NodeSet
3433 *
3434 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3435 * it with the Nodeset @val
3436 *
3437 * Returns the newly created object.
3438 */
3439 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)3440 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3441 {
3442 xmlXPathObjectPtr ret;
3443
3444 if (val == NULL)
3445 ret = NULL;
3446 else if (val->nodeTab == NULL)
3447 ret = xmlXPathNewNodeSet(NULL);
3448 else {
3449 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3450 if (ret) {
3451 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3452 if (ret->nodesetval == NULL) {
3453 xmlFree(ret);
3454 return(NULL);
3455 }
3456 }
3457 }
3458
3459 return (ret);
3460 }
3461
3462 /**
3463 * xmlXPathWrapNodeSet:
3464 * @val: the NodePtr value
3465 *
3466 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3467 *
3468 * Returns the newly created object.
3469 *
3470 * In case of error the node set is destroyed and NULL is returned.
3471 */
3472 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)3473 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3474 xmlXPathObjectPtr ret;
3475
3476 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3477 if (ret == NULL) {
3478 xmlXPathFreeNodeSet(val);
3479 return(NULL);
3480 }
3481 memset(ret, 0 , sizeof(xmlXPathObject));
3482 ret->type = XPATH_NODESET;
3483 ret->nodesetval = val;
3484 return(ret);
3485 }
3486
3487 /**
3488 * xmlXPathFreeNodeSetList:
3489 * @obj: an existing NodeSetList object
3490 *
3491 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3492 * the list contrary to xmlXPathFreeObject().
3493 */
3494 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)3495 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3496 if (obj == NULL) return;
3497 xmlFree(obj);
3498 }
3499
3500 /**
3501 * xmlXPathDifference:
3502 * @nodes1: a node-set
3503 * @nodes2: a node-set
3504 *
3505 * Implements the EXSLT - Sets difference() function:
3506 * node-set set:difference (node-set, node-set)
3507 *
3508 * Returns the difference between the two node sets, or nodes1 if
3509 * nodes2 is empty
3510 */
3511 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3512 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3513 xmlNodeSetPtr ret;
3514 int i, l1;
3515 xmlNodePtr cur;
3516
3517 if (xmlXPathNodeSetIsEmpty(nodes2))
3518 return(nodes1);
3519
3520 ret = xmlXPathNodeSetCreate(NULL);
3521 if (ret == NULL)
3522 return(NULL);
3523 if (xmlXPathNodeSetIsEmpty(nodes1))
3524 return(ret);
3525
3526 l1 = xmlXPathNodeSetGetLength(nodes1);
3527
3528 for (i = 0; i < l1; i++) {
3529 cur = xmlXPathNodeSetItem(nodes1, i);
3530 if (!xmlXPathNodeSetContains(nodes2, cur)) {
3531 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3532 xmlXPathFreeNodeSet(ret);
3533 return(NULL);
3534 }
3535 }
3536 }
3537 return(ret);
3538 }
3539
3540 /**
3541 * xmlXPathIntersection:
3542 * @nodes1: a node-set
3543 * @nodes2: a node-set
3544 *
3545 * Implements the EXSLT - Sets intersection() function:
3546 * node-set set:intersection (node-set, node-set)
3547 *
3548 * Returns a node set comprising the nodes that are within both the
3549 * node sets passed as arguments
3550 */
3551 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3552 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3553 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3554 int i, l1;
3555 xmlNodePtr cur;
3556
3557 if (ret == NULL)
3558 return(ret);
3559 if (xmlXPathNodeSetIsEmpty(nodes1))
3560 return(ret);
3561 if (xmlXPathNodeSetIsEmpty(nodes2))
3562 return(ret);
3563
3564 l1 = xmlXPathNodeSetGetLength(nodes1);
3565
3566 for (i = 0; i < l1; i++) {
3567 cur = xmlXPathNodeSetItem(nodes1, i);
3568 if (xmlXPathNodeSetContains(nodes2, cur)) {
3569 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3570 xmlXPathFreeNodeSet(ret);
3571 return(NULL);
3572 }
3573 }
3574 }
3575 return(ret);
3576 }
3577
3578 /**
3579 * xmlXPathDistinctSorted:
3580 * @nodes: a node-set, sorted by document order
3581 *
3582 * Implements the EXSLT - Sets distinct() function:
3583 * node-set set:distinct (node-set)
3584 *
3585 * Returns a subset of the nodes contained in @nodes, or @nodes if
3586 * it is empty
3587 */
3588 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)3589 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3590 xmlNodeSetPtr ret;
3591 xmlHashTablePtr hash;
3592 int i, l;
3593 xmlChar * strval;
3594 xmlNodePtr cur;
3595
3596 if (xmlXPathNodeSetIsEmpty(nodes))
3597 return(nodes);
3598
3599 ret = xmlXPathNodeSetCreate(NULL);
3600 if (ret == NULL)
3601 return(ret);
3602 l = xmlXPathNodeSetGetLength(nodes);
3603 hash = xmlHashCreate (l);
3604 for (i = 0; i < l; i++) {
3605 cur = xmlXPathNodeSetItem(nodes, i);
3606 strval = xmlXPathCastNodeToString(cur);
3607 if (xmlHashLookup(hash, strval) == NULL) {
3608 if (xmlHashAddEntry(hash, strval, strval) < 0) {
3609 xmlFree(strval);
3610 goto error;
3611 }
3612 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3613 goto error;
3614 } else {
3615 xmlFree(strval);
3616 }
3617 }
3618 xmlHashFree(hash, xmlHashDefaultDeallocator);
3619 return(ret);
3620
3621 error:
3622 xmlHashFree(hash, xmlHashDefaultDeallocator);
3623 xmlXPathFreeNodeSet(ret);
3624 return(NULL);
3625 }
3626
3627 /**
3628 * xmlXPathDistinct:
3629 * @nodes: a node-set
3630 *
3631 * Implements the EXSLT - Sets distinct() function:
3632 * node-set set:distinct (node-set)
3633 * @nodes is sorted by document order, then #exslSetsDistinctSorted
3634 * is called with the sorted node-set
3635 *
3636 * Returns a subset of the nodes contained in @nodes, or @nodes if
3637 * it is empty
3638 */
3639 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)3640 xmlXPathDistinct (xmlNodeSetPtr nodes) {
3641 if (xmlXPathNodeSetIsEmpty(nodes))
3642 return(nodes);
3643
3644 xmlXPathNodeSetSort(nodes);
3645 return(xmlXPathDistinctSorted(nodes));
3646 }
3647
3648 /**
3649 * xmlXPathHasSameNodes:
3650 * @nodes1: a node-set
3651 * @nodes2: a node-set
3652 *
3653 * Implements the EXSLT - Sets has-same-nodes function:
3654 * boolean set:has-same-node(node-set, node-set)
3655 *
3656 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3657 * otherwise
3658 */
3659 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3660 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3661 int i, l;
3662 xmlNodePtr cur;
3663
3664 if (xmlXPathNodeSetIsEmpty(nodes1) ||
3665 xmlXPathNodeSetIsEmpty(nodes2))
3666 return(0);
3667
3668 l = xmlXPathNodeSetGetLength(nodes1);
3669 for (i = 0; i < l; i++) {
3670 cur = xmlXPathNodeSetItem(nodes1, i);
3671 if (xmlXPathNodeSetContains(nodes2, cur))
3672 return(1);
3673 }
3674 return(0);
3675 }
3676
3677 /**
3678 * xmlXPathNodeLeadingSorted:
3679 * @nodes: a node-set, sorted by document order
3680 * @node: a node
3681 *
3682 * Implements the EXSLT - Sets leading() function:
3683 * node-set set:leading (node-set, node-set)
3684 *
3685 * Returns the nodes in @nodes that precede @node in document order,
3686 * @nodes if @node is NULL or an empty node-set if @nodes
3687 * doesn't contain @node
3688 */
3689 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3690 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3691 int i, l;
3692 xmlNodePtr cur;
3693 xmlNodeSetPtr ret;
3694
3695 if (node == NULL)
3696 return(nodes);
3697
3698 ret = xmlXPathNodeSetCreate(NULL);
3699 if (ret == NULL)
3700 return(ret);
3701 if (xmlXPathNodeSetIsEmpty(nodes) ||
3702 (!xmlXPathNodeSetContains(nodes, node)))
3703 return(ret);
3704
3705 l = xmlXPathNodeSetGetLength(nodes);
3706 for (i = 0; i < l; i++) {
3707 cur = xmlXPathNodeSetItem(nodes, i);
3708 if (cur == node)
3709 break;
3710 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3711 xmlXPathFreeNodeSet(ret);
3712 return(NULL);
3713 }
3714 }
3715 return(ret);
3716 }
3717
3718 /**
3719 * xmlXPathNodeLeading:
3720 * @nodes: a node-set
3721 * @node: a node
3722 *
3723 * Implements the EXSLT - Sets leading() function:
3724 * node-set set:leading (node-set, node-set)
3725 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3726 * is called.
3727 *
3728 * Returns the nodes in @nodes that precede @node in document order,
3729 * @nodes if @node is NULL or an empty node-set if @nodes
3730 * doesn't contain @node
3731 */
3732 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)3733 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3734 xmlXPathNodeSetSort(nodes);
3735 return(xmlXPathNodeLeadingSorted(nodes, node));
3736 }
3737
3738 /**
3739 * xmlXPathLeadingSorted:
3740 * @nodes1: a node-set, sorted by document order
3741 * @nodes2: a node-set, sorted by document order
3742 *
3743 * Implements the EXSLT - Sets leading() function:
3744 * node-set set:leading (node-set, node-set)
3745 *
3746 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3747 * in document order, @nodes1 if @nodes2 is NULL or empty or
3748 * an empty node-set if @nodes1 doesn't contain @nodes2
3749 */
3750 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3751 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3752 if (xmlXPathNodeSetIsEmpty(nodes2))
3753 return(nodes1);
3754 return(xmlXPathNodeLeadingSorted(nodes1,
3755 xmlXPathNodeSetItem(nodes2, 1)));
3756 }
3757
3758 /**
3759 * xmlXPathLeading:
3760 * @nodes1: a node-set
3761 * @nodes2: a node-set
3762 *
3763 * Implements the EXSLT - Sets leading() function:
3764 * node-set set:leading (node-set, node-set)
3765 * @nodes1 and @nodes2 are sorted by document order, then
3766 * #exslSetsLeadingSorted is called.
3767 *
3768 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3769 * in document order, @nodes1 if @nodes2 is NULL or empty or
3770 * an empty node-set if @nodes1 doesn't contain @nodes2
3771 */
3772 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3773 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3774 if (xmlXPathNodeSetIsEmpty(nodes2))
3775 return(nodes1);
3776 if (xmlXPathNodeSetIsEmpty(nodes1))
3777 return(xmlXPathNodeSetCreate(NULL));
3778 xmlXPathNodeSetSort(nodes1);
3779 xmlXPathNodeSetSort(nodes2);
3780 return(xmlXPathNodeLeadingSorted(nodes1,
3781 xmlXPathNodeSetItem(nodes2, 1)));
3782 }
3783
3784 /**
3785 * xmlXPathNodeTrailingSorted:
3786 * @nodes: a node-set, sorted by document order
3787 * @node: a node
3788 *
3789 * Implements the EXSLT - Sets trailing() function:
3790 * node-set set:trailing (node-set, node-set)
3791 *
3792 * Returns the nodes in @nodes that follow @node in document order,
3793 * @nodes if @node is NULL or an empty node-set if @nodes
3794 * doesn't contain @node
3795 */
3796 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)3797 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3798 int i, l;
3799 xmlNodePtr cur;
3800 xmlNodeSetPtr ret;
3801
3802 if (node == NULL)
3803 return(nodes);
3804
3805 ret = xmlXPathNodeSetCreate(NULL);
3806 if (ret == NULL)
3807 return(ret);
3808 if (xmlXPathNodeSetIsEmpty(nodes) ||
3809 (!xmlXPathNodeSetContains(nodes, node)))
3810 return(ret);
3811
3812 l = xmlXPathNodeSetGetLength(nodes);
3813 for (i = l - 1; i >= 0; i--) {
3814 cur = xmlXPathNodeSetItem(nodes, i);
3815 if (cur == node)
3816 break;
3817 if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3818 xmlXPathFreeNodeSet(ret);
3819 return(NULL);
3820 }
3821 }
3822 xmlXPathNodeSetSort(ret); /* bug 413451 */
3823 return(ret);
3824 }
3825
3826 /**
3827 * xmlXPathNodeTrailing:
3828 * @nodes: a node-set
3829 * @node: a node
3830 *
3831 * Implements the EXSLT - Sets trailing() function:
3832 * node-set set:trailing (node-set, node-set)
3833 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3834 * is called.
3835 *
3836 * Returns the nodes in @nodes that follow @node in document order,
3837 * @nodes if @node is NULL or an empty node-set if @nodes
3838 * doesn't contain @node
3839 */
3840 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)3841 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3842 xmlXPathNodeSetSort(nodes);
3843 return(xmlXPathNodeTrailingSorted(nodes, node));
3844 }
3845
3846 /**
3847 * xmlXPathTrailingSorted:
3848 * @nodes1: a node-set, sorted by document order
3849 * @nodes2: a node-set, sorted by document order
3850 *
3851 * Implements the EXSLT - Sets trailing() function:
3852 * node-set set:trailing (node-set, node-set)
3853 *
3854 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3855 * in document order, @nodes1 if @nodes2 is NULL or empty or
3856 * an empty node-set if @nodes1 doesn't contain @nodes2
3857 */
3858 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3859 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3860 if (xmlXPathNodeSetIsEmpty(nodes2))
3861 return(nodes1);
3862 return(xmlXPathNodeTrailingSorted(nodes1,
3863 xmlXPathNodeSetItem(nodes2, 0)));
3864 }
3865
3866 /**
3867 * xmlXPathTrailing:
3868 * @nodes1: a node-set
3869 * @nodes2: a node-set
3870 *
3871 * Implements the EXSLT - Sets trailing() function:
3872 * node-set set:trailing (node-set, node-set)
3873 * @nodes1 and @nodes2 are sorted by document order, then
3874 * #xmlXPathTrailingSorted is called.
3875 *
3876 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3877 * in document order, @nodes1 if @nodes2 is NULL or empty or
3878 * an empty node-set if @nodes1 doesn't contain @nodes2
3879 */
3880 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)3881 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3882 if (xmlXPathNodeSetIsEmpty(nodes2))
3883 return(nodes1);
3884 if (xmlXPathNodeSetIsEmpty(nodes1))
3885 return(xmlXPathNodeSetCreate(NULL));
3886 xmlXPathNodeSetSort(nodes1);
3887 xmlXPathNodeSetSort(nodes2);
3888 return(xmlXPathNodeTrailingSorted(nodes1,
3889 xmlXPathNodeSetItem(nodes2, 0)));
3890 }
3891
3892 /************************************************************************
3893 * *
3894 * Routines to handle extra functions *
3895 * *
3896 ************************************************************************/
3897
3898 /**
3899 * xmlXPathRegisterFunc:
3900 * @ctxt: the XPath context
3901 * @name: the function name
3902 * @f: the function implementation or NULL
3903 *
3904 * Register a new function. If @f is NULL it unregisters the function
3905 *
3906 * Returns 0 in case of success, -1 in case of error
3907 */
3908 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)3909 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3910 xmlXPathFunction f) {
3911 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3912 }
3913
3914 /**
3915 * xmlXPathRegisterFuncNS:
3916 * @ctxt: the XPath context
3917 * @name: the function name
3918 * @ns_uri: the function namespace URI
3919 * @f: the function implementation or NULL
3920 *
3921 * Register a new function. If @f is NULL it unregisters the function
3922 *
3923 * Returns 0 in case of success, -1 in case of error
3924 */
3925 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)3926 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3927 const xmlChar *ns_uri, xmlXPathFunction f) {
3928 int ret;
3929
3930 if (ctxt == NULL)
3931 return(-1);
3932 if (name == NULL)
3933 return(-1);
3934
3935 if (ctxt->funcHash == NULL)
3936 ctxt->funcHash = xmlHashCreate(0);
3937 if (ctxt->funcHash == NULL) {
3938 xmlXPathErrMemory(ctxt);
3939 return(-1);
3940 }
3941 if (f == NULL)
3942 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3943 XML_IGNORE_FPTR_CAST_WARNINGS
3944 ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3945 XML_POP_WARNINGS
3946 if (ret < 0) {
3947 xmlXPathErrMemory(ctxt);
3948 return(-1);
3949 }
3950
3951 return(0);
3952 }
3953
3954 /**
3955 * xmlXPathRegisterFuncLookup:
3956 * @ctxt: the XPath context
3957 * @f: the lookup function
3958 * @funcCtxt: the lookup data
3959 *
3960 * Registers an external mechanism to do function lookup.
3961 */
3962 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)3963 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3964 xmlXPathFuncLookupFunc f,
3965 void *funcCtxt) {
3966 if (ctxt == NULL)
3967 return;
3968 ctxt->funcLookupFunc = f;
3969 ctxt->funcLookupData = funcCtxt;
3970 }
3971
3972 /**
3973 * xmlXPathFunctionLookup:
3974 * @ctxt: the XPath context
3975 * @name: the function name
3976 *
3977 * Search in the Function array of the context for the given
3978 * function.
3979 *
3980 * Returns the xmlXPathFunction or NULL if not found
3981 */
3982 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)3983 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3984 if (ctxt == NULL)
3985 return (NULL);
3986
3987 if (ctxt->funcLookupFunc != NULL) {
3988 xmlXPathFunction ret;
3989 xmlXPathFuncLookupFunc f;
3990
3991 f = ctxt->funcLookupFunc;
3992 ret = f(ctxt->funcLookupData, name, NULL);
3993 if (ret != NULL)
3994 return(ret);
3995 }
3996 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3997 }
3998
3999 /**
4000 * xmlXPathFunctionLookupNS:
4001 * @ctxt: the XPath context
4002 * @name: the function name
4003 * @ns_uri: the function namespace URI
4004 *
4005 * Search in the Function array of the context for the given
4006 * function.
4007 *
4008 * Returns the xmlXPathFunction or NULL if not found
4009 */
4010 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4011 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4012 const xmlChar *ns_uri) {
4013 xmlXPathFunction ret;
4014
4015 if (ctxt == NULL)
4016 return(NULL);
4017 if (name == NULL)
4018 return(NULL);
4019
4020 if (ctxt->funcLookupFunc != NULL) {
4021 xmlXPathFuncLookupFunc f;
4022
4023 f = ctxt->funcLookupFunc;
4024 ret = f(ctxt->funcLookupData, name, ns_uri);
4025 if (ret != NULL)
4026 return(ret);
4027 }
4028
4029 if (ctxt->funcHash == NULL)
4030 return(NULL);
4031
4032 XML_IGNORE_FPTR_CAST_WARNINGS
4033 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4034 XML_POP_WARNINGS
4035 return(ret);
4036 }
4037
4038 /**
4039 * xmlXPathRegisteredFuncsCleanup:
4040 * @ctxt: the XPath context
4041 *
4042 * Cleanup the XPath context data associated to registered functions
4043 */
4044 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4045 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4046 if (ctxt == NULL)
4047 return;
4048
4049 xmlHashFree(ctxt->funcHash, NULL);
4050 ctxt->funcHash = NULL;
4051 }
4052
4053 /************************************************************************
4054 * *
4055 * Routines to handle Variables *
4056 * *
4057 ************************************************************************/
4058
4059 /**
4060 * xmlXPathRegisterVariable:
4061 * @ctxt: the XPath context
4062 * @name: the variable name
4063 * @value: the variable value or NULL
4064 *
4065 * Register a new variable value. If @value is NULL it unregisters
4066 * the variable
4067 *
4068 * Returns 0 in case of success, -1 in case of error
4069 */
4070 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4071 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4072 xmlXPathObjectPtr value) {
4073 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4074 }
4075
4076 /**
4077 * xmlXPathRegisterVariableNS:
4078 * @ctxt: the XPath context
4079 * @name: the variable name
4080 * @ns_uri: the variable namespace URI
4081 * @value: the variable value or NULL
4082 *
4083 * Register a new variable value. If @value is NULL it unregisters
4084 * the variable
4085 *
4086 * Returns 0 in case of success, -1 in case of error
4087 */
4088 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4089 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4090 const xmlChar *ns_uri,
4091 xmlXPathObjectPtr value) {
4092 if (ctxt == NULL)
4093 return(-1);
4094 if (name == NULL)
4095 return(-1);
4096
4097 if (ctxt->varHash == NULL)
4098 ctxt->varHash = xmlHashCreate(0);
4099 if (ctxt->varHash == NULL)
4100 return(-1);
4101 if (value == NULL)
4102 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4103 xmlXPathFreeObjectEntry));
4104 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4105 (void *) value, xmlXPathFreeObjectEntry));
4106 }
4107
4108 /**
4109 * xmlXPathRegisterVariableLookup:
4110 * @ctxt: the XPath context
4111 * @f: the lookup function
4112 * @data: the lookup data
4113 *
4114 * register an external mechanism to do variable lookup
4115 */
4116 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)4117 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4118 xmlXPathVariableLookupFunc f, void *data) {
4119 if (ctxt == NULL)
4120 return;
4121 ctxt->varLookupFunc = f;
4122 ctxt->varLookupData = data;
4123 }
4124
4125 /**
4126 * xmlXPathVariableLookup:
4127 * @ctxt: the XPath context
4128 * @name: the variable name
4129 *
4130 * Search in the Variable array of the context for the given
4131 * variable value.
4132 *
4133 * Returns a copy of the value or NULL if not found
4134 */
4135 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4136 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4137 if (ctxt == NULL)
4138 return(NULL);
4139
4140 if (ctxt->varLookupFunc != NULL) {
4141 xmlXPathObjectPtr ret;
4142
4143 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4144 (ctxt->varLookupData, name, NULL);
4145 return(ret);
4146 }
4147 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4148 }
4149
4150 /**
4151 * xmlXPathVariableLookupNS:
4152 * @ctxt: the XPath context
4153 * @name: the variable name
4154 * @ns_uri: the variable namespace URI
4155 *
4156 * Search in the Variable array of the context for the given
4157 * variable value.
4158 *
4159 * Returns the a copy of the value or NULL if not found
4160 */
4161 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4162 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4163 const xmlChar *ns_uri) {
4164 if (ctxt == NULL)
4165 return(NULL);
4166
4167 if (ctxt->varLookupFunc != NULL) {
4168 xmlXPathObjectPtr ret;
4169
4170 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4171 (ctxt->varLookupData, name, ns_uri);
4172 if (ret != NULL) return(ret);
4173 }
4174
4175 if (ctxt->varHash == NULL)
4176 return(NULL);
4177 if (name == NULL)
4178 return(NULL);
4179
4180 return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4181 }
4182
4183 /**
4184 * xmlXPathRegisteredVariablesCleanup:
4185 * @ctxt: the XPath context
4186 *
4187 * Cleanup the XPath context data associated to registered variables
4188 */
4189 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)4190 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4191 if (ctxt == NULL)
4192 return;
4193
4194 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4195 ctxt->varHash = NULL;
4196 }
4197
4198 /**
4199 * xmlXPathRegisterNs:
4200 * @ctxt: the XPath context
4201 * @prefix: the namespace prefix cannot be NULL or empty string
4202 * @ns_uri: the namespace name
4203 *
4204 * Register a new namespace. If @ns_uri is NULL it unregisters
4205 * the namespace
4206 *
4207 * Returns 0 in case of success, -1 in case of error
4208 */
4209 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)4210 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4211 const xmlChar *ns_uri) {
4212 xmlChar *copy;
4213
4214 if (ctxt == NULL)
4215 return(-1);
4216 if (prefix == NULL)
4217 return(-1);
4218 if (prefix[0] == 0)
4219 return(-1);
4220
4221 if (ctxt->nsHash == NULL)
4222 ctxt->nsHash = xmlHashCreate(10);
4223 if (ctxt->nsHash == NULL) {
4224 xmlXPathErrMemory(ctxt);
4225 return(-1);
4226 }
4227 if (ns_uri == NULL)
4228 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4229 xmlHashDefaultDeallocator));
4230
4231 copy = xmlStrdup(ns_uri);
4232 if (copy == NULL) {
4233 xmlXPathErrMemory(ctxt);
4234 return(-1);
4235 }
4236 if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4237 xmlHashDefaultDeallocator) < 0) {
4238 xmlXPathErrMemory(ctxt);
4239 xmlFree(copy);
4240 return(-1);
4241 }
4242
4243 return(0);
4244 }
4245
4246 /**
4247 * xmlXPathNsLookup:
4248 * @ctxt: the XPath context
4249 * @prefix: the namespace prefix value
4250 *
4251 * Search in the namespace declaration array of the context for the given
4252 * namespace name associated to the given prefix
4253 *
4254 * Returns the value or NULL if not found
4255 */
4256 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)4257 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4258 if (ctxt == NULL)
4259 return(NULL);
4260 if (prefix == NULL)
4261 return(NULL);
4262
4263 #ifdef XML_XML_NAMESPACE
4264 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4265 return(XML_XML_NAMESPACE);
4266 #endif
4267
4268 if (ctxt->namespaces != NULL) {
4269 int i;
4270
4271 for (i = 0;i < ctxt->nsNr;i++) {
4272 if ((ctxt->namespaces[i] != NULL) &&
4273 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4274 return(ctxt->namespaces[i]->href);
4275 }
4276 }
4277
4278 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4279 }
4280
4281 /**
4282 * xmlXPathRegisteredNsCleanup:
4283 * @ctxt: the XPath context
4284 *
4285 * Cleanup the XPath context data associated to registered variables
4286 */
4287 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)4288 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4289 if (ctxt == NULL)
4290 return;
4291
4292 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4293 ctxt->nsHash = NULL;
4294 }
4295
4296 /************************************************************************
4297 * *
4298 * Routines to handle Values *
4299 * *
4300 ************************************************************************/
4301
4302 /* Allocations are terrible, one needs to optimize all this !!! */
4303
4304 /**
4305 * xmlXPathNewFloat:
4306 * @val: the double value
4307 *
4308 * Create a new xmlXPathObjectPtr of type double and of value @val
4309 *
4310 * Returns the newly created object.
4311 */
4312 xmlXPathObjectPtr
xmlXPathNewFloat(double val)4313 xmlXPathNewFloat(double val) {
4314 xmlXPathObjectPtr ret;
4315
4316 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4317 if (ret == NULL)
4318 return(NULL);
4319 memset(ret, 0 , sizeof(xmlXPathObject));
4320 ret->type = XPATH_NUMBER;
4321 ret->floatval = val;
4322 return(ret);
4323 }
4324
4325 /**
4326 * xmlXPathNewBoolean:
4327 * @val: the boolean value
4328 *
4329 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4330 *
4331 * Returns the newly created object.
4332 */
4333 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)4334 xmlXPathNewBoolean(int val) {
4335 xmlXPathObjectPtr ret;
4336
4337 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4338 if (ret == NULL)
4339 return(NULL);
4340 memset(ret, 0 , sizeof(xmlXPathObject));
4341 ret->type = XPATH_BOOLEAN;
4342 ret->boolval = (val != 0);
4343 return(ret);
4344 }
4345
4346 /**
4347 * xmlXPathNewString:
4348 * @val: the xmlChar * value
4349 *
4350 * Create a new xmlXPathObjectPtr of type string and of value @val
4351 *
4352 * Returns the newly created object.
4353 */
4354 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)4355 xmlXPathNewString(const xmlChar *val) {
4356 xmlXPathObjectPtr ret;
4357
4358 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4359 if (ret == NULL)
4360 return(NULL);
4361 memset(ret, 0 , sizeof(xmlXPathObject));
4362 ret->type = XPATH_STRING;
4363 if (val == NULL)
4364 val = BAD_CAST "";
4365 ret->stringval = xmlStrdup(val);
4366 if (ret->stringval == NULL) {
4367 xmlFree(ret);
4368 return(NULL);
4369 }
4370 return(ret);
4371 }
4372
4373 /**
4374 * xmlXPathWrapString:
4375 * @val: the xmlChar * value
4376 *
4377 * Wraps the @val string into an XPath object.
4378 *
4379 * Returns the newly created object.
4380 *
4381 * Frees @val in case of error.
4382 */
4383 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)4384 xmlXPathWrapString (xmlChar *val) {
4385 xmlXPathObjectPtr ret;
4386
4387 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4388 if (ret == NULL) {
4389 xmlFree(val);
4390 return(NULL);
4391 }
4392 memset(ret, 0 , sizeof(xmlXPathObject));
4393 ret->type = XPATH_STRING;
4394 ret->stringval = val;
4395 return(ret);
4396 }
4397
4398 /**
4399 * xmlXPathNewCString:
4400 * @val: the char * value
4401 *
4402 * Create a new xmlXPathObjectPtr of type string and of value @val
4403 *
4404 * Returns the newly created object.
4405 */
4406 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)4407 xmlXPathNewCString(const char *val) {
4408 return(xmlXPathNewString(BAD_CAST val));
4409 }
4410
4411 /**
4412 * xmlXPathWrapCString:
4413 * @val: the char * value
4414 *
4415 * Wraps a string into an XPath object.
4416 *
4417 * Returns the newly created object.
4418 */
4419 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)4420 xmlXPathWrapCString (char * val) {
4421 return(xmlXPathWrapString((xmlChar *)(val)));
4422 }
4423
4424 /**
4425 * xmlXPathWrapExternal:
4426 * @val: the user data
4427 *
4428 * Wraps the @val data into an XPath object.
4429 *
4430 * Returns the newly created object.
4431 */
4432 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)4433 xmlXPathWrapExternal (void *val) {
4434 xmlXPathObjectPtr ret;
4435
4436 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4437 if (ret == NULL)
4438 return(NULL);
4439 memset(ret, 0 , sizeof(xmlXPathObject));
4440 ret->type = XPATH_USERS;
4441 ret->user = val;
4442 return(ret);
4443 }
4444
4445 /**
4446 * xmlXPathObjectCopy:
4447 * @val: the original object
4448 *
4449 * allocate a new copy of a given object
4450 *
4451 * Returns the newly created object.
4452 */
4453 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)4454 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4455 xmlXPathObjectPtr ret;
4456
4457 if (val == NULL)
4458 return(NULL);
4459
4460 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4461 if (ret == NULL)
4462 return(NULL);
4463 memcpy(ret, val , sizeof(xmlXPathObject));
4464 switch (val->type) {
4465 case XPATH_BOOLEAN:
4466 case XPATH_NUMBER:
4467 #ifdef LIBXML_XPTR_LOCS_ENABLED
4468 case XPATH_POINT:
4469 case XPATH_RANGE:
4470 #endif /* LIBXML_XPTR_LOCS_ENABLED */
4471 break;
4472 case XPATH_STRING:
4473 ret->stringval = xmlStrdup(val->stringval);
4474 if (ret->stringval == NULL) {
4475 xmlFree(ret);
4476 return(NULL);
4477 }
4478 break;
4479 case XPATH_XSLT_TREE:
4480 #if 0
4481 /*
4482 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4483 this previous handling is no longer correct, and can cause some serious
4484 problems (ref. bug 145547)
4485 */
4486 if ((val->nodesetval != NULL) &&
4487 (val->nodesetval->nodeTab != NULL)) {
4488 xmlNodePtr cur, tmp;
4489 xmlDocPtr top;
4490
4491 ret->boolval = 1;
4492 top = xmlNewDoc(NULL);
4493 top->name = (char *)
4494 xmlStrdup(val->nodesetval->nodeTab[0]->name);
4495 ret->user = top;
4496 if (top != NULL) {
4497 top->doc = top;
4498 cur = val->nodesetval->nodeTab[0]->children;
4499 while (cur != NULL) {
4500 tmp = xmlDocCopyNode(cur, top, 1);
4501 xmlAddChild((xmlNodePtr) top, tmp);
4502 cur = cur->next;
4503 }
4504 }
4505
4506 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4507 } else
4508 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4509 /* Deallocate the copied tree value */
4510 break;
4511 #endif
4512 case XPATH_NODESET:
4513 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4514 if (ret->nodesetval == NULL) {
4515 xmlFree(ret);
4516 return(NULL);
4517 }
4518 /* Do not deallocate the copied tree value */
4519 ret->boolval = 0;
4520 break;
4521 #ifdef LIBXML_XPTR_LOCS_ENABLED
4522 case XPATH_LOCATIONSET:
4523 {
4524 xmlLocationSetPtr loc = val->user;
4525 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
4526 break;
4527 }
4528 #endif
4529 case XPATH_USERS:
4530 ret->user = val->user;
4531 break;
4532 default:
4533 xmlFree(ret);
4534 ret = NULL;
4535 break;
4536 }
4537 return(ret);
4538 }
4539
4540 /**
4541 * xmlXPathFreeObject:
4542 * @obj: the object to free
4543 *
4544 * Free up an xmlXPathObjectPtr object.
4545 */
4546 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)4547 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4548 if (obj == NULL) return;
4549 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4550 if (obj->nodesetval != NULL)
4551 xmlXPathFreeNodeSet(obj->nodesetval);
4552 #ifdef LIBXML_XPTR_LOCS_ENABLED
4553 } else if (obj->type == XPATH_LOCATIONSET) {
4554 if (obj->user != NULL)
4555 xmlXPtrFreeLocationSet(obj->user);
4556 #endif
4557 } else if (obj->type == XPATH_STRING) {
4558 if (obj->stringval != NULL)
4559 xmlFree(obj->stringval);
4560 }
4561 xmlFree(obj);
4562 }
4563
4564 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)4565 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4566 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4567 }
4568
4569 /**
4570 * xmlXPathReleaseObject:
4571 * @obj: the xmlXPathObjectPtr to free or to cache
4572 *
4573 * Depending on the state of the cache this frees the given
4574 * XPath object or stores it in the cache.
4575 */
4576 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)4577 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4578 {
4579 if (obj == NULL)
4580 return;
4581 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4582 xmlXPathFreeObject(obj);
4583 } else {
4584 xmlXPathContextCachePtr cache =
4585 (xmlXPathContextCachePtr) ctxt->cache;
4586
4587 switch (obj->type) {
4588 case XPATH_NODESET:
4589 case XPATH_XSLT_TREE:
4590 if (obj->nodesetval != NULL) {
4591 if ((obj->nodesetval->nodeMax <= 40) &&
4592 (cache->numNodeset < cache->maxNodeset)) {
4593 obj->stringval = (void *) cache->nodesetObjs;
4594 cache->nodesetObjs = obj;
4595 cache->numNodeset += 1;
4596 goto obj_cached;
4597 } else {
4598 xmlXPathFreeNodeSet(obj->nodesetval);
4599 obj->nodesetval = NULL;
4600 }
4601 }
4602 break;
4603 case XPATH_STRING:
4604 if (obj->stringval != NULL)
4605 xmlFree(obj->stringval);
4606 obj->stringval = NULL;
4607 break;
4608 case XPATH_BOOLEAN:
4609 case XPATH_NUMBER:
4610 break;
4611 #ifdef LIBXML_XPTR_LOCS_ENABLED
4612 case XPATH_LOCATIONSET:
4613 if (obj->user != NULL) {
4614 xmlXPtrFreeLocationSet(obj->user);
4615 }
4616 goto free_obj;
4617 #endif
4618 default:
4619 goto free_obj;
4620 }
4621
4622 /*
4623 * Fallback to adding to the misc-objects slot.
4624 */
4625 if (cache->numMisc >= cache->maxMisc)
4626 goto free_obj;
4627 obj->stringval = (void *) cache->miscObjs;
4628 cache->miscObjs = obj;
4629 cache->numMisc += 1;
4630
4631 obj_cached:
4632 obj->boolval = 0;
4633 if (obj->nodesetval != NULL) {
4634 xmlNodeSetPtr tmpset = obj->nodesetval;
4635
4636 /*
4637 * Due to those nasty ns-nodes, we need to traverse
4638 * the list and free the ns-nodes.
4639 */
4640 if (tmpset->nodeNr > 0) {
4641 int i;
4642 xmlNodePtr node;
4643
4644 for (i = 0; i < tmpset->nodeNr; i++) {
4645 node = tmpset->nodeTab[i];
4646 if ((node != NULL) &&
4647 (node->type == XML_NAMESPACE_DECL))
4648 {
4649 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4650 }
4651 }
4652 }
4653 tmpset->nodeNr = 0;
4654 }
4655
4656 return;
4657
4658 free_obj:
4659 /*
4660 * Cache is full; free the object.
4661 */
4662 if (obj->nodesetval != NULL)
4663 xmlXPathFreeNodeSet(obj->nodesetval);
4664 xmlFree(obj);
4665 }
4666 return;
4667 }
4668
4669
4670 /************************************************************************
4671 * *
4672 * Type Casting Routines *
4673 * *
4674 ************************************************************************/
4675
4676 /**
4677 * xmlXPathCastBooleanToString:
4678 * @val: a boolean
4679 *
4680 * Converts a boolean to its string value.
4681 *
4682 * Returns a newly allocated string.
4683 */
4684 xmlChar *
xmlXPathCastBooleanToString(int val)4685 xmlXPathCastBooleanToString (int val) {
4686 xmlChar *ret;
4687 if (val)
4688 ret = xmlStrdup((const xmlChar *) "true");
4689 else
4690 ret = xmlStrdup((const xmlChar *) "false");
4691 return(ret);
4692 }
4693
4694 /**
4695 * xmlXPathCastNumberToString:
4696 * @val: a number
4697 *
4698 * Converts a number to its string value.
4699 *
4700 * Returns a newly allocated string.
4701 */
4702 xmlChar *
xmlXPathCastNumberToString(double val)4703 xmlXPathCastNumberToString (double val) {
4704 xmlChar *ret;
4705 switch (xmlXPathIsInf(val)) {
4706 case 1:
4707 ret = xmlStrdup((const xmlChar *) "Infinity");
4708 break;
4709 case -1:
4710 ret = xmlStrdup((const xmlChar *) "-Infinity");
4711 break;
4712 default:
4713 if (xmlXPathIsNaN(val)) {
4714 ret = xmlStrdup((const xmlChar *) "NaN");
4715 } else if (val == 0) {
4716 /* Omit sign for negative zero. */
4717 ret = xmlStrdup((const xmlChar *) "0");
4718 } else {
4719 /* could be improved */
4720 char buf[100];
4721 xmlXPathFormatNumber(val, buf, 99);
4722 buf[99] = 0;
4723 ret = xmlStrdup((const xmlChar *) buf);
4724 }
4725 }
4726 return(ret);
4727 }
4728
4729 /**
4730 * xmlXPathCastNodeToString:
4731 * @node: a node
4732 *
4733 * Converts a node to its string value.
4734 *
4735 * Returns a newly allocated string.
4736 */
4737 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)4738 xmlXPathCastNodeToString (xmlNodePtr node) {
4739 return(xmlNodeGetContent(node));
4740 }
4741
4742 /**
4743 * xmlXPathCastNodeSetToString:
4744 * @ns: a node-set
4745 *
4746 * Converts a node-set to its string value.
4747 *
4748 * Returns a newly allocated string.
4749 */
4750 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)4751 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4752 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4753 return(xmlStrdup((const xmlChar *) ""));
4754
4755 if (ns->nodeNr > 1)
4756 xmlXPathNodeSetSort(ns);
4757 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4758 }
4759
4760 /**
4761 * xmlXPathCastToString:
4762 * @val: an XPath object
4763 *
4764 * Converts an existing object to its string() equivalent
4765 *
4766 * Returns the allocated string value of the object, NULL in case of error.
4767 * It's up to the caller to free the string memory with xmlFree().
4768 */
4769 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)4770 xmlXPathCastToString(xmlXPathObjectPtr val) {
4771 xmlChar *ret = NULL;
4772
4773 if (val == NULL)
4774 return(xmlStrdup((const xmlChar *) ""));
4775 switch (val->type) {
4776 case XPATH_UNDEFINED:
4777 ret = xmlStrdup((const xmlChar *) "");
4778 break;
4779 case XPATH_NODESET:
4780 case XPATH_XSLT_TREE:
4781 ret = xmlXPathCastNodeSetToString(val->nodesetval);
4782 break;
4783 case XPATH_STRING:
4784 return(xmlStrdup(val->stringval));
4785 case XPATH_BOOLEAN:
4786 ret = xmlXPathCastBooleanToString(val->boolval);
4787 break;
4788 case XPATH_NUMBER: {
4789 ret = xmlXPathCastNumberToString(val->floatval);
4790 break;
4791 }
4792 case XPATH_USERS:
4793 #ifdef LIBXML_XPTR_LOCS_ENABLED
4794 case XPATH_POINT:
4795 case XPATH_RANGE:
4796 case XPATH_LOCATIONSET:
4797 #endif /* LIBXML_XPTR_LOCS_ENABLED */
4798 /* TODO */
4799 ret = xmlStrdup((const xmlChar *) "");
4800 break;
4801 }
4802 return(ret);
4803 }
4804
4805 /**
4806 * xmlXPathConvertString:
4807 * @val: an XPath object
4808 *
4809 * Converts an existing object to its string() equivalent
4810 *
4811 * Returns the new object, the old one is freed (or the operation
4812 * is done directly on @val)
4813 */
4814 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)4815 xmlXPathConvertString(xmlXPathObjectPtr val) {
4816 xmlChar *res = NULL;
4817
4818 if (val == NULL)
4819 return(xmlXPathNewCString(""));
4820
4821 switch (val->type) {
4822 case XPATH_UNDEFINED:
4823 break;
4824 case XPATH_NODESET:
4825 case XPATH_XSLT_TREE:
4826 res = xmlXPathCastNodeSetToString(val->nodesetval);
4827 break;
4828 case XPATH_STRING:
4829 return(val);
4830 case XPATH_BOOLEAN:
4831 res = xmlXPathCastBooleanToString(val->boolval);
4832 break;
4833 case XPATH_NUMBER:
4834 res = xmlXPathCastNumberToString(val->floatval);
4835 break;
4836 case XPATH_USERS:
4837 #ifdef LIBXML_XPTR_LOCS_ENABLED
4838 case XPATH_POINT:
4839 case XPATH_RANGE:
4840 case XPATH_LOCATIONSET:
4841 #endif /* LIBXML_XPTR_LOCS_ENABLED */
4842 /* TODO */
4843 break;
4844 }
4845 xmlXPathFreeObject(val);
4846 if (res == NULL)
4847 return(xmlXPathNewCString(""));
4848 return(xmlXPathWrapString(res));
4849 }
4850
4851 /**
4852 * xmlXPathCastBooleanToNumber:
4853 * @val: a boolean
4854 *
4855 * Converts a boolean to its number value
4856 *
4857 * Returns the number value
4858 */
4859 double
xmlXPathCastBooleanToNumber(int val)4860 xmlXPathCastBooleanToNumber(int val) {
4861 if (val)
4862 return(1.0);
4863 return(0.0);
4864 }
4865
4866 /**
4867 * xmlXPathCastStringToNumber:
4868 * @val: a string
4869 *
4870 * Converts a string to its number value
4871 *
4872 * Returns the number value
4873 */
4874 double
xmlXPathCastStringToNumber(const xmlChar * val)4875 xmlXPathCastStringToNumber(const xmlChar * val) {
4876 return(xmlXPathStringEvalNumber(val));
4877 }
4878
4879 /**
4880 * xmlXPathNodeToNumberInternal:
4881 * @node: a node
4882 *
4883 * Converts a node to its number value
4884 *
4885 * Returns the number value
4886 */
4887 static double
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr node)4888 xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4889 xmlChar *strval;
4890 double ret;
4891
4892 if (node == NULL)
4893 return(xmlXPathNAN);
4894 strval = xmlXPathCastNodeToString(node);
4895 if (strval == NULL) {
4896 xmlXPathPErrMemory(ctxt);
4897 return(xmlXPathNAN);
4898 }
4899 ret = xmlXPathCastStringToNumber(strval);
4900 xmlFree(strval);
4901
4902 return(ret);
4903 }
4904
4905 /**
4906 * xmlXPathCastNodeToNumber:
4907 * @node: a node
4908 *
4909 * Converts a node to its number value
4910 *
4911 * Returns the number value
4912 */
4913 double
xmlXPathCastNodeToNumber(xmlNodePtr node)4914 xmlXPathCastNodeToNumber (xmlNodePtr node) {
4915 return(xmlXPathNodeToNumberInternal(NULL, node));
4916 }
4917
4918 /**
4919 * xmlXPathCastNodeSetToNumber:
4920 * @ns: a node-set
4921 *
4922 * Converts a node-set to its number value
4923 *
4924 * Returns the number value
4925 */
4926 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)4927 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4928 xmlChar *str;
4929 double ret;
4930
4931 if (ns == NULL)
4932 return(xmlXPathNAN);
4933 str = xmlXPathCastNodeSetToString(ns);
4934 ret = xmlXPathCastStringToNumber(str);
4935 xmlFree(str);
4936 return(ret);
4937 }
4938
4939 /**
4940 * xmlXPathCastToNumber:
4941 * @val: an XPath object
4942 *
4943 * Converts an XPath object to its number value
4944 *
4945 * Returns the number value
4946 */
4947 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)4948 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4949 return(xmlXPathCastToNumberInternal(NULL, val));
4950 }
4951
4952 /**
4953 * xmlXPathConvertNumber:
4954 * @val: an XPath object
4955 *
4956 * Converts an existing object to its number() equivalent
4957 *
4958 * Returns the new object, the old one is freed (or the operation
4959 * is done directly on @val)
4960 */
4961 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)4962 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4963 xmlXPathObjectPtr ret;
4964
4965 if (val == NULL)
4966 return(xmlXPathNewFloat(0.0));
4967 if (val->type == XPATH_NUMBER)
4968 return(val);
4969 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4970 xmlXPathFreeObject(val);
4971 return(ret);
4972 }
4973
4974 /**
4975 * xmlXPathCastNumberToBoolean:
4976 * @val: a number
4977 *
4978 * Converts a number to its boolean value
4979 *
4980 * Returns the boolean value
4981 */
4982 int
xmlXPathCastNumberToBoolean(double val)4983 xmlXPathCastNumberToBoolean (double val) {
4984 if (xmlXPathIsNaN(val) || (val == 0.0))
4985 return(0);
4986 return(1);
4987 }
4988
4989 /**
4990 * xmlXPathCastStringToBoolean:
4991 * @val: a string
4992 *
4993 * Converts a string to its boolean value
4994 *
4995 * Returns the boolean value
4996 */
4997 int
xmlXPathCastStringToBoolean(const xmlChar * val)4998 xmlXPathCastStringToBoolean (const xmlChar *val) {
4999 if ((val == NULL) || (xmlStrlen(val) == 0))
5000 return(0);
5001 return(1);
5002 }
5003
5004 /**
5005 * xmlXPathCastNodeSetToBoolean:
5006 * @ns: a node-set
5007 *
5008 * Converts a node-set to its boolean value
5009 *
5010 * Returns the boolean value
5011 */
5012 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)5013 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5014 if ((ns == NULL) || (ns->nodeNr == 0))
5015 return(0);
5016 return(1);
5017 }
5018
5019 /**
5020 * xmlXPathCastToBoolean:
5021 * @val: an XPath object
5022 *
5023 * Converts an XPath object to its boolean value
5024 *
5025 * Returns the boolean value
5026 */
5027 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)5028 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5029 int ret = 0;
5030
5031 if (val == NULL)
5032 return(0);
5033 switch (val->type) {
5034 case XPATH_UNDEFINED:
5035 ret = 0;
5036 break;
5037 case XPATH_NODESET:
5038 case XPATH_XSLT_TREE:
5039 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5040 break;
5041 case XPATH_STRING:
5042 ret = xmlXPathCastStringToBoolean(val->stringval);
5043 break;
5044 case XPATH_NUMBER:
5045 ret = xmlXPathCastNumberToBoolean(val->floatval);
5046 break;
5047 case XPATH_BOOLEAN:
5048 ret = val->boolval;
5049 break;
5050 case XPATH_USERS:
5051 #ifdef LIBXML_XPTR_LOCS_ENABLED
5052 case XPATH_POINT:
5053 case XPATH_RANGE:
5054 case XPATH_LOCATIONSET:
5055 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5056 /* TODO */
5057 ret = 0;
5058 break;
5059 }
5060 return(ret);
5061 }
5062
5063
5064 /**
5065 * xmlXPathConvertBoolean:
5066 * @val: an XPath object
5067 *
5068 * Converts an existing object to its boolean() equivalent
5069 *
5070 * Returns the new object, the old one is freed (or the operation
5071 * is done directly on @val)
5072 */
5073 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)5074 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5075 xmlXPathObjectPtr ret;
5076
5077 if (val == NULL)
5078 return(xmlXPathNewBoolean(0));
5079 if (val->type == XPATH_BOOLEAN)
5080 return(val);
5081 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5082 xmlXPathFreeObject(val);
5083 return(ret);
5084 }
5085
5086 /************************************************************************
5087 * *
5088 * Routines to handle XPath contexts *
5089 * *
5090 ************************************************************************/
5091
5092 /**
5093 * xmlXPathNewContext:
5094 * @doc: the XML document
5095 *
5096 * Create a new xmlXPathContext
5097 *
5098 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5099 */
5100 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)5101 xmlXPathNewContext(xmlDocPtr doc) {
5102 xmlXPathContextPtr ret;
5103
5104 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5105 if (ret == NULL)
5106 return(NULL);
5107 memset(ret, 0 , sizeof(xmlXPathContext));
5108 ret->doc = doc;
5109 ret->node = NULL;
5110
5111 ret->varHash = NULL;
5112
5113 ret->nb_types = 0;
5114 ret->max_types = 0;
5115 ret->types = NULL;
5116
5117 ret->nb_axis = 0;
5118 ret->max_axis = 0;
5119 ret->axis = NULL;
5120
5121 ret->nsHash = NULL;
5122 ret->user = NULL;
5123
5124 ret->contextSize = -1;
5125 ret->proximityPosition = -1;
5126
5127 #ifdef XP_DEFAULT_CACHE_ON
5128 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5129 xmlXPathFreeContext(ret);
5130 return(NULL);
5131 }
5132 #endif
5133
5134 xmlXPathRegisterAllFunctions(ret);
5135
5136 if (ret->lastError.code != XML_ERR_OK) {
5137 xmlXPathFreeContext(ret);
5138 return(NULL);
5139 }
5140
5141 return(ret);
5142 }
5143
5144 /**
5145 * xmlXPathFreeContext:
5146 * @ctxt: the context to free
5147 *
5148 * Free up an xmlXPathContext
5149 */
5150 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)5151 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5152 if (ctxt == NULL) return;
5153
5154 if (ctxt->cache != NULL)
5155 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5156 xmlXPathRegisteredNsCleanup(ctxt);
5157 xmlXPathRegisteredFuncsCleanup(ctxt);
5158 xmlXPathRegisteredVariablesCleanup(ctxt);
5159 xmlResetError(&ctxt->lastError);
5160 xmlFree(ctxt);
5161 }
5162
5163 /**
5164 * xmlXPathSetErrorHandler:
5165 * @ctxt: the XPath context
5166 * @handler: error handler
5167 * @data: user data which will be passed to the handler
5168 *
5169 * Register a callback function that will be called on errors and
5170 * warnings. If handler is NULL, the error handler will be deactivated.
5171 *
5172 * Available since 2.13.0.
5173 */
5174 void
xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,xmlStructuredErrorFunc handler,void * data)5175 xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
5176 xmlStructuredErrorFunc handler, void *data) {
5177 if (ctxt == NULL)
5178 return;
5179
5180 ctxt->error = handler;
5181 ctxt->userData = data;
5182 }
5183
5184 /************************************************************************
5185 * *
5186 * Routines to handle XPath parser contexts *
5187 * *
5188 ************************************************************************/
5189
5190 /**
5191 * xmlXPathNewParserContext:
5192 * @str: the XPath expression
5193 * @ctxt: the XPath context
5194 *
5195 * Create a new xmlXPathParserContext
5196 *
5197 * Returns the xmlXPathParserContext just allocated.
5198 */
5199 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)5200 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5201 xmlXPathParserContextPtr ret;
5202
5203 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5204 if (ret == NULL) {
5205 xmlXPathErrMemory(ctxt);
5206 return(NULL);
5207 }
5208 memset(ret, 0 , sizeof(xmlXPathParserContext));
5209 ret->cur = ret->base = str;
5210 ret->context = ctxt;
5211
5212 ret->comp = xmlXPathNewCompExpr();
5213 if (ret->comp == NULL) {
5214 xmlXPathErrMemory(ctxt);
5215 xmlFree(ret->valueTab);
5216 xmlFree(ret);
5217 return(NULL);
5218 }
5219 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5220 ret->comp->dict = ctxt->dict;
5221 xmlDictReference(ret->comp->dict);
5222 }
5223
5224 return(ret);
5225 }
5226
5227 /**
5228 * xmlXPathCompParserContext:
5229 * @comp: the XPath compiled expression
5230 * @ctxt: the XPath context
5231 *
5232 * Create a new xmlXPathParserContext when processing a compiled expression
5233 *
5234 * Returns the xmlXPathParserContext just allocated.
5235 */
5236 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)5237 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5238 xmlXPathParserContextPtr ret;
5239
5240 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5241 if (ret == NULL) {
5242 xmlXPathErrMemory(ctxt);
5243 return(NULL);
5244 }
5245 memset(ret, 0 , sizeof(xmlXPathParserContext));
5246
5247 /* Allocate the value stack */
5248 ret->valueTab = (xmlXPathObjectPtr *)
5249 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5250 if (ret->valueTab == NULL) {
5251 xmlFree(ret);
5252 xmlXPathErrMemory(ctxt);
5253 return(NULL);
5254 }
5255 ret->valueNr = 0;
5256 ret->valueMax = 10;
5257 ret->value = NULL;
5258
5259 ret->context = ctxt;
5260 ret->comp = comp;
5261
5262 return(ret);
5263 }
5264
5265 /**
5266 * xmlXPathFreeParserContext:
5267 * @ctxt: the context to free
5268 *
5269 * Free up an xmlXPathParserContext
5270 */
5271 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)5272 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5273 int i;
5274
5275 if (ctxt->valueTab != NULL) {
5276 for (i = 0; i < ctxt->valueNr; i++) {
5277 if (ctxt->context)
5278 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5279 else
5280 xmlXPathFreeObject(ctxt->valueTab[i]);
5281 }
5282 xmlFree(ctxt->valueTab);
5283 }
5284 if (ctxt->comp != NULL) {
5285 #ifdef XPATH_STREAMING
5286 if (ctxt->comp->stream != NULL) {
5287 xmlFreePatternList(ctxt->comp->stream);
5288 ctxt->comp->stream = NULL;
5289 }
5290 #endif
5291 xmlXPathFreeCompExpr(ctxt->comp);
5292 }
5293 xmlFree(ctxt);
5294 }
5295
5296 /************************************************************************
5297 * *
5298 * The implicit core function library *
5299 * *
5300 ************************************************************************/
5301
5302 /**
5303 * xmlXPathNodeValHash:
5304 * @node: a node pointer
5305 *
5306 * Function computing the beginning of the string value of the node,
5307 * used to speed up comparisons
5308 *
5309 * Returns an int usable as a hash
5310 */
5311 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)5312 xmlXPathNodeValHash(xmlNodePtr node) {
5313 int len = 2;
5314 const xmlChar * string = NULL;
5315 xmlNodePtr tmp = NULL;
5316 unsigned int ret = 0;
5317
5318 if (node == NULL)
5319 return(0);
5320
5321 if (node->type == XML_DOCUMENT_NODE) {
5322 tmp = xmlDocGetRootElement((xmlDocPtr) node);
5323 if (tmp == NULL)
5324 node = node->children;
5325 else
5326 node = tmp;
5327
5328 if (node == NULL)
5329 return(0);
5330 }
5331
5332 switch (node->type) {
5333 case XML_COMMENT_NODE:
5334 case XML_PI_NODE:
5335 case XML_CDATA_SECTION_NODE:
5336 case XML_TEXT_NODE:
5337 string = node->content;
5338 if (string == NULL)
5339 return(0);
5340 if (string[0] == 0)
5341 return(0);
5342 return(string[0] + (string[1] << 8));
5343 case XML_NAMESPACE_DECL:
5344 string = ((xmlNsPtr)node)->href;
5345 if (string == NULL)
5346 return(0);
5347 if (string[0] == 0)
5348 return(0);
5349 return(string[0] + (string[1] << 8));
5350 case XML_ATTRIBUTE_NODE:
5351 tmp = ((xmlAttrPtr) node)->children;
5352 break;
5353 case XML_ELEMENT_NODE:
5354 tmp = node->children;
5355 break;
5356 default:
5357 return(0);
5358 }
5359 while (tmp != NULL) {
5360 switch (tmp->type) {
5361 case XML_CDATA_SECTION_NODE:
5362 case XML_TEXT_NODE:
5363 string = tmp->content;
5364 break;
5365 default:
5366 string = NULL;
5367 break;
5368 }
5369 if ((string != NULL) && (string[0] != 0)) {
5370 if (len == 1) {
5371 return(ret + (string[0] << 8));
5372 }
5373 if (string[1] == 0) {
5374 len = 1;
5375 ret = string[0];
5376 } else {
5377 return(string[0] + (string[1] << 8));
5378 }
5379 }
5380 /*
5381 * Skip to next node
5382 */
5383 if ((tmp->children != NULL) &&
5384 (tmp->type != XML_DTD_NODE) &&
5385 (tmp->type != XML_ENTITY_REF_NODE) &&
5386 (tmp->children->type != XML_ENTITY_DECL)) {
5387 tmp = tmp->children;
5388 continue;
5389 }
5390 if (tmp == node)
5391 break;
5392
5393 if (tmp->next != NULL) {
5394 tmp = tmp->next;
5395 continue;
5396 }
5397
5398 do {
5399 tmp = tmp->parent;
5400 if (tmp == NULL)
5401 break;
5402 if (tmp == node) {
5403 tmp = NULL;
5404 break;
5405 }
5406 if (tmp->next != NULL) {
5407 tmp = tmp->next;
5408 break;
5409 }
5410 } while (tmp != NULL);
5411 }
5412 return(ret);
5413 }
5414
5415 /**
5416 * xmlXPathStringHash:
5417 * @string: a string
5418 *
5419 * Function computing the beginning of the string value of the node,
5420 * used to speed up comparisons
5421 *
5422 * Returns an int usable as a hash
5423 */
5424 static unsigned int
xmlXPathStringHash(const xmlChar * string)5425 xmlXPathStringHash(const xmlChar * string) {
5426 if (string == NULL)
5427 return(0);
5428 if (string[0] == 0)
5429 return(0);
5430 return(string[0] + (string[1] << 8));
5431 }
5432
5433 /**
5434 * xmlXPathCompareNodeSetFloat:
5435 * @ctxt: the XPath Parser context
5436 * @inf: less than (1) or greater than (0)
5437 * @strict: is the comparison strict
5438 * @arg: the node set
5439 * @f: the value
5440 *
5441 * Implement the compare operation between a nodeset and a number
5442 * @ns < @val (1, 1, ...
5443 * @ns <= @val (1, 0, ...
5444 * @ns > @val (0, 1, ...
5445 * @ns >= @val (0, 0, ...
5446 *
5447 * If one object to be compared is a node-set and the other is a number,
5448 * then the comparison will be true if and only if there is a node in the
5449 * node-set such that the result of performing the comparison on the number
5450 * to be compared and on the result of converting the string-value of that
5451 * node to a number using the number function is true.
5452 *
5453 * Returns 0 or 1 depending on the results of the test.
5454 */
5455 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)5456 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5457 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5458 int i, ret = 0;
5459 xmlNodeSetPtr ns;
5460 xmlChar *str2;
5461
5462 if ((f == NULL) || (arg == NULL) ||
5463 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5464 xmlXPathReleaseObject(ctxt->context, arg);
5465 xmlXPathReleaseObject(ctxt->context, f);
5466 return(0);
5467 }
5468 ns = arg->nodesetval;
5469 if (ns != NULL) {
5470 for (i = 0;i < ns->nodeNr;i++) {
5471 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5472 if (str2 != NULL) {
5473 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5474 xmlFree(str2);
5475 xmlXPathNumberFunction(ctxt, 1);
5476 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5477 ret = xmlXPathCompareValues(ctxt, inf, strict);
5478 if (ret)
5479 break;
5480 } else {
5481 xmlXPathPErrMemory(ctxt);
5482 }
5483 }
5484 }
5485 xmlXPathReleaseObject(ctxt->context, arg);
5486 xmlXPathReleaseObject(ctxt->context, f);
5487 return(ret);
5488 }
5489
5490 /**
5491 * xmlXPathCompareNodeSetString:
5492 * @ctxt: the XPath Parser context
5493 * @inf: less than (1) or greater than (0)
5494 * @strict: is the comparison strict
5495 * @arg: the node set
5496 * @s: the value
5497 *
5498 * Implement the compare operation between a nodeset and a string
5499 * @ns < @val (1, 1, ...
5500 * @ns <= @val (1, 0, ...
5501 * @ns > @val (0, 1, ...
5502 * @ns >= @val (0, 0, ...
5503 *
5504 * If one object to be compared is a node-set and the other is a string,
5505 * then the comparison will be true if and only if there is a node in
5506 * the node-set such that the result of performing the comparison on the
5507 * string-value of the node and the other string is true.
5508 *
5509 * Returns 0 or 1 depending on the results of the test.
5510 */
5511 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)5512 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5513 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5514 int i, ret = 0;
5515 xmlNodeSetPtr ns;
5516 xmlChar *str2;
5517
5518 if ((s == NULL) || (arg == NULL) ||
5519 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5520 xmlXPathReleaseObject(ctxt->context, arg);
5521 xmlXPathReleaseObject(ctxt->context, s);
5522 return(0);
5523 }
5524 ns = arg->nodesetval;
5525 if (ns != NULL) {
5526 for (i = 0;i < ns->nodeNr;i++) {
5527 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5528 if (str2 != NULL) {
5529 valuePush(ctxt,
5530 xmlXPathCacheNewString(ctxt, str2));
5531 xmlFree(str2);
5532 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5533 ret = xmlXPathCompareValues(ctxt, inf, strict);
5534 if (ret)
5535 break;
5536 } else {
5537 xmlXPathPErrMemory(ctxt);
5538 }
5539 }
5540 }
5541 xmlXPathReleaseObject(ctxt->context, arg);
5542 xmlXPathReleaseObject(ctxt->context, s);
5543 return(ret);
5544 }
5545
5546 /**
5547 * xmlXPathCompareNodeSets:
5548 * @inf: less than (1) or greater than (0)
5549 * @strict: is the comparison strict
5550 * @arg1: the first node set object
5551 * @arg2: the second node set object
5552 *
5553 * Implement the compare operation on nodesets:
5554 *
5555 * If both objects to be compared are node-sets, then the comparison
5556 * will be true if and only if there is a node in the first node-set
5557 * and a node in the second node-set such that the result of performing
5558 * the comparison on the string-values of the two nodes is true.
5559 * ....
5560 * When neither object to be compared is a node-set and the operator
5561 * is <=, <, >= or >, then the objects are compared by converting both
5562 * objects to numbers and comparing the numbers according to IEEE 754.
5563 * ....
5564 * The number function converts its argument to a number as follows:
5565 * - a string that consists of optional whitespace followed by an
5566 * optional minus sign followed by a Number followed by whitespace
5567 * is converted to the IEEE 754 number that is nearest (according
5568 * to the IEEE 754 round-to-nearest rule) to the mathematical value
5569 * represented by the string; any other string is converted to NaN
5570 *
5571 * Conclusion all nodes need to be converted first to their string value
5572 * and then the comparison must be done when possible
5573 */
5574 static int
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5575 xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5576 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5577 int i, j, init = 0;
5578 double val1;
5579 double *values2;
5580 int ret = 0;
5581 xmlNodeSetPtr ns1;
5582 xmlNodeSetPtr ns2;
5583
5584 if ((arg1 == NULL) ||
5585 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5586 xmlXPathFreeObject(arg2);
5587 return(0);
5588 }
5589 if ((arg2 == NULL) ||
5590 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5591 xmlXPathFreeObject(arg1);
5592 xmlXPathFreeObject(arg2);
5593 return(0);
5594 }
5595
5596 ns1 = arg1->nodesetval;
5597 ns2 = arg2->nodesetval;
5598
5599 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5600 xmlXPathFreeObject(arg1);
5601 xmlXPathFreeObject(arg2);
5602 return(0);
5603 }
5604 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5605 xmlXPathFreeObject(arg1);
5606 xmlXPathFreeObject(arg2);
5607 return(0);
5608 }
5609
5610 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5611 if (values2 == NULL) {
5612 xmlXPathPErrMemory(ctxt);
5613 xmlXPathFreeObject(arg1);
5614 xmlXPathFreeObject(arg2);
5615 return(0);
5616 }
5617 for (i = 0;i < ns1->nodeNr;i++) {
5618 val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5619 if (xmlXPathIsNaN(val1))
5620 continue;
5621 for (j = 0;j < ns2->nodeNr;j++) {
5622 if (init == 0) {
5623 values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5624 ns2->nodeTab[j]);
5625 }
5626 if (xmlXPathIsNaN(values2[j]))
5627 continue;
5628 if (inf && strict)
5629 ret = (val1 < values2[j]);
5630 else if (inf && !strict)
5631 ret = (val1 <= values2[j]);
5632 else if (!inf && strict)
5633 ret = (val1 > values2[j]);
5634 else if (!inf && !strict)
5635 ret = (val1 >= values2[j]);
5636 if (ret)
5637 break;
5638 }
5639 if (ret)
5640 break;
5641 init = 1;
5642 }
5643 xmlFree(values2);
5644 xmlXPathFreeObject(arg1);
5645 xmlXPathFreeObject(arg2);
5646 return(ret);
5647 }
5648
5649 /**
5650 * xmlXPathCompareNodeSetValue:
5651 * @ctxt: the XPath Parser context
5652 * @inf: less than (1) or greater than (0)
5653 * @strict: is the comparison strict
5654 * @arg: the node set
5655 * @val: the value
5656 *
5657 * Implement the compare operation between a nodeset and a value
5658 * @ns < @val (1, 1, ...
5659 * @ns <= @val (1, 0, ...
5660 * @ns > @val (0, 1, ...
5661 * @ns >= @val (0, 0, ...
5662 *
5663 * If one object to be compared is a node-set and the other is a boolean,
5664 * then the comparison will be true if and only if the result of performing
5665 * the comparison on the boolean and on the result of converting
5666 * the node-set to a boolean using the boolean function is true.
5667 *
5668 * Returns 0 or 1 depending on the results of the test.
5669 */
5670 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)5671 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5672 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5673 if ((val == NULL) || (arg == NULL) ||
5674 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5675 return(0);
5676
5677 switch(val->type) {
5678 case XPATH_NUMBER:
5679 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5680 case XPATH_NODESET:
5681 case XPATH_XSLT_TREE:
5682 return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5683 case XPATH_STRING:
5684 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5685 case XPATH_BOOLEAN:
5686 valuePush(ctxt, arg);
5687 xmlXPathBooleanFunction(ctxt, 1);
5688 valuePush(ctxt, val);
5689 return(xmlXPathCompareValues(ctxt, inf, strict));
5690 default:
5691 xmlXPathReleaseObject(ctxt->context, arg);
5692 xmlXPathReleaseObject(ctxt->context, val);
5693 XP_ERROR0(XPATH_INVALID_TYPE);
5694 }
5695 return(0);
5696 }
5697
5698 /**
5699 * xmlXPathEqualNodeSetString:
5700 * @arg: the nodeset object argument
5701 * @str: the string to compare to.
5702 * @neq: flag to show whether for '=' (0) or '!=' (1)
5703 *
5704 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5705 * If one object to be compared is a node-set and the other is a string,
5706 * then the comparison will be true if and only if there is a node in
5707 * the node-set such that the result of performing the comparison on the
5708 * string-value of the node and the other string is true.
5709 *
5710 * Returns 0 or 1 depending on the results of the test.
5711 */
5712 static int
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,const xmlChar * str,int neq)5713 xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5714 xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5715 {
5716 int i;
5717 xmlNodeSetPtr ns;
5718 xmlChar *str2;
5719 unsigned int hash;
5720
5721 if ((str == NULL) || (arg == NULL) ||
5722 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5723 return (0);
5724 ns = arg->nodesetval;
5725 /*
5726 * A NULL nodeset compared with a string is always false
5727 * (since there is no node equal, and no node not equal)
5728 */
5729 if ((ns == NULL) || (ns->nodeNr <= 0) )
5730 return (0);
5731 hash = xmlXPathStringHash(str);
5732 for (i = 0; i < ns->nodeNr; i++) {
5733 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5734 str2 = xmlNodeGetContent(ns->nodeTab[i]);
5735 if (str2 == NULL) {
5736 xmlXPathPErrMemory(ctxt);
5737 return(0);
5738 }
5739 if (xmlStrEqual(str, str2)) {
5740 xmlFree(str2);
5741 if (neq)
5742 continue;
5743 return (1);
5744 } else if (neq) {
5745 xmlFree(str2);
5746 return (1);
5747 }
5748 xmlFree(str2);
5749 } else if (neq)
5750 return (1);
5751 }
5752 return (0);
5753 }
5754
5755 /**
5756 * xmlXPathEqualNodeSetFloat:
5757 * @arg: the nodeset object argument
5758 * @f: the float to compare to
5759 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
5760 *
5761 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5762 * If one object to be compared is a node-set and the other is a number,
5763 * then the comparison will be true if and only if there is a node in
5764 * the node-set such that the result of performing the comparison on the
5765 * number to be compared and on the result of converting the string-value
5766 * of that node to a number using the number function is true.
5767 *
5768 * Returns 0 or 1 depending on the results of the test.
5769 */
5770 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)5771 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5772 xmlXPathObjectPtr arg, double f, int neq) {
5773 int i, ret=0;
5774 xmlNodeSetPtr ns;
5775 xmlChar *str2;
5776 xmlXPathObjectPtr val;
5777 double v;
5778
5779 if ((arg == NULL) ||
5780 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5781 return(0);
5782
5783 ns = arg->nodesetval;
5784 if (ns != NULL) {
5785 for (i=0;i<ns->nodeNr;i++) {
5786 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5787 if (str2 != NULL) {
5788 valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5789 xmlFree(str2);
5790 xmlXPathNumberFunction(ctxt, 1);
5791 CHECK_ERROR0;
5792 val = valuePop(ctxt);
5793 v = val->floatval;
5794 xmlXPathReleaseObject(ctxt->context, val);
5795 if (!xmlXPathIsNaN(v)) {
5796 if ((!neq) && (v==f)) {
5797 ret = 1;
5798 break;
5799 } else if ((neq) && (v!=f)) {
5800 ret = 1;
5801 break;
5802 }
5803 } else { /* NaN is unequal to any value */
5804 if (neq)
5805 ret = 1;
5806 }
5807 } else {
5808 xmlXPathPErrMemory(ctxt);
5809 }
5810 }
5811 }
5812
5813 return(ret);
5814 }
5815
5816
5817 /**
5818 * xmlXPathEqualNodeSets:
5819 * @arg1: first nodeset object argument
5820 * @arg2: second nodeset object argument
5821 * @neq: flag to show whether to test '=' (0) or '!=' (1)
5822 *
5823 * Implement the equal / not equal operation on XPath nodesets:
5824 * @arg1 == @arg2 or @arg1 != @arg2
5825 * If both objects to be compared are node-sets, then the comparison
5826 * will be true if and only if there is a node in the first node-set and
5827 * a node in the second node-set such that the result of performing the
5828 * comparison on the string-values of the two nodes is true.
5829 *
5830 * (needless to say, this is a costly operation)
5831 *
5832 * Returns 0 or 1 depending on the results of the test.
5833 */
5834 static int
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)5835 xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5836 xmlXPathObjectPtr arg2, int neq) {
5837 int i, j;
5838 unsigned int *hashs1;
5839 unsigned int *hashs2;
5840 xmlChar **values1;
5841 xmlChar **values2;
5842 int ret = 0;
5843 xmlNodeSetPtr ns1;
5844 xmlNodeSetPtr ns2;
5845
5846 if ((arg1 == NULL) ||
5847 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5848 return(0);
5849 if ((arg2 == NULL) ||
5850 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5851 return(0);
5852
5853 ns1 = arg1->nodesetval;
5854 ns2 = arg2->nodesetval;
5855
5856 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5857 return(0);
5858 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5859 return(0);
5860
5861 /*
5862 * for equal, check if there is a node pertaining to both sets
5863 */
5864 if (neq == 0)
5865 for (i = 0;i < ns1->nodeNr;i++)
5866 for (j = 0;j < ns2->nodeNr;j++)
5867 if (ns1->nodeTab[i] == ns2->nodeTab[j])
5868 return(1);
5869
5870 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5871 if (values1 == NULL) {
5872 xmlXPathPErrMemory(ctxt);
5873 return(0);
5874 }
5875 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5876 if (hashs1 == NULL) {
5877 xmlXPathPErrMemory(ctxt);
5878 xmlFree(values1);
5879 return(0);
5880 }
5881 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5882 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5883 if (values2 == NULL) {
5884 xmlXPathPErrMemory(ctxt);
5885 xmlFree(hashs1);
5886 xmlFree(values1);
5887 return(0);
5888 }
5889 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5890 if (hashs2 == NULL) {
5891 xmlXPathPErrMemory(ctxt);
5892 xmlFree(hashs1);
5893 xmlFree(values1);
5894 xmlFree(values2);
5895 return(0);
5896 }
5897 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5898 for (i = 0;i < ns1->nodeNr;i++) {
5899 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5900 for (j = 0;j < ns2->nodeNr;j++) {
5901 if (i == 0)
5902 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5903 if (hashs1[i] != hashs2[j]) {
5904 if (neq) {
5905 ret = 1;
5906 break;
5907 }
5908 }
5909 else {
5910 if (values1[i] == NULL) {
5911 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5912 if (values1[i] == NULL)
5913 xmlXPathPErrMemory(ctxt);
5914 }
5915 if (values2[j] == NULL) {
5916 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5917 if (values2[j] == NULL)
5918 xmlXPathPErrMemory(ctxt);
5919 }
5920 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5921 if (ret)
5922 break;
5923 }
5924 }
5925 if (ret)
5926 break;
5927 }
5928 for (i = 0;i < ns1->nodeNr;i++)
5929 if (values1[i] != NULL)
5930 xmlFree(values1[i]);
5931 for (j = 0;j < ns2->nodeNr;j++)
5932 if (values2[j] != NULL)
5933 xmlFree(values2[j]);
5934 xmlFree(values1);
5935 xmlFree(values2);
5936 xmlFree(hashs1);
5937 xmlFree(hashs2);
5938 return(ret);
5939 }
5940
5941 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)5942 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5943 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5944 int ret = 0;
5945 /*
5946 *At this point we are assured neither arg1 nor arg2
5947 *is a nodeset, so we can just pick the appropriate routine.
5948 */
5949 switch (arg1->type) {
5950 case XPATH_UNDEFINED:
5951 break;
5952 case XPATH_BOOLEAN:
5953 switch (arg2->type) {
5954 case XPATH_UNDEFINED:
5955 break;
5956 case XPATH_BOOLEAN:
5957 ret = (arg1->boolval == arg2->boolval);
5958 break;
5959 case XPATH_NUMBER:
5960 ret = (arg1->boolval ==
5961 xmlXPathCastNumberToBoolean(arg2->floatval));
5962 break;
5963 case XPATH_STRING:
5964 if ((arg2->stringval == NULL) ||
5965 (arg2->stringval[0] == 0)) ret = 0;
5966 else
5967 ret = 1;
5968 ret = (arg1->boolval == ret);
5969 break;
5970 case XPATH_USERS:
5971 #ifdef LIBXML_XPTR_LOCS_ENABLED
5972 case XPATH_POINT:
5973 case XPATH_RANGE:
5974 case XPATH_LOCATIONSET:
5975 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5976 /* TODO */
5977 break;
5978 case XPATH_NODESET:
5979 case XPATH_XSLT_TREE:
5980 break;
5981 }
5982 break;
5983 case XPATH_NUMBER:
5984 switch (arg2->type) {
5985 case XPATH_UNDEFINED:
5986 break;
5987 case XPATH_BOOLEAN:
5988 ret = (arg2->boolval==
5989 xmlXPathCastNumberToBoolean(arg1->floatval));
5990 break;
5991 case XPATH_STRING:
5992 valuePush(ctxt, arg2);
5993 xmlXPathNumberFunction(ctxt, 1);
5994 arg2 = valuePop(ctxt);
5995 if (ctxt->error)
5996 break;
5997 /* Falls through. */
5998 case XPATH_NUMBER:
5999 /* Hand check NaN and Infinity equalities */
6000 if (xmlXPathIsNaN(arg1->floatval) ||
6001 xmlXPathIsNaN(arg2->floatval)) {
6002 ret = 0;
6003 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6004 if (xmlXPathIsInf(arg2->floatval) == 1)
6005 ret = 1;
6006 else
6007 ret = 0;
6008 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6009 if (xmlXPathIsInf(arg2->floatval) == -1)
6010 ret = 1;
6011 else
6012 ret = 0;
6013 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6014 if (xmlXPathIsInf(arg1->floatval) == 1)
6015 ret = 1;
6016 else
6017 ret = 0;
6018 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6019 if (xmlXPathIsInf(arg1->floatval) == -1)
6020 ret = 1;
6021 else
6022 ret = 0;
6023 } else {
6024 ret = (arg1->floatval == arg2->floatval);
6025 }
6026 break;
6027 case XPATH_USERS:
6028 #ifdef LIBXML_XPTR_LOCS_ENABLED
6029 case XPATH_POINT:
6030 case XPATH_RANGE:
6031 case XPATH_LOCATIONSET:
6032 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6033 /* TODO */
6034 break;
6035 case XPATH_NODESET:
6036 case XPATH_XSLT_TREE:
6037 break;
6038 }
6039 break;
6040 case XPATH_STRING:
6041 switch (arg2->type) {
6042 case XPATH_UNDEFINED:
6043 break;
6044 case XPATH_BOOLEAN:
6045 if ((arg1->stringval == NULL) ||
6046 (arg1->stringval[0] == 0)) ret = 0;
6047 else
6048 ret = 1;
6049 ret = (arg2->boolval == ret);
6050 break;
6051 case XPATH_STRING:
6052 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6053 break;
6054 case XPATH_NUMBER:
6055 valuePush(ctxt, arg1);
6056 xmlXPathNumberFunction(ctxt, 1);
6057 arg1 = valuePop(ctxt);
6058 if (ctxt->error)
6059 break;
6060 /* Hand check NaN and Infinity equalities */
6061 if (xmlXPathIsNaN(arg1->floatval) ||
6062 xmlXPathIsNaN(arg2->floatval)) {
6063 ret = 0;
6064 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6065 if (xmlXPathIsInf(arg2->floatval) == 1)
6066 ret = 1;
6067 else
6068 ret = 0;
6069 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6070 if (xmlXPathIsInf(arg2->floatval) == -1)
6071 ret = 1;
6072 else
6073 ret = 0;
6074 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6075 if (xmlXPathIsInf(arg1->floatval) == 1)
6076 ret = 1;
6077 else
6078 ret = 0;
6079 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6080 if (xmlXPathIsInf(arg1->floatval) == -1)
6081 ret = 1;
6082 else
6083 ret = 0;
6084 } else {
6085 ret = (arg1->floatval == arg2->floatval);
6086 }
6087 break;
6088 case XPATH_USERS:
6089 #ifdef LIBXML_XPTR_LOCS_ENABLED
6090 case XPATH_POINT:
6091 case XPATH_RANGE:
6092 case XPATH_LOCATIONSET:
6093 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6094 /* TODO */
6095 break;
6096 case XPATH_NODESET:
6097 case XPATH_XSLT_TREE:
6098 break;
6099 }
6100 break;
6101 case XPATH_USERS:
6102 #ifdef LIBXML_XPTR_LOCS_ENABLED
6103 case XPATH_POINT:
6104 case XPATH_RANGE:
6105 case XPATH_LOCATIONSET:
6106 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6107 /* TODO */
6108 break;
6109 case XPATH_NODESET:
6110 case XPATH_XSLT_TREE:
6111 break;
6112 }
6113 xmlXPathReleaseObject(ctxt->context, arg1);
6114 xmlXPathReleaseObject(ctxt->context, arg2);
6115 return(ret);
6116 }
6117
6118 /**
6119 * xmlXPathEqualValues:
6120 * @ctxt: the XPath Parser context
6121 *
6122 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6123 *
6124 * Returns 0 or 1 depending on the results of the test.
6125 */
6126 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)6127 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6128 xmlXPathObjectPtr arg1, arg2, argtmp;
6129 int ret = 0;
6130
6131 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6132 arg2 = valuePop(ctxt);
6133 arg1 = valuePop(ctxt);
6134 if ((arg1 == NULL) || (arg2 == NULL)) {
6135 if (arg1 != NULL)
6136 xmlXPathReleaseObject(ctxt->context, arg1);
6137 else
6138 xmlXPathReleaseObject(ctxt->context, arg2);
6139 XP_ERROR0(XPATH_INVALID_OPERAND);
6140 }
6141
6142 if (arg1 == arg2) {
6143 xmlXPathFreeObject(arg1);
6144 return(1);
6145 }
6146
6147 /*
6148 *If either argument is a nodeset, it's a 'special case'
6149 */
6150 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6151 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6152 /*
6153 *Hack it to assure arg1 is the nodeset
6154 */
6155 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6156 argtmp = arg2;
6157 arg2 = arg1;
6158 arg1 = argtmp;
6159 }
6160 switch (arg2->type) {
6161 case XPATH_UNDEFINED:
6162 break;
6163 case XPATH_NODESET:
6164 case XPATH_XSLT_TREE:
6165 ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
6166 break;
6167 case XPATH_BOOLEAN:
6168 if ((arg1->nodesetval == NULL) ||
6169 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6170 else
6171 ret = 1;
6172 ret = (ret == arg2->boolval);
6173 break;
6174 case XPATH_NUMBER:
6175 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6176 break;
6177 case XPATH_STRING:
6178 ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6179 arg2->stringval, 0);
6180 break;
6181 case XPATH_USERS:
6182 #ifdef LIBXML_XPTR_LOCS_ENABLED
6183 case XPATH_POINT:
6184 case XPATH_RANGE:
6185 case XPATH_LOCATIONSET:
6186 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6187 /* TODO */
6188 break;
6189 }
6190 xmlXPathReleaseObject(ctxt->context, arg1);
6191 xmlXPathReleaseObject(ctxt->context, arg2);
6192 return(ret);
6193 }
6194
6195 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6196 }
6197
6198 /**
6199 * xmlXPathNotEqualValues:
6200 * @ctxt: the XPath Parser context
6201 *
6202 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6203 *
6204 * Returns 0 or 1 depending on the results of the test.
6205 */
6206 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)6207 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6208 xmlXPathObjectPtr arg1, arg2, argtmp;
6209 int ret = 0;
6210
6211 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6212 arg2 = valuePop(ctxt);
6213 arg1 = valuePop(ctxt);
6214 if ((arg1 == NULL) || (arg2 == NULL)) {
6215 if (arg1 != NULL)
6216 xmlXPathReleaseObject(ctxt->context, arg1);
6217 else
6218 xmlXPathReleaseObject(ctxt->context, arg2);
6219 XP_ERROR0(XPATH_INVALID_OPERAND);
6220 }
6221
6222 if (arg1 == arg2) {
6223 xmlXPathReleaseObject(ctxt->context, arg1);
6224 return(0);
6225 }
6226
6227 /*
6228 *If either argument is a nodeset, it's a 'special case'
6229 */
6230 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6231 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6232 /*
6233 *Hack it to assure arg1 is the nodeset
6234 */
6235 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6236 argtmp = arg2;
6237 arg2 = arg1;
6238 arg1 = argtmp;
6239 }
6240 switch (arg2->type) {
6241 case XPATH_UNDEFINED:
6242 break;
6243 case XPATH_NODESET:
6244 case XPATH_XSLT_TREE:
6245 ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
6246 break;
6247 case XPATH_BOOLEAN:
6248 if ((arg1->nodesetval == NULL) ||
6249 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6250 else
6251 ret = 1;
6252 ret = (ret != arg2->boolval);
6253 break;
6254 case XPATH_NUMBER:
6255 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6256 break;
6257 case XPATH_STRING:
6258 ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6259 arg2->stringval, 1);
6260 break;
6261 case XPATH_USERS:
6262 #ifdef LIBXML_XPTR_LOCS_ENABLED
6263 case XPATH_POINT:
6264 case XPATH_RANGE:
6265 case XPATH_LOCATIONSET:
6266 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6267 /* TODO */
6268 break;
6269 }
6270 xmlXPathReleaseObject(ctxt->context, arg1);
6271 xmlXPathReleaseObject(ctxt->context, arg2);
6272 return(ret);
6273 }
6274
6275 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6276 }
6277
6278 /**
6279 * xmlXPathCompareValues:
6280 * @ctxt: the XPath Parser context
6281 * @inf: less than (1) or greater than (0)
6282 * @strict: is the comparison strict
6283 *
6284 * Implement the compare operation on XPath objects:
6285 * @arg1 < @arg2 (1, 1, ...
6286 * @arg1 <= @arg2 (1, 0, ...
6287 * @arg1 > @arg2 (0, 1, ...
6288 * @arg1 >= @arg2 (0, 0, ...
6289 *
6290 * When neither object to be compared is a node-set and the operator is
6291 * <=, <, >=, >, then the objects are compared by converted both objects
6292 * to numbers and comparing the numbers according to IEEE 754. The <
6293 * comparison will be true if and only if the first number is less than the
6294 * second number. The <= comparison will be true if and only if the first
6295 * number is less than or equal to the second number. The > comparison
6296 * will be true if and only if the first number is greater than the second
6297 * number. The >= comparison will be true if and only if the first number
6298 * is greater than or equal to the second number.
6299 *
6300 * Returns 1 if the comparison succeeded, 0 if it failed
6301 */
6302 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)6303 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6304 int ret = 0, arg1i = 0, arg2i = 0;
6305 xmlXPathObjectPtr arg1, arg2;
6306
6307 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6308 arg2 = valuePop(ctxt);
6309 arg1 = valuePop(ctxt);
6310 if ((arg1 == NULL) || (arg2 == NULL)) {
6311 if (arg1 != NULL)
6312 xmlXPathReleaseObject(ctxt->context, arg1);
6313 else
6314 xmlXPathReleaseObject(ctxt->context, arg2);
6315 XP_ERROR0(XPATH_INVALID_OPERAND);
6316 }
6317
6318 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6319 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6320 /*
6321 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6322 * are not freed from within this routine; they will be freed from the
6323 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6324 */
6325 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6326 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6327 ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6328 } else {
6329 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6330 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6331 arg1, arg2);
6332 } else {
6333 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6334 arg2, arg1);
6335 }
6336 }
6337 return(ret);
6338 }
6339
6340 if (arg1->type != XPATH_NUMBER) {
6341 valuePush(ctxt, arg1);
6342 xmlXPathNumberFunction(ctxt, 1);
6343 arg1 = valuePop(ctxt);
6344 }
6345 if (arg2->type != XPATH_NUMBER) {
6346 valuePush(ctxt, arg2);
6347 xmlXPathNumberFunction(ctxt, 1);
6348 arg2 = valuePop(ctxt);
6349 }
6350 if (ctxt->error)
6351 goto error;
6352 /*
6353 * Add tests for infinity and nan
6354 * => feedback on 3.4 for Inf and NaN
6355 */
6356 /* Hand check NaN and Infinity comparisons */
6357 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6358 ret=0;
6359 } else {
6360 arg1i=xmlXPathIsInf(arg1->floatval);
6361 arg2i=xmlXPathIsInf(arg2->floatval);
6362 if (inf && strict) {
6363 if ((arg1i == -1 && arg2i != -1) ||
6364 (arg2i == 1 && arg1i != 1)) {
6365 ret = 1;
6366 } else if (arg1i == 0 && arg2i == 0) {
6367 ret = (arg1->floatval < arg2->floatval);
6368 } else {
6369 ret = 0;
6370 }
6371 }
6372 else if (inf && !strict) {
6373 if (arg1i == -1 || arg2i == 1) {
6374 ret = 1;
6375 } else if (arg1i == 0 && arg2i == 0) {
6376 ret = (arg1->floatval <= arg2->floatval);
6377 } else {
6378 ret = 0;
6379 }
6380 }
6381 else if (!inf && strict) {
6382 if ((arg1i == 1 && arg2i != 1) ||
6383 (arg2i == -1 && arg1i != -1)) {
6384 ret = 1;
6385 } else if (arg1i == 0 && arg2i == 0) {
6386 ret = (arg1->floatval > arg2->floatval);
6387 } else {
6388 ret = 0;
6389 }
6390 }
6391 else if (!inf && !strict) {
6392 if (arg1i == 1 || arg2i == -1) {
6393 ret = 1;
6394 } else if (arg1i == 0 && arg2i == 0) {
6395 ret = (arg1->floatval >= arg2->floatval);
6396 } else {
6397 ret = 0;
6398 }
6399 }
6400 }
6401 error:
6402 xmlXPathReleaseObject(ctxt->context, arg1);
6403 xmlXPathReleaseObject(ctxt->context, arg2);
6404 return(ret);
6405 }
6406
6407 /**
6408 * xmlXPathValueFlipSign:
6409 * @ctxt: the XPath Parser context
6410 *
6411 * Implement the unary - operation on an XPath object
6412 * The numeric operators convert their operands to numbers as if
6413 * by calling the number function.
6414 */
6415 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)6416 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6417 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6418 CAST_TO_NUMBER;
6419 CHECK_TYPE(XPATH_NUMBER);
6420 ctxt->value->floatval = -ctxt->value->floatval;
6421 }
6422
6423 /**
6424 * xmlXPathAddValues:
6425 * @ctxt: the XPath Parser context
6426 *
6427 * Implement the add operation on XPath objects:
6428 * The numeric operators convert their operands to numbers as if
6429 * by calling the number function.
6430 */
6431 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)6432 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6433 xmlXPathObjectPtr arg;
6434 double val;
6435
6436 arg = valuePop(ctxt);
6437 if (arg == NULL)
6438 XP_ERROR(XPATH_INVALID_OPERAND);
6439 val = xmlXPathCastToNumberInternal(ctxt, arg);
6440 xmlXPathReleaseObject(ctxt->context, arg);
6441 CAST_TO_NUMBER;
6442 CHECK_TYPE(XPATH_NUMBER);
6443 ctxt->value->floatval += val;
6444 }
6445
6446 /**
6447 * xmlXPathSubValues:
6448 * @ctxt: the XPath Parser context
6449 *
6450 * Implement the subtraction operation on XPath objects:
6451 * The numeric operators convert their operands to numbers as if
6452 * by calling the number function.
6453 */
6454 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)6455 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6456 xmlXPathObjectPtr arg;
6457 double val;
6458
6459 arg = valuePop(ctxt);
6460 if (arg == NULL)
6461 XP_ERROR(XPATH_INVALID_OPERAND);
6462 val = xmlXPathCastToNumberInternal(ctxt, arg);
6463 xmlXPathReleaseObject(ctxt->context, arg);
6464 CAST_TO_NUMBER;
6465 CHECK_TYPE(XPATH_NUMBER);
6466 ctxt->value->floatval -= val;
6467 }
6468
6469 /**
6470 * xmlXPathMultValues:
6471 * @ctxt: the XPath Parser context
6472 *
6473 * Implement the multiply operation on XPath objects:
6474 * The numeric operators convert their operands to numbers as if
6475 * by calling the number function.
6476 */
6477 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)6478 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6479 xmlXPathObjectPtr arg;
6480 double val;
6481
6482 arg = valuePop(ctxt);
6483 if (arg == NULL)
6484 XP_ERROR(XPATH_INVALID_OPERAND);
6485 val = xmlXPathCastToNumberInternal(ctxt, arg);
6486 xmlXPathReleaseObject(ctxt->context, arg);
6487 CAST_TO_NUMBER;
6488 CHECK_TYPE(XPATH_NUMBER);
6489 ctxt->value->floatval *= val;
6490 }
6491
6492 /**
6493 * xmlXPathDivValues:
6494 * @ctxt: the XPath Parser context
6495 *
6496 * Implement the div operation on XPath objects @arg1 / @arg2:
6497 * The numeric operators convert their operands to numbers as if
6498 * by calling the number function.
6499 */
6500 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6501 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)6502 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6503 xmlXPathObjectPtr arg;
6504 double val;
6505
6506 arg = valuePop(ctxt);
6507 if (arg == NULL)
6508 XP_ERROR(XPATH_INVALID_OPERAND);
6509 val = xmlXPathCastToNumberInternal(ctxt, arg);
6510 xmlXPathReleaseObject(ctxt->context, arg);
6511 CAST_TO_NUMBER;
6512 CHECK_TYPE(XPATH_NUMBER);
6513 ctxt->value->floatval /= val;
6514 }
6515
6516 /**
6517 * xmlXPathModValues:
6518 * @ctxt: the XPath Parser context
6519 *
6520 * Implement the mod operation on XPath objects: @arg1 / @arg2
6521 * The numeric operators convert their operands to numbers as if
6522 * by calling the number function.
6523 */
6524 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)6525 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6526 xmlXPathObjectPtr arg;
6527 double arg1, arg2;
6528
6529 arg = valuePop(ctxt);
6530 if (arg == NULL)
6531 XP_ERROR(XPATH_INVALID_OPERAND);
6532 arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6533 xmlXPathReleaseObject(ctxt->context, arg);
6534 CAST_TO_NUMBER;
6535 CHECK_TYPE(XPATH_NUMBER);
6536 arg1 = ctxt->value->floatval;
6537 if (arg2 == 0)
6538 ctxt->value->floatval = xmlXPathNAN;
6539 else {
6540 ctxt->value->floatval = fmod(arg1, arg2);
6541 }
6542 }
6543
6544 /************************************************************************
6545 * *
6546 * The traversal functions *
6547 * *
6548 ************************************************************************/
6549
6550 /*
6551 * A traversal function enumerates nodes along an axis.
6552 * Initially it must be called with NULL, and it indicates
6553 * termination on the axis by returning NULL.
6554 */
6555 typedef xmlNodePtr (*xmlXPathTraversalFunction)
6556 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6557
6558 /*
6559 * xmlXPathTraversalFunctionExt:
6560 * A traversal function enumerates nodes along an axis.
6561 * Initially it must be called with NULL, and it indicates
6562 * termination on the axis by returning NULL.
6563 * The context node of the traversal is specified via @contextNode.
6564 */
6565 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6566 (xmlNodePtr cur, xmlNodePtr contextNode);
6567
6568 /*
6569 * xmlXPathNodeSetMergeFunction:
6570 * Used for merging node sets in xmlXPathCollectAndTest().
6571 */
6572 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6573 (xmlNodeSetPtr, xmlNodeSetPtr);
6574
6575
6576 /**
6577 * xmlXPathNextSelf:
6578 * @ctxt: the XPath Parser context
6579 * @cur: the current node in the traversal
6580 *
6581 * Traversal function for the "self" direction
6582 * The self axis contains just the context node itself
6583 *
6584 * Returns the next element following that axis
6585 */
6586 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6587 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6588 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6589 if (cur == NULL)
6590 return(ctxt->context->node);
6591 return(NULL);
6592 }
6593
6594 /**
6595 * xmlXPathNextChild:
6596 * @ctxt: the XPath Parser context
6597 * @cur: the current node in the traversal
6598 *
6599 * Traversal function for the "child" direction
6600 * The child axis contains the children of the context node in document order.
6601 *
6602 * Returns the next element following that axis
6603 */
6604 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6605 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6606 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6607 if (cur == NULL) {
6608 if (ctxt->context->node == NULL) return(NULL);
6609 switch (ctxt->context->node->type) {
6610 case XML_ELEMENT_NODE:
6611 case XML_TEXT_NODE:
6612 case XML_CDATA_SECTION_NODE:
6613 case XML_ENTITY_REF_NODE:
6614 case XML_ENTITY_NODE:
6615 case XML_PI_NODE:
6616 case XML_COMMENT_NODE:
6617 case XML_NOTATION_NODE:
6618 case XML_DTD_NODE:
6619 return(ctxt->context->node->children);
6620 case XML_DOCUMENT_NODE:
6621 case XML_DOCUMENT_TYPE_NODE:
6622 case XML_DOCUMENT_FRAG_NODE:
6623 case XML_HTML_DOCUMENT_NODE:
6624 return(((xmlDocPtr) ctxt->context->node)->children);
6625 case XML_ELEMENT_DECL:
6626 case XML_ATTRIBUTE_DECL:
6627 case XML_ENTITY_DECL:
6628 case XML_ATTRIBUTE_NODE:
6629 case XML_NAMESPACE_DECL:
6630 case XML_XINCLUDE_START:
6631 case XML_XINCLUDE_END:
6632 return(NULL);
6633 }
6634 return(NULL);
6635 }
6636 if ((cur->type == XML_DOCUMENT_NODE) ||
6637 (cur->type == XML_HTML_DOCUMENT_NODE))
6638 return(NULL);
6639 return(cur->next);
6640 }
6641
6642 /**
6643 * xmlXPathNextChildElement:
6644 * @ctxt: the XPath Parser context
6645 * @cur: the current node in the traversal
6646 *
6647 * Traversal function for the "child" direction and nodes of type element.
6648 * The child axis contains the children of the context node in document order.
6649 *
6650 * Returns the next element following that axis
6651 */
6652 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6653 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6654 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6655 if (cur == NULL) {
6656 cur = ctxt->context->node;
6657 if (cur == NULL) return(NULL);
6658 /*
6659 * Get the first element child.
6660 */
6661 switch (cur->type) {
6662 case XML_ELEMENT_NODE:
6663 case XML_DOCUMENT_FRAG_NODE:
6664 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6665 case XML_ENTITY_NODE:
6666 cur = cur->children;
6667 if (cur != NULL) {
6668 if (cur->type == XML_ELEMENT_NODE)
6669 return(cur);
6670 do {
6671 cur = cur->next;
6672 } while ((cur != NULL) &&
6673 (cur->type != XML_ELEMENT_NODE));
6674 return(cur);
6675 }
6676 return(NULL);
6677 case XML_DOCUMENT_NODE:
6678 case XML_HTML_DOCUMENT_NODE:
6679 return(xmlDocGetRootElement((xmlDocPtr) cur));
6680 default:
6681 return(NULL);
6682 }
6683 return(NULL);
6684 }
6685 /*
6686 * Get the next sibling element node.
6687 */
6688 switch (cur->type) {
6689 case XML_ELEMENT_NODE:
6690 case XML_TEXT_NODE:
6691 case XML_ENTITY_REF_NODE:
6692 case XML_ENTITY_NODE:
6693 case XML_CDATA_SECTION_NODE:
6694 case XML_PI_NODE:
6695 case XML_COMMENT_NODE:
6696 case XML_XINCLUDE_END:
6697 break;
6698 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6699 default:
6700 return(NULL);
6701 }
6702 if (cur->next != NULL) {
6703 if (cur->next->type == XML_ELEMENT_NODE)
6704 return(cur->next);
6705 cur = cur->next;
6706 do {
6707 cur = cur->next;
6708 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6709 return(cur);
6710 }
6711 return(NULL);
6712 }
6713
6714 #if 0
6715 /**
6716 * xmlXPathNextDescendantOrSelfElemParent:
6717 * @ctxt: the XPath Parser context
6718 * @cur: the current node in the traversal
6719 *
6720 * Traversal function for the "descendant-or-self" axis.
6721 * Additionally it returns only nodes which can be parents of
6722 * element nodes.
6723 *
6724 *
6725 * Returns the next element following that axis
6726 */
6727 static xmlNodePtr
6728 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
6729 xmlNodePtr contextNode)
6730 {
6731 if (cur == NULL) {
6732 if (contextNode == NULL)
6733 return(NULL);
6734 switch (contextNode->type) {
6735 case XML_ELEMENT_NODE:
6736 case XML_XINCLUDE_START:
6737 case XML_DOCUMENT_FRAG_NODE:
6738 case XML_DOCUMENT_NODE:
6739 case XML_HTML_DOCUMENT_NODE:
6740 return(contextNode);
6741 default:
6742 return(NULL);
6743 }
6744 return(NULL);
6745 } else {
6746 xmlNodePtr start = cur;
6747
6748 while (cur != NULL) {
6749 switch (cur->type) {
6750 case XML_ELEMENT_NODE:
6751 /* TODO: OK to have XInclude here? */
6752 case XML_XINCLUDE_START:
6753 case XML_DOCUMENT_FRAG_NODE:
6754 if (cur != start)
6755 return(cur);
6756 if (cur->children != NULL) {
6757 cur = cur->children;
6758 continue;
6759 }
6760 break;
6761 /* Not sure if we need those here. */
6762 case XML_DOCUMENT_NODE:
6763 case XML_HTML_DOCUMENT_NODE:
6764 if (cur != start)
6765 return(cur);
6766 return(xmlDocGetRootElement((xmlDocPtr) cur));
6767 default:
6768 break;
6769 }
6770
6771 next_sibling:
6772 if ((cur == NULL) || (cur == contextNode))
6773 return(NULL);
6774 if (cur->next != NULL) {
6775 cur = cur->next;
6776 } else {
6777 cur = cur->parent;
6778 goto next_sibling;
6779 }
6780 }
6781 }
6782 return(NULL);
6783 }
6784 #endif
6785
6786 /**
6787 * xmlXPathNextDescendant:
6788 * @ctxt: the XPath Parser context
6789 * @cur: the current node in the traversal
6790 *
6791 * Traversal function for the "descendant" direction
6792 * the descendant axis contains the descendants of the context node in document
6793 * order; a descendant is a child or a child of a child and so on.
6794 *
6795 * Returns the next element following that axis
6796 */
6797 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6798 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6799 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6800 if (cur == NULL) {
6801 if (ctxt->context->node == NULL)
6802 return(NULL);
6803 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6804 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6805 return(NULL);
6806
6807 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6808 return(ctxt->context->doc->children);
6809 return(ctxt->context->node->children);
6810 }
6811
6812 if (cur->type == XML_NAMESPACE_DECL)
6813 return(NULL);
6814 if (cur->children != NULL) {
6815 /*
6816 * Do not descend on entities declarations
6817 */
6818 if (cur->children->type != XML_ENTITY_DECL) {
6819 cur = cur->children;
6820 /*
6821 * Skip DTDs
6822 */
6823 if (cur->type != XML_DTD_NODE)
6824 return(cur);
6825 }
6826 }
6827
6828 if (cur == ctxt->context->node) return(NULL);
6829
6830 while (cur->next != NULL) {
6831 cur = cur->next;
6832 if ((cur->type != XML_ENTITY_DECL) &&
6833 (cur->type != XML_DTD_NODE))
6834 return(cur);
6835 }
6836
6837 do {
6838 cur = cur->parent;
6839 if (cur == NULL) break;
6840 if (cur == ctxt->context->node) return(NULL);
6841 if (cur->next != NULL) {
6842 cur = cur->next;
6843 return(cur);
6844 }
6845 } while (cur != NULL);
6846 return(cur);
6847 }
6848
6849 /**
6850 * xmlXPathNextDescendantOrSelf:
6851 * @ctxt: the XPath Parser context
6852 * @cur: the current node in the traversal
6853 *
6854 * Traversal function for the "descendant-or-self" direction
6855 * the descendant-or-self axis contains the context node and the descendants
6856 * of the context node in document order; thus the context node is the first
6857 * node on the axis, and the first child of the context node is the second node
6858 * on the axis
6859 *
6860 * Returns the next element following that axis
6861 */
6862 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6863 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6864 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6865 if (cur == NULL)
6866 return(ctxt->context->node);
6867
6868 if (ctxt->context->node == NULL)
6869 return(NULL);
6870 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6871 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6872 return(NULL);
6873
6874 return(xmlXPathNextDescendant(ctxt, cur));
6875 }
6876
6877 /**
6878 * xmlXPathNextParent:
6879 * @ctxt: the XPath Parser context
6880 * @cur: the current node in the traversal
6881 *
6882 * Traversal function for the "parent" direction
6883 * The parent axis contains the parent of the context node, if there is one.
6884 *
6885 * Returns the next element following that axis
6886 */
6887 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6888 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6889 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6890 /*
6891 * the parent of an attribute or namespace node is the element
6892 * to which the attribute or namespace node is attached
6893 * Namespace handling !!!
6894 */
6895 if (cur == NULL) {
6896 if (ctxt->context->node == NULL) return(NULL);
6897 switch (ctxt->context->node->type) {
6898 case XML_ELEMENT_NODE:
6899 case XML_TEXT_NODE:
6900 case XML_CDATA_SECTION_NODE:
6901 case XML_ENTITY_REF_NODE:
6902 case XML_ENTITY_NODE:
6903 case XML_PI_NODE:
6904 case XML_COMMENT_NODE:
6905 case XML_NOTATION_NODE:
6906 case XML_DTD_NODE:
6907 case XML_ELEMENT_DECL:
6908 case XML_ATTRIBUTE_DECL:
6909 case XML_XINCLUDE_START:
6910 case XML_XINCLUDE_END:
6911 case XML_ENTITY_DECL:
6912 if (ctxt->context->node->parent == NULL)
6913 return((xmlNodePtr) ctxt->context->doc);
6914 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6915 ((ctxt->context->node->parent->name[0] == ' ') ||
6916 (xmlStrEqual(ctxt->context->node->parent->name,
6917 BAD_CAST "fake node libxslt"))))
6918 return(NULL);
6919 return(ctxt->context->node->parent);
6920 case XML_ATTRIBUTE_NODE: {
6921 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6922
6923 return(att->parent);
6924 }
6925 case XML_DOCUMENT_NODE:
6926 case XML_DOCUMENT_TYPE_NODE:
6927 case XML_DOCUMENT_FRAG_NODE:
6928 case XML_HTML_DOCUMENT_NODE:
6929 return(NULL);
6930 case XML_NAMESPACE_DECL: {
6931 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6932
6933 if ((ns->next != NULL) &&
6934 (ns->next->type != XML_NAMESPACE_DECL))
6935 return((xmlNodePtr) ns->next);
6936 return(NULL);
6937 }
6938 }
6939 }
6940 return(NULL);
6941 }
6942
6943 /**
6944 * xmlXPathNextAncestor:
6945 * @ctxt: the XPath Parser context
6946 * @cur: the current node in the traversal
6947 *
6948 * Traversal function for the "ancestor" direction
6949 * the ancestor axis contains the ancestors of the context node; the ancestors
6950 * of the context node consist of the parent of context node and the parent's
6951 * parent and so on; the nodes are ordered in reverse document order; thus the
6952 * parent is the first node on the axis, and the parent's parent is the second
6953 * node on the axis
6954 *
6955 * Returns the next element following that axis
6956 */
6957 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)6958 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6959 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6960 /*
6961 * the parent of an attribute or namespace node is the element
6962 * to which the attribute or namespace node is attached
6963 * !!!!!!!!!!!!!
6964 */
6965 if (cur == NULL) {
6966 if (ctxt->context->node == NULL) return(NULL);
6967 switch (ctxt->context->node->type) {
6968 case XML_ELEMENT_NODE:
6969 case XML_TEXT_NODE:
6970 case XML_CDATA_SECTION_NODE:
6971 case XML_ENTITY_REF_NODE:
6972 case XML_ENTITY_NODE:
6973 case XML_PI_NODE:
6974 case XML_COMMENT_NODE:
6975 case XML_DTD_NODE:
6976 case XML_ELEMENT_DECL:
6977 case XML_ATTRIBUTE_DECL:
6978 case XML_ENTITY_DECL:
6979 case XML_NOTATION_NODE:
6980 case XML_XINCLUDE_START:
6981 case XML_XINCLUDE_END:
6982 if (ctxt->context->node->parent == NULL)
6983 return((xmlNodePtr) ctxt->context->doc);
6984 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6985 ((ctxt->context->node->parent->name[0] == ' ') ||
6986 (xmlStrEqual(ctxt->context->node->parent->name,
6987 BAD_CAST "fake node libxslt"))))
6988 return(NULL);
6989 return(ctxt->context->node->parent);
6990 case XML_ATTRIBUTE_NODE: {
6991 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6992
6993 return(tmp->parent);
6994 }
6995 case XML_DOCUMENT_NODE:
6996 case XML_DOCUMENT_TYPE_NODE:
6997 case XML_DOCUMENT_FRAG_NODE:
6998 case XML_HTML_DOCUMENT_NODE:
6999 return(NULL);
7000 case XML_NAMESPACE_DECL: {
7001 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7002
7003 if ((ns->next != NULL) &&
7004 (ns->next->type != XML_NAMESPACE_DECL))
7005 return((xmlNodePtr) ns->next);
7006 /* Bad, how did that namespace end up here ? */
7007 return(NULL);
7008 }
7009 }
7010 return(NULL);
7011 }
7012 if (cur == ctxt->context->doc->children)
7013 return((xmlNodePtr) ctxt->context->doc);
7014 if (cur == (xmlNodePtr) ctxt->context->doc)
7015 return(NULL);
7016 switch (cur->type) {
7017 case XML_ELEMENT_NODE:
7018 case XML_TEXT_NODE:
7019 case XML_CDATA_SECTION_NODE:
7020 case XML_ENTITY_REF_NODE:
7021 case XML_ENTITY_NODE:
7022 case XML_PI_NODE:
7023 case XML_COMMENT_NODE:
7024 case XML_NOTATION_NODE:
7025 case XML_DTD_NODE:
7026 case XML_ELEMENT_DECL:
7027 case XML_ATTRIBUTE_DECL:
7028 case XML_ENTITY_DECL:
7029 case XML_XINCLUDE_START:
7030 case XML_XINCLUDE_END:
7031 if (cur->parent == NULL)
7032 return(NULL);
7033 if ((cur->parent->type == XML_ELEMENT_NODE) &&
7034 ((cur->parent->name[0] == ' ') ||
7035 (xmlStrEqual(cur->parent->name,
7036 BAD_CAST "fake node libxslt"))))
7037 return(NULL);
7038 return(cur->parent);
7039 case XML_ATTRIBUTE_NODE: {
7040 xmlAttrPtr att = (xmlAttrPtr) cur;
7041
7042 return(att->parent);
7043 }
7044 case XML_NAMESPACE_DECL: {
7045 xmlNsPtr ns = (xmlNsPtr) cur;
7046
7047 if ((ns->next != NULL) &&
7048 (ns->next->type != XML_NAMESPACE_DECL))
7049 return((xmlNodePtr) ns->next);
7050 /* Bad, how did that namespace end up here ? */
7051 return(NULL);
7052 }
7053 case XML_DOCUMENT_NODE:
7054 case XML_DOCUMENT_TYPE_NODE:
7055 case XML_DOCUMENT_FRAG_NODE:
7056 case XML_HTML_DOCUMENT_NODE:
7057 return(NULL);
7058 }
7059 return(NULL);
7060 }
7061
7062 /**
7063 * xmlXPathNextAncestorOrSelf:
7064 * @ctxt: the XPath Parser context
7065 * @cur: the current node in the traversal
7066 *
7067 * Traversal function for the "ancestor-or-self" direction
7068 * he ancestor-or-self axis contains the context node and ancestors of
7069 * the context node in reverse document order; thus the context node is
7070 * the first node on the axis, and the context node's parent the second;
7071 * parent here is defined the same as with the parent axis.
7072 *
7073 * Returns the next element following that axis
7074 */
7075 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7076 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7077 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7078 if (cur == NULL)
7079 return(ctxt->context->node);
7080 return(xmlXPathNextAncestor(ctxt, cur));
7081 }
7082
7083 /**
7084 * xmlXPathNextFollowingSibling:
7085 * @ctxt: the XPath Parser context
7086 * @cur: the current node in the traversal
7087 *
7088 * Traversal function for the "following-sibling" direction
7089 * The following-sibling axis contains the following siblings of the context
7090 * node in document order.
7091 *
7092 * Returns the next element following that axis
7093 */
7094 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7095 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7096 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7097 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7098 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7099 return(NULL);
7100 if (cur == (xmlNodePtr) ctxt->context->doc)
7101 return(NULL);
7102 if (cur == NULL)
7103 return(ctxt->context->node->next);
7104 return(cur->next);
7105 }
7106
7107 /**
7108 * xmlXPathNextPrecedingSibling:
7109 * @ctxt: the XPath Parser context
7110 * @cur: the current node in the traversal
7111 *
7112 * Traversal function for the "preceding-sibling" direction
7113 * The preceding-sibling axis contains the preceding siblings of the context
7114 * node in reverse document order; the first preceding sibling is first on the
7115 * axis; the sibling preceding that node is the second on the axis and so on.
7116 *
7117 * Returns the next element following that axis
7118 */
7119 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7120 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7121 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7122 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7123 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7124 return(NULL);
7125 if (cur == (xmlNodePtr) ctxt->context->doc)
7126 return(NULL);
7127 if (cur == NULL)
7128 return(ctxt->context->node->prev);
7129 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7130 cur = cur->prev;
7131 if (cur == NULL)
7132 return(ctxt->context->node->prev);
7133 }
7134 return(cur->prev);
7135 }
7136
7137 /**
7138 * xmlXPathNextFollowing:
7139 * @ctxt: the XPath Parser context
7140 * @cur: the current node in the traversal
7141 *
7142 * Traversal function for the "following" direction
7143 * The following axis contains all nodes in the same document as the context
7144 * node that are after the context node in document order, excluding any
7145 * descendants and excluding attribute nodes and namespace nodes; the nodes
7146 * are ordered in document order
7147 *
7148 * Returns the next element following that axis
7149 */
7150 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7151 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7152 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7153 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
7154 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7155 return(cur->children);
7156
7157 if (cur == NULL) {
7158 cur = ctxt->context->node;
7159 if (cur->type == XML_ATTRIBUTE_NODE) {
7160 cur = cur->parent;
7161 } else if (cur->type == XML_NAMESPACE_DECL) {
7162 xmlNsPtr ns = (xmlNsPtr) cur;
7163
7164 if ((ns->next == NULL) ||
7165 (ns->next->type == XML_NAMESPACE_DECL))
7166 return (NULL);
7167 cur = (xmlNodePtr) ns->next;
7168 }
7169 }
7170 if (cur == NULL) return(NULL) ; /* ERROR */
7171 if (cur->next != NULL) return(cur->next) ;
7172 do {
7173 cur = cur->parent;
7174 if (cur == NULL) break;
7175 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7176 if (cur->next != NULL) return(cur->next);
7177 } while (cur != NULL);
7178 return(cur);
7179 }
7180
7181 /*
7182 * xmlXPathIsAncestor:
7183 * @ancestor: the ancestor node
7184 * @node: the current node
7185 *
7186 * Check that @ancestor is a @node's ancestor
7187 *
7188 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7189 */
7190 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)7191 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7192 if ((ancestor == NULL) || (node == NULL)) return(0);
7193 if (node->type == XML_NAMESPACE_DECL)
7194 return(0);
7195 if (ancestor->type == XML_NAMESPACE_DECL)
7196 return(0);
7197 /* nodes need to be in the same document */
7198 if (ancestor->doc != node->doc) return(0);
7199 /* avoid searching if ancestor or node is the root node */
7200 if (ancestor == (xmlNodePtr) node->doc) return(1);
7201 if (node == (xmlNodePtr) ancestor->doc) return(0);
7202 while (node->parent != NULL) {
7203 if (node->parent == ancestor)
7204 return(1);
7205 node = node->parent;
7206 }
7207 return(0);
7208 }
7209
7210 /**
7211 * xmlXPathNextPreceding:
7212 * @ctxt: the XPath Parser context
7213 * @cur: the current node in the traversal
7214 *
7215 * Traversal function for the "preceding" direction
7216 * the preceding axis contains all nodes in the same document as the context
7217 * node that are before the context node in document order, excluding any
7218 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7219 * ordered in reverse document order
7220 *
7221 * Returns the next element following that axis
7222 */
7223 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7224 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7225 {
7226 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7227 if (cur == NULL) {
7228 cur = ctxt->context->node;
7229 if (cur->type == XML_ATTRIBUTE_NODE) {
7230 cur = cur->parent;
7231 } else if (cur->type == XML_NAMESPACE_DECL) {
7232 xmlNsPtr ns = (xmlNsPtr) cur;
7233
7234 if ((ns->next == NULL) ||
7235 (ns->next->type == XML_NAMESPACE_DECL))
7236 return (NULL);
7237 cur = (xmlNodePtr) ns->next;
7238 }
7239 }
7240 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7241 return (NULL);
7242 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7243 cur = cur->prev;
7244 do {
7245 if (cur->prev != NULL) {
7246 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7247 return (cur);
7248 }
7249
7250 cur = cur->parent;
7251 if (cur == NULL)
7252 return (NULL);
7253 if (cur == ctxt->context->doc->children)
7254 return (NULL);
7255 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7256 return (cur);
7257 }
7258
7259 /**
7260 * xmlXPathNextPrecedingInternal:
7261 * @ctxt: the XPath Parser context
7262 * @cur: the current node in the traversal
7263 *
7264 * Traversal function for the "preceding" direction
7265 * the preceding axis contains all nodes in the same document as the context
7266 * node that are before the context node in document order, excluding any
7267 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7268 * ordered in reverse document order
7269 * This is a faster implementation but internal only since it requires a
7270 * state kept in the parser context: ctxt->ancestor.
7271 *
7272 * Returns the next element following that axis
7273 */
7274 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7275 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7276 xmlNodePtr cur)
7277 {
7278 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7279 if (cur == NULL) {
7280 cur = ctxt->context->node;
7281 if (cur == NULL)
7282 return (NULL);
7283 if (cur->type == XML_ATTRIBUTE_NODE) {
7284 cur = cur->parent;
7285 } else if (cur->type == XML_NAMESPACE_DECL) {
7286 xmlNsPtr ns = (xmlNsPtr) cur;
7287
7288 if ((ns->next == NULL) ||
7289 (ns->next->type == XML_NAMESPACE_DECL))
7290 return (NULL);
7291 cur = (xmlNodePtr) ns->next;
7292 }
7293 ctxt->ancestor = cur->parent;
7294 }
7295 if (cur->type == XML_NAMESPACE_DECL)
7296 return(NULL);
7297 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7298 cur = cur->prev;
7299 while (cur->prev == NULL) {
7300 cur = cur->parent;
7301 if (cur == NULL)
7302 return (NULL);
7303 if (cur == ctxt->context->doc->children)
7304 return (NULL);
7305 if (cur != ctxt->ancestor)
7306 return (cur);
7307 ctxt->ancestor = cur->parent;
7308 }
7309 cur = cur->prev;
7310 while (cur->last != NULL)
7311 cur = cur->last;
7312 return (cur);
7313 }
7314
7315 /**
7316 * xmlXPathNextNamespace:
7317 * @ctxt: the XPath Parser context
7318 * @cur: the current attribute in the traversal
7319 *
7320 * Traversal function for the "namespace" direction
7321 * the namespace axis contains the namespace nodes of the context node;
7322 * the order of nodes on this axis is implementation-defined; the axis will
7323 * be empty unless the context node is an element
7324 *
7325 * We keep the XML namespace node at the end of the list.
7326 *
7327 * Returns the next element following that axis
7328 */
7329 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7330 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7331 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7332 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7333 if (cur == NULL) {
7334 if (ctxt->context->tmpNsList != NULL)
7335 xmlFree(ctxt->context->tmpNsList);
7336 ctxt->context->tmpNsNr = 0;
7337 if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7338 &ctxt->context->tmpNsList) < 0) {
7339 xmlXPathPErrMemory(ctxt);
7340 return(NULL);
7341 }
7342 if (ctxt->context->tmpNsList != NULL) {
7343 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7344 ctxt->context->tmpNsNr++;
7345 }
7346 }
7347 return((xmlNodePtr) xmlXPathXMLNamespace);
7348 }
7349 if (ctxt->context->tmpNsNr > 0) {
7350 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7351 } else {
7352 if (ctxt->context->tmpNsList != NULL)
7353 xmlFree(ctxt->context->tmpNsList);
7354 ctxt->context->tmpNsList = NULL;
7355 return(NULL);
7356 }
7357 }
7358
7359 /**
7360 * xmlXPathNextAttribute:
7361 * @ctxt: the XPath Parser context
7362 * @cur: the current attribute in the traversal
7363 *
7364 * Traversal function for the "attribute" direction
7365 * TODO: support DTD inherited default attributes
7366 *
7367 * Returns the next element following that axis
7368 */
7369 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7370 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7371 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7372 if (ctxt->context->node == NULL)
7373 return(NULL);
7374 if (ctxt->context->node->type != XML_ELEMENT_NODE)
7375 return(NULL);
7376 if (cur == NULL) {
7377 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7378 return(NULL);
7379 return((xmlNodePtr)ctxt->context->node->properties);
7380 }
7381 return((xmlNodePtr)cur->next);
7382 }
7383
7384 /************************************************************************
7385 * *
7386 * NodeTest Functions *
7387 * *
7388 ************************************************************************/
7389
7390 #define IS_FUNCTION 200
7391
7392
7393 /************************************************************************
7394 * *
7395 * Implicit tree core function library *
7396 * *
7397 ************************************************************************/
7398
7399 /**
7400 * xmlXPathRoot:
7401 * @ctxt: the XPath Parser context
7402 *
7403 * Initialize the context to the root of the document
7404 */
7405 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)7406 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7407 if ((ctxt == NULL) || (ctxt->context == NULL))
7408 return;
7409 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7410 (xmlNodePtr) ctxt->context->doc));
7411 }
7412
7413 /************************************************************************
7414 * *
7415 * The explicit core function library *
7416 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7417 * *
7418 ************************************************************************/
7419
7420
7421 /**
7422 * xmlXPathLastFunction:
7423 * @ctxt: the XPath Parser context
7424 * @nargs: the number of arguments
7425 *
7426 * Implement the last() XPath function
7427 * number last()
7428 * The last function returns the number of nodes in the context node list.
7429 */
7430 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)7431 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7432 CHECK_ARITY(0);
7433 if (ctxt->context->contextSize >= 0) {
7434 valuePush(ctxt,
7435 xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7436 } else {
7437 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7438 }
7439 }
7440
7441 /**
7442 * xmlXPathPositionFunction:
7443 * @ctxt: the XPath Parser context
7444 * @nargs: the number of arguments
7445 *
7446 * Implement the position() XPath function
7447 * number position()
7448 * The position function returns the position of the context node in the
7449 * context node list. The first position is 1, and so the last position
7450 * will be equal to last().
7451 */
7452 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)7453 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7454 CHECK_ARITY(0);
7455 if (ctxt->context->proximityPosition >= 0) {
7456 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7457 (double) ctxt->context->proximityPosition));
7458 } else {
7459 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7460 }
7461 }
7462
7463 /**
7464 * xmlXPathCountFunction:
7465 * @ctxt: the XPath Parser context
7466 * @nargs: the number of arguments
7467 *
7468 * Implement the count() XPath function
7469 * number count(node-set)
7470 */
7471 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)7472 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7473 xmlXPathObjectPtr cur;
7474
7475 CHECK_ARITY(1);
7476 if ((ctxt->value == NULL) ||
7477 ((ctxt->value->type != XPATH_NODESET) &&
7478 (ctxt->value->type != XPATH_XSLT_TREE)))
7479 XP_ERROR(XPATH_INVALID_TYPE);
7480 cur = valuePop(ctxt);
7481
7482 if ((cur == NULL) || (cur->nodesetval == NULL))
7483 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7484 else
7485 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7486 (double) cur->nodesetval->nodeNr));
7487 xmlXPathReleaseObject(ctxt->context, cur);
7488 }
7489
7490 /**
7491 * xmlXPathGetElementsByIds:
7492 * @doc: the document
7493 * @ids: a whitespace separated list of IDs
7494 *
7495 * Selects elements by their unique ID.
7496 *
7497 * Returns a node-set of selected elements.
7498 */
7499 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)7500 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7501 xmlNodeSetPtr ret;
7502 const xmlChar *cur = ids;
7503 xmlChar *ID;
7504 xmlAttrPtr attr;
7505 xmlNodePtr elem = NULL;
7506
7507 if (ids == NULL) return(NULL);
7508
7509 ret = xmlXPathNodeSetCreate(NULL);
7510 if (ret == NULL)
7511 return(ret);
7512
7513 while (IS_BLANK_CH(*cur)) cur++;
7514 while (*cur != 0) {
7515 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7516 cur++;
7517
7518 ID = xmlStrndup(ids, cur - ids);
7519 if (ID == NULL) {
7520 xmlXPathFreeNodeSet(ret);
7521 return(NULL);
7522 }
7523 /*
7524 * We used to check the fact that the value passed
7525 * was an NCName, but this generated much troubles for
7526 * me and Aleksey Sanin, people blatantly violated that
7527 * constraint, like Visa3D spec.
7528 * if (xmlValidateNCName(ID, 1) == 0)
7529 */
7530 attr = xmlGetID(doc, ID);
7531 xmlFree(ID);
7532 if (attr != NULL) {
7533 if (attr->type == XML_ATTRIBUTE_NODE)
7534 elem = attr->parent;
7535 else if (attr->type == XML_ELEMENT_NODE)
7536 elem = (xmlNodePtr) attr;
7537 else
7538 elem = NULL;
7539 if (elem != NULL) {
7540 if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7541 xmlXPathFreeNodeSet(ret);
7542 return(NULL);
7543 }
7544 }
7545 }
7546
7547 while (IS_BLANK_CH(*cur)) cur++;
7548 ids = cur;
7549 }
7550 return(ret);
7551 }
7552
7553 /**
7554 * xmlXPathIdFunction:
7555 * @ctxt: the XPath Parser context
7556 * @nargs: the number of arguments
7557 *
7558 * Implement the id() XPath function
7559 * node-set id(object)
7560 * The id function selects elements by their unique ID
7561 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7562 * then the result is the union of the result of applying id to the
7563 * string value of each of the nodes in the argument node-set. When the
7564 * argument to id is of any other type, the argument is converted to a
7565 * string as if by a call to the string function; the string is split
7566 * into a whitespace-separated list of tokens (whitespace is any sequence
7567 * of characters matching the production S); the result is a node-set
7568 * containing the elements in the same document as the context node that
7569 * have a unique ID equal to any of the tokens in the list.
7570 */
7571 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)7572 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7573 xmlChar *tokens;
7574 xmlNodeSetPtr ret;
7575 xmlXPathObjectPtr obj;
7576
7577 CHECK_ARITY(1);
7578 obj = valuePop(ctxt);
7579 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7580 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7581 xmlNodeSetPtr ns;
7582 int i;
7583
7584 ret = xmlXPathNodeSetCreate(NULL);
7585 if (ret == NULL)
7586 xmlXPathPErrMemory(ctxt);
7587
7588 if (obj->nodesetval != NULL) {
7589 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7590 tokens =
7591 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7592 if (tokens == NULL)
7593 xmlXPathPErrMemory(ctxt);
7594 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7595 if (ns == NULL)
7596 xmlXPathPErrMemory(ctxt);
7597 ret = xmlXPathNodeSetMerge(ret, ns);
7598 if (ret == NULL)
7599 xmlXPathPErrMemory(ctxt);
7600 xmlXPathFreeNodeSet(ns);
7601 if (tokens != NULL)
7602 xmlFree(tokens);
7603 }
7604 }
7605 xmlXPathReleaseObject(ctxt->context, obj);
7606 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7607 return;
7608 }
7609 tokens = xmlXPathCastToString(obj);
7610 if (tokens == NULL)
7611 xmlXPathPErrMemory(ctxt);
7612 xmlXPathReleaseObject(ctxt->context, obj);
7613 ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7614 if (ret == NULL)
7615 xmlXPathPErrMemory(ctxt);
7616 xmlFree(tokens);
7617 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7618 return;
7619 }
7620
7621 /**
7622 * xmlXPathLocalNameFunction:
7623 * @ctxt: the XPath Parser context
7624 * @nargs: the number of arguments
7625 *
7626 * Implement the local-name() XPath function
7627 * string local-name(node-set?)
7628 * The local-name function returns a string containing the local part
7629 * of the name of the node in the argument node-set that is first in
7630 * document order. If the node-set is empty or the first node has no
7631 * name, an empty string is returned. If the argument is omitted it
7632 * defaults to the context node.
7633 */
7634 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7635 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7636 xmlXPathObjectPtr cur;
7637
7638 if (ctxt == NULL) return;
7639
7640 if (nargs == 0) {
7641 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7642 nargs = 1;
7643 }
7644
7645 CHECK_ARITY(1);
7646 if ((ctxt->value == NULL) ||
7647 ((ctxt->value->type != XPATH_NODESET) &&
7648 (ctxt->value->type != XPATH_XSLT_TREE)))
7649 XP_ERROR(XPATH_INVALID_TYPE);
7650 cur = valuePop(ctxt);
7651
7652 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7653 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7654 } else {
7655 int i = 0; /* Should be first in document order !!!!! */
7656 switch (cur->nodesetval->nodeTab[i]->type) {
7657 case XML_ELEMENT_NODE:
7658 case XML_ATTRIBUTE_NODE:
7659 case XML_PI_NODE:
7660 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7661 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7662 else
7663 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7664 cur->nodesetval->nodeTab[i]->name));
7665 break;
7666 case XML_NAMESPACE_DECL:
7667 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7668 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7669 break;
7670 default:
7671 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7672 }
7673 }
7674 xmlXPathReleaseObject(ctxt->context, cur);
7675 }
7676
7677 /**
7678 * xmlXPathNamespaceURIFunction:
7679 * @ctxt: the XPath Parser context
7680 * @nargs: the number of arguments
7681 *
7682 * Implement the namespace-uri() XPath function
7683 * string namespace-uri(node-set?)
7684 * The namespace-uri function returns a string containing the
7685 * namespace URI of the expanded name of the node in the argument
7686 * node-set that is first in document order. If the node-set is empty,
7687 * the first node has no name, or the expanded name has no namespace
7688 * URI, an empty string is returned. If the argument is omitted it
7689 * defaults to the context node.
7690 */
7691 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)7692 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7693 xmlXPathObjectPtr cur;
7694
7695 if (ctxt == NULL) return;
7696
7697 if (nargs == 0) {
7698 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7699 nargs = 1;
7700 }
7701 CHECK_ARITY(1);
7702 if ((ctxt->value == NULL) ||
7703 ((ctxt->value->type != XPATH_NODESET) &&
7704 (ctxt->value->type != XPATH_XSLT_TREE)))
7705 XP_ERROR(XPATH_INVALID_TYPE);
7706 cur = valuePop(ctxt);
7707
7708 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7709 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7710 } else {
7711 int i = 0; /* Should be first in document order !!!!! */
7712 switch (cur->nodesetval->nodeTab[i]->type) {
7713 case XML_ELEMENT_NODE:
7714 case XML_ATTRIBUTE_NODE:
7715 if (cur->nodesetval->nodeTab[i]->ns == NULL)
7716 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7717 else
7718 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7719 cur->nodesetval->nodeTab[i]->ns->href));
7720 break;
7721 default:
7722 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7723 }
7724 }
7725 xmlXPathReleaseObject(ctxt->context, cur);
7726 }
7727
7728 /**
7729 * xmlXPathNameFunction:
7730 * @ctxt: the XPath Parser context
7731 * @nargs: the number of arguments
7732 *
7733 * Implement the name() XPath function
7734 * string name(node-set?)
7735 * The name function returns a string containing a QName representing
7736 * the name of the node in the argument node-set that is first in document
7737 * order. The QName must represent the name with respect to the namespace
7738 * declarations in effect on the node whose name is being represented.
7739 * Typically, this will be the form in which the name occurred in the XML
7740 * source. This need not be the case if there are namespace declarations
7741 * in effect on the node that associate multiple prefixes with the same
7742 * namespace. However, an implementation may include information about
7743 * the original prefix in its representation of nodes; in this case, an
7744 * implementation can ensure that the returned string is always the same
7745 * as the QName used in the XML source. If the argument it omitted it
7746 * defaults to the context node.
7747 * Libxml keep the original prefix so the "real qualified name" used is
7748 * returned.
7749 */
7750 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)7751 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7752 {
7753 xmlXPathObjectPtr cur;
7754
7755 if (nargs == 0) {
7756 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7757 nargs = 1;
7758 }
7759
7760 CHECK_ARITY(1);
7761 if ((ctxt->value == NULL) ||
7762 ((ctxt->value->type != XPATH_NODESET) &&
7763 (ctxt->value->type != XPATH_XSLT_TREE)))
7764 XP_ERROR(XPATH_INVALID_TYPE);
7765 cur = valuePop(ctxt);
7766
7767 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7768 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7769 } else {
7770 int i = 0; /* Should be first in document order !!!!! */
7771
7772 switch (cur->nodesetval->nodeTab[i]->type) {
7773 case XML_ELEMENT_NODE:
7774 case XML_ATTRIBUTE_NODE:
7775 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7776 valuePush(ctxt,
7777 xmlXPathCacheNewCString(ctxt, ""));
7778 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7779 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7780 valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7781 cur->nodesetval->nodeTab[i]->name));
7782 } else {
7783 xmlChar *fullname;
7784
7785 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7786 cur->nodesetval->nodeTab[i]->ns->prefix,
7787 NULL, 0);
7788 if (fullname == cur->nodesetval->nodeTab[i]->name)
7789 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7790 if (fullname == NULL)
7791 xmlXPathPErrMemory(ctxt);
7792 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7793 }
7794 break;
7795 default:
7796 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7797 cur->nodesetval->nodeTab[i]));
7798 xmlXPathLocalNameFunction(ctxt, 1);
7799 }
7800 }
7801 xmlXPathReleaseObject(ctxt->context, cur);
7802 }
7803
7804
7805 /**
7806 * xmlXPathStringFunction:
7807 * @ctxt: the XPath Parser context
7808 * @nargs: the number of arguments
7809 *
7810 * Implement the string() XPath function
7811 * string string(object?)
7812 * The string function converts an object to a string as follows:
7813 * - A node-set is converted to a string by returning the value of
7814 * the node in the node-set that is first in document order.
7815 * If the node-set is empty, an empty string is returned.
7816 * - A number is converted to a string as follows
7817 * + NaN is converted to the string NaN
7818 * + positive zero is converted to the string 0
7819 * + negative zero is converted to the string 0
7820 * + positive infinity is converted to the string Infinity
7821 * + negative infinity is converted to the string -Infinity
7822 * + if the number is an integer, the number is represented in
7823 * decimal form as a Number with no decimal point and no leading
7824 * zeros, preceded by a minus sign (-) if the number is negative
7825 * + otherwise, the number is represented in decimal form as a
7826 * Number including a decimal point with at least one digit
7827 * before the decimal point and at least one digit after the
7828 * decimal point, preceded by a minus sign (-) if the number
7829 * is negative; there must be no leading zeros before the decimal
7830 * point apart possibly from the one required digit immediately
7831 * before the decimal point; beyond the one required digit
7832 * after the decimal point there must be as many, but only as
7833 * many, more digits as are needed to uniquely distinguish the
7834 * number from all other IEEE 754 numeric values.
7835 * - The boolean false value is converted to the string false.
7836 * The boolean true value is converted to the string true.
7837 *
7838 * If the argument is omitted, it defaults to a node-set with the
7839 * context node as its only member.
7840 */
7841 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)7842 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7843 xmlXPathObjectPtr cur;
7844 xmlChar *stringval;
7845
7846 if (ctxt == NULL) return;
7847 if (nargs == 0) {
7848 stringval = xmlXPathCastNodeToString(ctxt->context->node);
7849 if (stringval == NULL)
7850 xmlXPathPErrMemory(ctxt);
7851 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7852 return;
7853 }
7854
7855 CHECK_ARITY(1);
7856 cur = valuePop(ctxt);
7857 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7858 if (cur->type != XPATH_STRING) {
7859 stringval = xmlXPathCastToString(cur);
7860 if (stringval == NULL)
7861 xmlXPathPErrMemory(ctxt);
7862 xmlXPathReleaseObject(ctxt->context, cur);
7863 cur = xmlXPathCacheWrapString(ctxt, stringval);
7864 }
7865 valuePush(ctxt, cur);
7866 }
7867
7868 /**
7869 * xmlXPathStringLengthFunction:
7870 * @ctxt: the XPath Parser context
7871 * @nargs: the number of arguments
7872 *
7873 * Implement the string-length() XPath function
7874 * number string-length(string?)
7875 * The string-length returns the number of characters in the string
7876 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7877 * the context node converted to a string, in other words the value
7878 * of the context node.
7879 */
7880 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)7881 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7882 xmlXPathObjectPtr cur;
7883
7884 if (nargs == 0) {
7885 if ((ctxt == NULL) || (ctxt->context == NULL))
7886 return;
7887 if (ctxt->context->node == NULL) {
7888 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7889 } else {
7890 xmlChar *content;
7891
7892 content = xmlXPathCastNodeToString(ctxt->context->node);
7893 if (content == NULL)
7894 xmlXPathPErrMemory(ctxt);
7895 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7896 xmlUTF8Strlen(content)));
7897 xmlFree(content);
7898 }
7899 return;
7900 }
7901 CHECK_ARITY(1);
7902 CAST_TO_STRING;
7903 CHECK_TYPE(XPATH_STRING);
7904 cur = valuePop(ctxt);
7905 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7906 xmlUTF8Strlen(cur->stringval)));
7907 xmlXPathReleaseObject(ctxt->context, cur);
7908 }
7909
7910 /**
7911 * xmlXPathConcatFunction:
7912 * @ctxt: the XPath Parser context
7913 * @nargs: the number of arguments
7914 *
7915 * Implement the concat() XPath function
7916 * string concat(string, string, string*)
7917 * The concat function returns the concatenation of its arguments.
7918 */
7919 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)7920 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7921 xmlXPathObjectPtr cur, newobj;
7922 xmlChar *tmp;
7923
7924 if (ctxt == NULL) return;
7925 if (nargs < 2) {
7926 CHECK_ARITY(2);
7927 }
7928
7929 CAST_TO_STRING;
7930 cur = valuePop(ctxt);
7931 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7932 xmlXPathReleaseObject(ctxt->context, cur);
7933 return;
7934 }
7935 nargs--;
7936
7937 while (nargs > 0) {
7938 CAST_TO_STRING;
7939 newobj = valuePop(ctxt);
7940 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7941 xmlXPathReleaseObject(ctxt->context, newobj);
7942 xmlXPathReleaseObject(ctxt->context, cur);
7943 XP_ERROR(XPATH_INVALID_TYPE);
7944 }
7945 tmp = xmlStrcat(newobj->stringval, cur->stringval);
7946 if (tmp == NULL)
7947 xmlXPathPErrMemory(ctxt);
7948 newobj->stringval = cur->stringval;
7949 cur->stringval = tmp;
7950 xmlXPathReleaseObject(ctxt->context, newobj);
7951 nargs--;
7952 }
7953 valuePush(ctxt, cur);
7954 }
7955
7956 /**
7957 * xmlXPathContainsFunction:
7958 * @ctxt: the XPath Parser context
7959 * @nargs: the number of arguments
7960 *
7961 * Implement the contains() XPath function
7962 * boolean contains(string, string)
7963 * The contains function returns true if the first argument string
7964 * contains the second argument string, and otherwise returns false.
7965 */
7966 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)7967 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7968 xmlXPathObjectPtr hay, needle;
7969
7970 CHECK_ARITY(2);
7971 CAST_TO_STRING;
7972 CHECK_TYPE(XPATH_STRING);
7973 needle = valuePop(ctxt);
7974 CAST_TO_STRING;
7975 hay = valuePop(ctxt);
7976
7977 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7978 xmlXPathReleaseObject(ctxt->context, hay);
7979 xmlXPathReleaseObject(ctxt->context, needle);
7980 XP_ERROR(XPATH_INVALID_TYPE);
7981 }
7982 if (xmlStrstr(hay->stringval, needle->stringval))
7983 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7984 else
7985 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7986 xmlXPathReleaseObject(ctxt->context, hay);
7987 xmlXPathReleaseObject(ctxt->context, needle);
7988 }
7989
7990 /**
7991 * xmlXPathStartsWithFunction:
7992 * @ctxt: the XPath Parser context
7993 * @nargs: the number of arguments
7994 *
7995 * Implement the starts-with() XPath function
7996 * boolean starts-with(string, string)
7997 * The starts-with function returns true if the first argument string
7998 * starts with the second argument string, and otherwise returns false.
7999 */
8000 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)8001 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8002 xmlXPathObjectPtr hay, needle;
8003 int n;
8004
8005 CHECK_ARITY(2);
8006 CAST_TO_STRING;
8007 CHECK_TYPE(XPATH_STRING);
8008 needle = valuePop(ctxt);
8009 CAST_TO_STRING;
8010 hay = valuePop(ctxt);
8011
8012 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8013 xmlXPathReleaseObject(ctxt->context, hay);
8014 xmlXPathReleaseObject(ctxt->context, needle);
8015 XP_ERROR(XPATH_INVALID_TYPE);
8016 }
8017 n = xmlStrlen(needle->stringval);
8018 if (xmlStrncmp(hay->stringval, needle->stringval, n))
8019 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8020 else
8021 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8022 xmlXPathReleaseObject(ctxt->context, hay);
8023 xmlXPathReleaseObject(ctxt->context, needle);
8024 }
8025
8026 /**
8027 * xmlXPathSubstringFunction:
8028 * @ctxt: the XPath Parser context
8029 * @nargs: the number of arguments
8030 *
8031 * Implement the substring() XPath function
8032 * string substring(string, number, number?)
8033 * The substring function returns the substring of the first argument
8034 * starting at the position specified in the second argument with
8035 * length specified in the third argument. For example,
8036 * substring("12345",2,3) returns "234". If the third argument is not
8037 * specified, it returns the substring starting at the position specified
8038 * in the second argument and continuing to the end of the string. For
8039 * example, substring("12345",2) returns "2345". More precisely, each
8040 * character in the string (see [3.6 Strings]) is considered to have a
8041 * numeric position: the position of the first character is 1, the position
8042 * of the second character is 2 and so on. The returned substring contains
8043 * those characters for which the position of the character is greater than
8044 * or equal to the second argument and, if the third argument is specified,
8045 * less than the sum of the second and third arguments; the comparisons
8046 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8047 * - substring("12345", 1.5, 2.6) returns "234"
8048 * - substring("12345", 0, 3) returns "12"
8049 * - substring("12345", 0 div 0, 3) returns ""
8050 * - substring("12345", 1, 0 div 0) returns ""
8051 * - substring("12345", -42, 1 div 0) returns "12345"
8052 * - substring("12345", -1 div 0, 1 div 0) returns ""
8053 */
8054 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)8055 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8056 xmlXPathObjectPtr str, start, len;
8057 double le=0, in;
8058 int i = 1, j = INT_MAX;
8059
8060 if (nargs < 2) {
8061 CHECK_ARITY(2);
8062 }
8063 if (nargs > 3) {
8064 CHECK_ARITY(3);
8065 }
8066 /*
8067 * take care of possible last (position) argument
8068 */
8069 if (nargs == 3) {
8070 CAST_TO_NUMBER;
8071 CHECK_TYPE(XPATH_NUMBER);
8072 len = valuePop(ctxt);
8073 le = len->floatval;
8074 xmlXPathReleaseObject(ctxt->context, len);
8075 }
8076
8077 CAST_TO_NUMBER;
8078 CHECK_TYPE(XPATH_NUMBER);
8079 start = valuePop(ctxt);
8080 in = start->floatval;
8081 xmlXPathReleaseObject(ctxt->context, start);
8082 CAST_TO_STRING;
8083 CHECK_TYPE(XPATH_STRING);
8084 str = valuePop(ctxt);
8085
8086 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
8087 i = INT_MAX;
8088 } else if (in >= 1.0) {
8089 i = (int)in;
8090 if (in - floor(in) >= 0.5)
8091 i += 1;
8092 }
8093
8094 if (nargs == 3) {
8095 double rin, rle, end;
8096
8097 rin = floor(in);
8098 if (in - rin >= 0.5)
8099 rin += 1.0;
8100
8101 rle = floor(le);
8102 if (le - rle >= 0.5)
8103 rle += 1.0;
8104
8105 end = rin + rle;
8106 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
8107 j = 1;
8108 } else if (end < INT_MAX) {
8109 j = (int)end;
8110 }
8111 }
8112
8113 i -= 1;
8114 j -= 1;
8115
8116 if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
8117 xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
8118 if (ret == NULL)
8119 xmlXPathPErrMemory(ctxt);
8120 valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
8121 xmlFree(ret);
8122 } else {
8123 valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
8124 }
8125
8126 xmlXPathReleaseObject(ctxt->context, str);
8127 }
8128
8129 /**
8130 * xmlXPathSubstringBeforeFunction:
8131 * @ctxt: the XPath Parser context
8132 * @nargs: the number of arguments
8133 *
8134 * Implement the substring-before() XPath function
8135 * string substring-before(string, string)
8136 * The substring-before function returns the substring of the first
8137 * argument string that precedes the first occurrence of the second
8138 * argument string in the first argument string, or the empty string
8139 * if the first argument string does not contain the second argument
8140 * string. For example, substring-before("1999/04/01","/") returns 1999.
8141 */
8142 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)8143 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8144 xmlXPathObjectPtr str = NULL;
8145 xmlXPathObjectPtr find = NULL;
8146 const xmlChar *point;
8147 xmlChar *result;
8148
8149 CHECK_ARITY(2);
8150 CAST_TO_STRING;
8151 find = valuePop(ctxt);
8152 CAST_TO_STRING;
8153 str = valuePop(ctxt);
8154 if (ctxt->error != 0)
8155 goto error;
8156
8157 point = xmlStrstr(str->stringval, find->stringval);
8158 if (point == NULL) {
8159 result = xmlStrdup(BAD_CAST "");
8160 } else {
8161 result = xmlStrndup(str->stringval, point - str->stringval);
8162 }
8163 if (result == NULL) {
8164 xmlXPathPErrMemory(ctxt);
8165 goto error;
8166 }
8167 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8168
8169 error:
8170 xmlXPathReleaseObject(ctxt->context, str);
8171 xmlXPathReleaseObject(ctxt->context, find);
8172 }
8173
8174 /**
8175 * xmlXPathSubstringAfterFunction:
8176 * @ctxt: the XPath Parser context
8177 * @nargs: the number of arguments
8178 *
8179 * Implement the substring-after() XPath function
8180 * string substring-after(string, string)
8181 * The substring-after function returns the substring of the first
8182 * argument string that follows the first occurrence of the second
8183 * argument string in the first argument string, or the empty string
8184 * if the first argument string does not contain the second argument
8185 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8186 * and substring-after("1999/04/01","19") returns 99/04/01.
8187 */
8188 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)8189 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8190 xmlXPathObjectPtr str = NULL;
8191 xmlXPathObjectPtr find = NULL;
8192 const xmlChar *point;
8193 xmlChar *result;
8194
8195 CHECK_ARITY(2);
8196 CAST_TO_STRING;
8197 find = valuePop(ctxt);
8198 CAST_TO_STRING;
8199 str = valuePop(ctxt);
8200 if (ctxt->error != 0)
8201 goto error;
8202
8203 point = xmlStrstr(str->stringval, find->stringval);
8204 if (point == NULL) {
8205 result = xmlStrdup(BAD_CAST "");
8206 } else {
8207 result = xmlStrdup(point + xmlStrlen(find->stringval));
8208 }
8209 if (result == NULL) {
8210 xmlXPathPErrMemory(ctxt);
8211 goto error;
8212 }
8213 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8214
8215 error:
8216 xmlXPathReleaseObject(ctxt->context, str);
8217 xmlXPathReleaseObject(ctxt->context, find);
8218 }
8219
8220 /**
8221 * xmlXPathNormalizeFunction:
8222 * @ctxt: the XPath Parser context
8223 * @nargs: the number of arguments
8224 *
8225 * Implement the normalize-space() XPath function
8226 * string normalize-space(string?)
8227 * The normalize-space function returns the argument string with white
8228 * space normalized by stripping leading and trailing whitespace
8229 * and replacing sequences of whitespace characters by a single
8230 * space. Whitespace characters are the same allowed by the S production
8231 * in XML. If the argument is omitted, it defaults to the context
8232 * node converted to a string, in other words the value of the context node.
8233 */
8234 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)8235 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8236 xmlChar *source, *target;
8237 int blank;
8238
8239 if (ctxt == NULL) return;
8240 if (nargs == 0) {
8241 /* Use current context node */
8242 source = xmlXPathCastNodeToString(ctxt->context->node);
8243 if (source == NULL)
8244 xmlXPathPErrMemory(ctxt);
8245 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
8246 nargs = 1;
8247 }
8248
8249 CHECK_ARITY(1);
8250 CAST_TO_STRING;
8251 CHECK_TYPE(XPATH_STRING);
8252 source = ctxt->value->stringval;
8253 if (source == NULL)
8254 return;
8255 target = source;
8256
8257 /* Skip leading whitespaces */
8258 while (IS_BLANK_CH(*source))
8259 source++;
8260
8261 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8262 blank = 0;
8263 while (*source) {
8264 if (IS_BLANK_CH(*source)) {
8265 blank = 1;
8266 } else {
8267 if (blank) {
8268 *target++ = 0x20;
8269 blank = 0;
8270 }
8271 *target++ = *source;
8272 }
8273 source++;
8274 }
8275 *target = 0;
8276 }
8277
8278 /**
8279 * xmlXPathTranslateFunction:
8280 * @ctxt: the XPath Parser context
8281 * @nargs: the number of arguments
8282 *
8283 * Implement the translate() XPath function
8284 * string translate(string, string, string)
8285 * The translate function returns the first argument string with
8286 * occurrences of characters in the second argument string replaced
8287 * by the character at the corresponding position in the third argument
8288 * string. For example, translate("bar","abc","ABC") returns the string
8289 * BAr. If there is a character in the second argument string with no
8290 * character at a corresponding position in the third argument string
8291 * (because the second argument string is longer than the third argument
8292 * string), then occurrences of that character in the first argument
8293 * string are removed. For example, translate("--aaa--","abc-","ABC")
8294 * returns "AAA". If a character occurs more than once in second
8295 * argument string, then the first occurrence determines the replacement
8296 * character. If the third argument string is longer than the second
8297 * argument string, then excess characters are ignored.
8298 */
8299 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)8300 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8301 xmlXPathObjectPtr str = NULL;
8302 xmlXPathObjectPtr from = NULL;
8303 xmlXPathObjectPtr to = NULL;
8304 xmlBufPtr target;
8305 int offset, max;
8306 int ch;
8307 const xmlChar *point;
8308 xmlChar *cptr, *content;
8309
8310 CHECK_ARITY(3);
8311
8312 CAST_TO_STRING;
8313 to = valuePop(ctxt);
8314 CAST_TO_STRING;
8315 from = valuePop(ctxt);
8316 CAST_TO_STRING;
8317 str = valuePop(ctxt);
8318 if (ctxt->error != 0)
8319 goto error;
8320
8321 target = xmlBufCreate();
8322 if (target == NULL) {
8323 xmlXPathPErrMemory(ctxt);
8324 goto error;
8325 }
8326
8327 max = xmlUTF8Strlen(to->stringval);
8328 for (cptr = str->stringval; (ch=*cptr); ) {
8329 offset = xmlUTF8Strloc(from->stringval, cptr);
8330 if (offset >= 0) {
8331 if (offset < max) {
8332 point = xmlUTF8Strpos(to->stringval, offset);
8333 if (point)
8334 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8335 }
8336 } else
8337 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8338
8339 /* Step to next character in input */
8340 cptr++;
8341 if ( ch & 0x80 ) {
8342 /* if not simple ascii, verify proper format */
8343 if ( (ch & 0xc0) != 0xc0 ) {
8344 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8345 break;
8346 }
8347 /* then skip over remaining bytes for this char */
8348 while ( (ch <<= 1) & 0x80 )
8349 if ( (*cptr++ & 0xc0) != 0x80 ) {
8350 xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8351 break;
8352 }
8353 if (ch & 0x80) /* must have had error encountered */
8354 break;
8355 }
8356 }
8357
8358 content = xmlBufDetach(target);
8359 if (content == NULL)
8360 xmlXPathPErrMemory(ctxt);
8361 else
8362 valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
8363 xmlBufFree(target);
8364 error:
8365 xmlXPathReleaseObject(ctxt->context, str);
8366 xmlXPathReleaseObject(ctxt->context, from);
8367 xmlXPathReleaseObject(ctxt->context, to);
8368 }
8369
8370 /**
8371 * xmlXPathBooleanFunction:
8372 * @ctxt: the XPath Parser context
8373 * @nargs: the number of arguments
8374 *
8375 * Implement the boolean() XPath function
8376 * boolean boolean(object)
8377 * The boolean function converts its argument to a boolean as follows:
8378 * - a number is true if and only if it is neither positive or
8379 * negative zero nor NaN
8380 * - a node-set is true if and only if it is non-empty
8381 * - a string is true if and only if its length is non-zero
8382 */
8383 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)8384 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8385 xmlXPathObjectPtr cur;
8386
8387 CHECK_ARITY(1);
8388 cur = valuePop(ctxt);
8389 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8390 if (cur->type != XPATH_BOOLEAN) {
8391 int boolval = xmlXPathCastToBoolean(cur);
8392
8393 xmlXPathReleaseObject(ctxt->context, cur);
8394 cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8395 }
8396 valuePush(ctxt, cur);
8397 }
8398
8399 /**
8400 * xmlXPathNotFunction:
8401 * @ctxt: the XPath Parser context
8402 * @nargs: the number of arguments
8403 *
8404 * Implement the not() XPath function
8405 * boolean not(boolean)
8406 * The not function returns true if its argument is false,
8407 * and false otherwise.
8408 */
8409 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)8410 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8411 CHECK_ARITY(1);
8412 CAST_TO_BOOLEAN;
8413 CHECK_TYPE(XPATH_BOOLEAN);
8414 ctxt->value->boolval = ! ctxt->value->boolval;
8415 }
8416
8417 /**
8418 * xmlXPathTrueFunction:
8419 * @ctxt: the XPath Parser context
8420 * @nargs: the number of arguments
8421 *
8422 * Implement the true() XPath function
8423 * boolean true()
8424 */
8425 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)8426 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8427 CHECK_ARITY(0);
8428 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8429 }
8430
8431 /**
8432 * xmlXPathFalseFunction:
8433 * @ctxt: the XPath Parser context
8434 * @nargs: the number of arguments
8435 *
8436 * Implement the false() XPath function
8437 * boolean false()
8438 */
8439 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)8440 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8441 CHECK_ARITY(0);
8442 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8443 }
8444
8445 /**
8446 * xmlXPathLangFunction:
8447 * @ctxt: the XPath Parser context
8448 * @nargs: the number of arguments
8449 *
8450 * Implement the lang() XPath function
8451 * boolean lang(string)
8452 * The lang function returns true or false depending on whether the
8453 * language of the context node as specified by xml:lang attributes
8454 * is the same as or is a sublanguage of the language specified by
8455 * the argument string. The language of the context node is determined
8456 * by the value of the xml:lang attribute on the context node, or, if
8457 * the context node has no xml:lang attribute, by the value of the
8458 * xml:lang attribute on the nearest ancestor of the context node that
8459 * has an xml:lang attribute. If there is no such attribute, then lang
8460 * returns false. If there is such an attribute, then lang returns
8461 * true if the attribute value is equal to the argument ignoring case,
8462 * or if there is some suffix starting with - such that the attribute
8463 * value is equal to the argument ignoring that suffix of the attribute
8464 * value and ignoring case.
8465 */
8466 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)8467 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8468 xmlXPathObjectPtr val;
8469 xmlNodePtr cur;
8470 xmlChar *theLang;
8471 const xmlChar *lang;
8472 int ret = 0;
8473 int i;
8474
8475 CHECK_ARITY(1);
8476 CAST_TO_STRING;
8477 CHECK_TYPE(XPATH_STRING);
8478 val = valuePop(ctxt);
8479 lang = val->stringval;
8480 cur = ctxt->context->node;
8481 while (cur != NULL) {
8482 if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8483 &theLang) < 0)
8484 xmlXPathPErrMemory(ctxt);
8485 if (theLang != NULL)
8486 break;
8487 cur = cur->parent;
8488 }
8489 if ((theLang != NULL) && (lang != NULL)) {
8490 for (i = 0;lang[i] != 0;i++)
8491 if (toupper(lang[i]) != toupper(theLang[i]))
8492 goto not_equal;
8493 if ((theLang[i] == 0) || (theLang[i] == '-'))
8494 ret = 1;
8495 }
8496 not_equal:
8497 if (theLang != NULL)
8498 xmlFree((void *)theLang);
8499
8500 xmlXPathReleaseObject(ctxt->context, val);
8501 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8502 }
8503
8504 /**
8505 * xmlXPathNumberFunction:
8506 * @ctxt: the XPath Parser context
8507 * @nargs: the number of arguments
8508 *
8509 * Implement the number() XPath function
8510 * number number(object?)
8511 */
8512 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)8513 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514 xmlXPathObjectPtr cur;
8515 double res;
8516
8517 if (ctxt == NULL) return;
8518 if (nargs == 0) {
8519 if (ctxt->context->node == NULL) {
8520 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8521 } else {
8522 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8523 if (content == NULL)
8524 xmlXPathPErrMemory(ctxt);
8525
8526 res = xmlXPathStringEvalNumber(content);
8527 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8528 xmlFree(content);
8529 }
8530 return;
8531 }
8532
8533 CHECK_ARITY(1);
8534 cur = valuePop(ctxt);
8535 if (cur->type != XPATH_NUMBER) {
8536 double floatval;
8537
8538 floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8539 xmlXPathReleaseObject(ctxt->context, cur);
8540 cur = xmlXPathCacheNewFloat(ctxt, floatval);
8541 }
8542 valuePush(ctxt, cur);
8543 }
8544
8545 /**
8546 * xmlXPathSumFunction:
8547 * @ctxt: the XPath Parser context
8548 * @nargs: the number of arguments
8549 *
8550 * Implement the sum() XPath function
8551 * number sum(node-set)
8552 * The sum function returns the sum of the values of the nodes in
8553 * the argument node-set.
8554 */
8555 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)8556 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8557 xmlXPathObjectPtr cur;
8558 int i;
8559 double res = 0.0;
8560
8561 CHECK_ARITY(1);
8562 if ((ctxt->value == NULL) ||
8563 ((ctxt->value->type != XPATH_NODESET) &&
8564 (ctxt->value->type != XPATH_XSLT_TREE)))
8565 XP_ERROR(XPATH_INVALID_TYPE);
8566 cur = valuePop(ctxt);
8567
8568 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8569 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8570 res += xmlXPathNodeToNumberInternal(ctxt,
8571 cur->nodesetval->nodeTab[i]);
8572 }
8573 }
8574 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8575 xmlXPathReleaseObject(ctxt->context, cur);
8576 }
8577
8578 /**
8579 * xmlXPathFloorFunction:
8580 * @ctxt: the XPath Parser context
8581 * @nargs: the number of arguments
8582 *
8583 * Implement the floor() XPath function
8584 * number floor(number)
8585 * The floor function returns the largest (closest to positive infinity)
8586 * number that is not greater than the argument and that is an integer.
8587 */
8588 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)8589 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8590 CHECK_ARITY(1);
8591 CAST_TO_NUMBER;
8592 CHECK_TYPE(XPATH_NUMBER);
8593
8594 ctxt->value->floatval = floor(ctxt->value->floatval);
8595 }
8596
8597 /**
8598 * xmlXPathCeilingFunction:
8599 * @ctxt: the XPath Parser context
8600 * @nargs: the number of arguments
8601 *
8602 * Implement the ceiling() XPath function
8603 * number ceiling(number)
8604 * The ceiling function returns the smallest (closest to negative infinity)
8605 * number that is not less than the argument and that is an integer.
8606 */
8607 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)8608 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8609 CHECK_ARITY(1);
8610 CAST_TO_NUMBER;
8611 CHECK_TYPE(XPATH_NUMBER);
8612
8613 #ifdef _AIX
8614 /* Work around buggy ceil() function on AIX */
8615 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8616 #else
8617 ctxt->value->floatval = ceil(ctxt->value->floatval);
8618 #endif
8619 }
8620
8621 /**
8622 * xmlXPathRoundFunction:
8623 * @ctxt: the XPath Parser context
8624 * @nargs: the number of arguments
8625 *
8626 * Implement the round() XPath function
8627 * number round(number)
8628 * The round function returns the number that is closest to the
8629 * argument and that is an integer. If there are two such numbers,
8630 * then the one that is closest to positive infinity is returned.
8631 */
8632 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)8633 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8634 double f;
8635
8636 CHECK_ARITY(1);
8637 CAST_TO_NUMBER;
8638 CHECK_TYPE(XPATH_NUMBER);
8639
8640 f = ctxt->value->floatval;
8641
8642 if ((f >= -0.5) && (f < 0.5)) {
8643 /* Handles negative zero. */
8644 ctxt->value->floatval *= 0.0;
8645 }
8646 else {
8647 double rounded = floor(f);
8648 if (f - rounded >= 0.5)
8649 rounded += 1.0;
8650 ctxt->value->floatval = rounded;
8651 }
8652 }
8653
8654 /************************************************************************
8655 * *
8656 * The Parser *
8657 * *
8658 ************************************************************************/
8659
8660 /*
8661 * a few forward declarations since we use a recursive call based
8662 * implementation.
8663 */
8664 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8665 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8666 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8667 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8668 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8669 int qualified);
8670
8671 /**
8672 * xmlXPathCurrentChar:
8673 * @ctxt: the XPath parser context
8674 * @cur: pointer to the beginning of the char
8675 * @len: pointer to the length of the char read
8676 *
8677 * The current char value, if using UTF-8 this may actually span multiple
8678 * bytes in the input buffer.
8679 *
8680 * Returns the current char value and its length
8681 */
8682
8683 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)8684 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8685 unsigned char c;
8686 unsigned int val;
8687 const xmlChar *cur;
8688
8689 if (ctxt == NULL)
8690 return(0);
8691 cur = ctxt->cur;
8692
8693 /*
8694 * We are supposed to handle UTF8, check it's valid
8695 * From rfc2044: encoding of the Unicode values on UTF-8:
8696 *
8697 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
8698 * 0000 0000-0000 007F 0xxxxxxx
8699 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
8700 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
8701 *
8702 * Check for the 0x110000 limit too
8703 */
8704 c = *cur;
8705 if (c & 0x80) {
8706 if ((cur[1] & 0xc0) != 0x80)
8707 goto encoding_error;
8708 if ((c & 0xe0) == 0xe0) {
8709
8710 if ((cur[2] & 0xc0) != 0x80)
8711 goto encoding_error;
8712 if ((c & 0xf0) == 0xf0) {
8713 if (((c & 0xf8) != 0xf0) ||
8714 ((cur[3] & 0xc0) != 0x80))
8715 goto encoding_error;
8716 /* 4-byte code */
8717 *len = 4;
8718 val = (cur[0] & 0x7) << 18;
8719 val |= (cur[1] & 0x3f) << 12;
8720 val |= (cur[2] & 0x3f) << 6;
8721 val |= cur[3] & 0x3f;
8722 } else {
8723 /* 3-byte code */
8724 *len = 3;
8725 val = (cur[0] & 0xf) << 12;
8726 val |= (cur[1] & 0x3f) << 6;
8727 val |= cur[2] & 0x3f;
8728 }
8729 } else {
8730 /* 2-byte code */
8731 *len = 2;
8732 val = (cur[0] & 0x1f) << 6;
8733 val |= cur[1] & 0x3f;
8734 }
8735 if (!IS_CHAR(val)) {
8736 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8737 }
8738 return(val);
8739 } else {
8740 /* 1-byte code */
8741 *len = 1;
8742 return(*cur);
8743 }
8744 encoding_error:
8745 /*
8746 * If we detect an UTF8 error that probably means that the
8747 * input encoding didn't get properly advertised in the
8748 * declaration header. Report the error and switch the encoding
8749 * to ISO-Latin-1 (if you don't like this policy, just declare the
8750 * encoding !)
8751 */
8752 *len = 0;
8753 XP_ERROR0(XPATH_ENCODING_ERROR);
8754 }
8755
8756 /**
8757 * xmlXPathParseNCName:
8758 * @ctxt: the XPath Parser context
8759 *
8760 * parse an XML namespace non qualified name.
8761 *
8762 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8763 *
8764 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8765 * CombiningChar | Extender
8766 *
8767 * Returns the namespace name or NULL
8768 */
8769
8770 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)8771 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8772 const xmlChar *in;
8773 xmlChar *ret;
8774 int count = 0;
8775
8776 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8777 /*
8778 * Accelerator for simple ASCII names
8779 */
8780 in = ctxt->cur;
8781 if (((*in >= 0x61) && (*in <= 0x7A)) ||
8782 ((*in >= 0x41) && (*in <= 0x5A)) ||
8783 (*in == '_')) {
8784 in++;
8785 while (((*in >= 0x61) && (*in <= 0x7A)) ||
8786 ((*in >= 0x41) && (*in <= 0x5A)) ||
8787 ((*in >= 0x30) && (*in <= 0x39)) ||
8788 (*in == '_') || (*in == '.') ||
8789 (*in == '-'))
8790 in++;
8791 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8792 (*in == '[') || (*in == ']') || (*in == ':') ||
8793 (*in == '@') || (*in == '*')) {
8794 count = in - ctxt->cur;
8795 if (count == 0)
8796 return(NULL);
8797 ret = xmlStrndup(ctxt->cur, count);
8798 if (ret == NULL)
8799 xmlXPathPErrMemory(ctxt);
8800 ctxt->cur = in;
8801 return(ret);
8802 }
8803 }
8804 return(xmlXPathParseNameComplex(ctxt, 0));
8805 }
8806
8807
8808 /**
8809 * xmlXPathParseQName:
8810 * @ctxt: the XPath Parser context
8811 * @prefix: a xmlChar **
8812 *
8813 * parse an XML qualified name
8814 *
8815 * [NS 5] QName ::= (Prefix ':')? LocalPart
8816 *
8817 * [NS 6] Prefix ::= NCName
8818 *
8819 * [NS 7] LocalPart ::= NCName
8820 *
8821 * Returns the function returns the local part, and prefix is updated
8822 * to get the Prefix if any.
8823 */
8824
8825 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)8826 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8827 xmlChar *ret = NULL;
8828
8829 *prefix = NULL;
8830 ret = xmlXPathParseNCName(ctxt);
8831 if (ret && CUR == ':') {
8832 *prefix = ret;
8833 NEXT;
8834 ret = xmlXPathParseNCName(ctxt);
8835 }
8836 return(ret);
8837 }
8838
8839 /**
8840 * xmlXPathParseName:
8841 * @ctxt: the XPath Parser context
8842 *
8843 * parse an XML name
8844 *
8845 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8846 * CombiningChar | Extender
8847 *
8848 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8849 *
8850 * Returns the namespace name or NULL
8851 */
8852
8853 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)8854 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8855 const xmlChar *in;
8856 xmlChar *ret;
8857 size_t count = 0;
8858
8859 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8860 /*
8861 * Accelerator for simple ASCII names
8862 */
8863 in = ctxt->cur;
8864 if (((*in >= 0x61) && (*in <= 0x7A)) ||
8865 ((*in >= 0x41) && (*in <= 0x5A)) ||
8866 (*in == '_') || (*in == ':')) {
8867 in++;
8868 while (((*in >= 0x61) && (*in <= 0x7A)) ||
8869 ((*in >= 0x41) && (*in <= 0x5A)) ||
8870 ((*in >= 0x30) && (*in <= 0x39)) ||
8871 (*in == '_') || (*in == '-') ||
8872 (*in == ':') || (*in == '.'))
8873 in++;
8874 if ((*in > 0) && (*in < 0x80)) {
8875 count = in - ctxt->cur;
8876 if (count > XML_MAX_NAME_LENGTH) {
8877 ctxt->cur = in;
8878 XP_ERRORNULL(XPATH_EXPR_ERROR);
8879 }
8880 ret = xmlStrndup(ctxt->cur, count);
8881 if (ret == NULL)
8882 xmlXPathPErrMemory(ctxt);
8883 ctxt->cur = in;
8884 return(ret);
8885 }
8886 }
8887 return(xmlXPathParseNameComplex(ctxt, 1));
8888 }
8889
8890 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)8891 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8892 xmlChar *ret;
8893 xmlChar buf[XML_MAX_NAMELEN + 5];
8894 int len = 0, l;
8895 int c;
8896
8897 /*
8898 * Handler for more complex cases
8899 */
8900 c = CUR_CHAR(l);
8901 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8902 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8903 (c == '*') || /* accelerators */
8904 (!IS_LETTER(c) && (c != '_') &&
8905 ((!qualified) || (c != ':')))) {
8906 return(NULL);
8907 }
8908
8909 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8910 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8911 (c == '.') || (c == '-') ||
8912 (c == '_') || ((qualified) && (c == ':')) ||
8913 (IS_COMBINING(c)) ||
8914 (IS_EXTENDER(c)))) {
8915 COPY_BUF(l,buf,len,c);
8916 NEXTL(l);
8917 c = CUR_CHAR(l);
8918 if (len >= XML_MAX_NAMELEN) {
8919 /*
8920 * Okay someone managed to make a huge name, so he's ready to pay
8921 * for the processing speed.
8922 */
8923 xmlChar *buffer;
8924 int max = len * 2;
8925
8926 if (len > XML_MAX_NAME_LENGTH) {
8927 XP_ERRORNULL(XPATH_EXPR_ERROR);
8928 }
8929 buffer = (xmlChar *) xmlMallocAtomic(max);
8930 if (buffer == NULL) {
8931 xmlXPathPErrMemory(ctxt);
8932 return(NULL);
8933 }
8934 memcpy(buffer, buf, len);
8935 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8936 (c == '.') || (c == '-') ||
8937 (c == '_') || ((qualified) && (c == ':')) ||
8938 (IS_COMBINING(c)) ||
8939 (IS_EXTENDER(c))) {
8940 if (len + 10 > max) {
8941 xmlChar *tmp;
8942 if (max > XML_MAX_NAME_LENGTH) {
8943 xmlFree(buffer);
8944 XP_ERRORNULL(XPATH_EXPR_ERROR);
8945 }
8946 max *= 2;
8947 tmp = (xmlChar *) xmlRealloc(buffer, max);
8948 if (tmp == NULL) {
8949 xmlFree(buffer);
8950 xmlXPathPErrMemory(ctxt);
8951 return(NULL);
8952 }
8953 buffer = tmp;
8954 }
8955 COPY_BUF(l,buffer,len,c);
8956 NEXTL(l);
8957 c = CUR_CHAR(l);
8958 }
8959 buffer[len] = 0;
8960 return(buffer);
8961 }
8962 }
8963 if (len == 0)
8964 return(NULL);
8965 ret = xmlStrndup(buf, len);
8966 if (ret == NULL)
8967 xmlXPathPErrMemory(ctxt);
8968 return(ret);
8969 }
8970
8971 #define MAX_FRAC 20
8972
8973 /**
8974 * xmlXPathStringEvalNumber:
8975 * @str: A string to scan
8976 *
8977 * [30a] Float ::= Number ('e' Digits?)?
8978 *
8979 * [30] Number ::= Digits ('.' Digits?)?
8980 * | '.' Digits
8981 * [31] Digits ::= [0-9]+
8982 *
8983 * Compile a Number in the string
8984 * In complement of the Number expression, this function also handles
8985 * negative values : '-' Number.
8986 *
8987 * Returns the double value.
8988 */
8989 double
xmlXPathStringEvalNumber(const xmlChar * str)8990 xmlXPathStringEvalNumber(const xmlChar *str) {
8991 const xmlChar *cur = str;
8992 double ret;
8993 int ok = 0;
8994 int isneg = 0;
8995 int exponent = 0;
8996 int is_exponent_negative = 0;
8997 #ifdef __GNUC__
8998 unsigned long tmp = 0;
8999 double temp;
9000 #endif
9001 if (cur == NULL) return(0);
9002 while (IS_BLANK_CH(*cur)) cur++;
9003 if (*cur == '-') {
9004 isneg = 1;
9005 cur++;
9006 }
9007 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9008 return(xmlXPathNAN);
9009 }
9010
9011 #ifdef __GNUC__
9012 /*
9013 * tmp/temp is a workaround against a gcc compiler bug
9014 * http://veillard.com/gcc.bug
9015 */
9016 ret = 0;
9017 while ((*cur >= '0') && (*cur <= '9')) {
9018 ret = ret * 10;
9019 tmp = (*cur - '0');
9020 ok = 1;
9021 cur++;
9022 temp = (double) tmp;
9023 ret = ret + temp;
9024 }
9025 #else
9026 ret = 0;
9027 while ((*cur >= '0') && (*cur <= '9')) {
9028 ret = ret * 10 + (*cur - '0');
9029 ok = 1;
9030 cur++;
9031 }
9032 #endif
9033
9034 if (*cur == '.') {
9035 int v, frac = 0, max;
9036 double fraction = 0;
9037
9038 cur++;
9039 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9040 return(xmlXPathNAN);
9041 }
9042 while (*cur == '0') {
9043 frac = frac + 1;
9044 cur++;
9045 }
9046 max = frac + MAX_FRAC;
9047 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
9048 v = (*cur - '0');
9049 fraction = fraction * 10 + v;
9050 frac = frac + 1;
9051 cur++;
9052 }
9053 fraction /= pow(10.0, frac);
9054 ret = ret + fraction;
9055 while ((*cur >= '0') && (*cur <= '9'))
9056 cur++;
9057 }
9058 if ((*cur == 'e') || (*cur == 'E')) {
9059 cur++;
9060 if (*cur == '-') {
9061 is_exponent_negative = 1;
9062 cur++;
9063 } else if (*cur == '+') {
9064 cur++;
9065 }
9066 while ((*cur >= '0') && (*cur <= '9')) {
9067 if (exponent < 1000000)
9068 exponent = exponent * 10 + (*cur - '0');
9069 cur++;
9070 }
9071 }
9072 while (IS_BLANK_CH(*cur)) cur++;
9073 if (*cur != 0) return(xmlXPathNAN);
9074 if (isneg) ret = -ret;
9075 if (is_exponent_negative) exponent = -exponent;
9076 ret *= pow(10.0, (double)exponent);
9077 return(ret);
9078 }
9079
9080 /**
9081 * xmlXPathCompNumber:
9082 * @ctxt: the XPath Parser context
9083 *
9084 * [30] Number ::= Digits ('.' Digits?)?
9085 * | '.' Digits
9086 * [31] Digits ::= [0-9]+
9087 *
9088 * Compile a Number, then push it on the stack
9089 *
9090 */
9091 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)9092 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9093 {
9094 double ret = 0.0;
9095 int ok = 0;
9096 int exponent = 0;
9097 int is_exponent_negative = 0;
9098 xmlXPathObjectPtr num;
9099 #ifdef __GNUC__
9100 unsigned long tmp = 0;
9101 double temp;
9102 #endif
9103
9104 CHECK_ERROR;
9105 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9106 XP_ERROR(XPATH_NUMBER_ERROR);
9107 }
9108 #ifdef __GNUC__
9109 /*
9110 * tmp/temp is a workaround against a gcc compiler bug
9111 * http://veillard.com/gcc.bug
9112 */
9113 ret = 0;
9114 while ((CUR >= '0') && (CUR <= '9')) {
9115 ret = ret * 10;
9116 tmp = (CUR - '0');
9117 ok = 1;
9118 NEXT;
9119 temp = (double) tmp;
9120 ret = ret + temp;
9121 }
9122 #else
9123 ret = 0;
9124 while ((CUR >= '0') && (CUR <= '9')) {
9125 ret = ret * 10 + (CUR - '0');
9126 ok = 1;
9127 NEXT;
9128 }
9129 #endif
9130 if (CUR == '.') {
9131 int v, frac = 0, max;
9132 double fraction = 0;
9133
9134 NEXT;
9135 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9136 XP_ERROR(XPATH_NUMBER_ERROR);
9137 }
9138 while (CUR == '0') {
9139 frac = frac + 1;
9140 NEXT;
9141 }
9142 max = frac + MAX_FRAC;
9143 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9144 v = (CUR - '0');
9145 fraction = fraction * 10 + v;
9146 frac = frac + 1;
9147 NEXT;
9148 }
9149 fraction /= pow(10.0, frac);
9150 ret = ret + fraction;
9151 while ((CUR >= '0') && (CUR <= '9'))
9152 NEXT;
9153 }
9154 if ((CUR == 'e') || (CUR == 'E')) {
9155 NEXT;
9156 if (CUR == '-') {
9157 is_exponent_negative = 1;
9158 NEXT;
9159 } else if (CUR == '+') {
9160 NEXT;
9161 }
9162 while ((CUR >= '0') && (CUR <= '9')) {
9163 if (exponent < 1000000)
9164 exponent = exponent * 10 + (CUR - '0');
9165 NEXT;
9166 }
9167 if (is_exponent_negative)
9168 exponent = -exponent;
9169 ret *= pow(10.0, (double) exponent);
9170 }
9171 num = xmlXPathCacheNewFloat(ctxt, ret);
9172 if (num == NULL) {
9173 ctxt->error = XPATH_MEMORY_ERROR;
9174 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9175 NULL) == -1) {
9176 xmlXPathReleaseObject(ctxt->context, num);
9177 }
9178 }
9179
9180 /**
9181 * xmlXPathParseLiteral:
9182 * @ctxt: the XPath Parser context
9183 *
9184 * Parse a Literal
9185 *
9186 * [29] Literal ::= '"' [^"]* '"'
9187 * | "'" [^']* "'"
9188 *
9189 * Returns the value found or NULL in case of error
9190 */
9191 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)9192 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9193 const xmlChar *q;
9194 xmlChar *ret = NULL;
9195 int quote;
9196
9197 if (CUR == '"') {
9198 quote = '"';
9199 } else if (CUR == '\'') {
9200 quote = '\'';
9201 } else {
9202 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9203 }
9204
9205 NEXT;
9206 q = CUR_PTR;
9207 while (CUR != quote) {
9208 int ch;
9209 int len = 4;
9210
9211 if (CUR == 0)
9212 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9213 ch = xmlGetUTF8Char(CUR_PTR, &len);
9214 if ((ch < 0) || (IS_CHAR(ch) == 0))
9215 XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
9216 CUR_PTR += len;
9217 }
9218 ret = xmlStrndup(q, CUR_PTR - q);
9219 if (ret == NULL)
9220 xmlXPathPErrMemory(ctxt);
9221 NEXT;
9222 return(ret);
9223 }
9224
9225 /**
9226 * xmlXPathCompLiteral:
9227 * @ctxt: the XPath Parser context
9228 *
9229 * Parse a Literal and push it on the stack.
9230 *
9231 * [29] Literal ::= '"' [^"]* '"'
9232 * | "'" [^']* "'"
9233 *
9234 * TODO: xmlXPathCompLiteral memory allocation could be improved.
9235 */
9236 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)9237 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9238 xmlChar *ret = NULL;
9239 xmlXPathObjectPtr lit;
9240
9241 ret = xmlXPathParseLiteral(ctxt);
9242 if (ret == NULL)
9243 return;
9244 lit = xmlXPathCacheNewString(ctxt, ret);
9245 if (lit == NULL) {
9246 ctxt->error = XPATH_MEMORY_ERROR;
9247 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9248 NULL) == -1) {
9249 xmlXPathReleaseObject(ctxt->context, lit);
9250 }
9251 xmlFree(ret);
9252 }
9253
9254 /**
9255 * xmlXPathCompVariableReference:
9256 * @ctxt: the XPath Parser context
9257 *
9258 * Parse a VariableReference, evaluate it and push it on the stack.
9259 *
9260 * The variable bindings consist of a mapping from variable names
9261 * to variable values. The value of a variable is an object, which can be
9262 * of any of the types that are possible for the value of an expression,
9263 * and may also be of additional types not specified here.
9264 *
9265 * Early evaluation is possible since:
9266 * The variable bindings [...] used to evaluate a subexpression are
9267 * always the same as those used to evaluate the containing expression.
9268 *
9269 * [36] VariableReference ::= '$' QName
9270 */
9271 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)9272 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9273 xmlChar *name;
9274 xmlChar *prefix;
9275
9276 SKIP_BLANKS;
9277 if (CUR != '$') {
9278 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9279 }
9280 NEXT;
9281 name = xmlXPathParseQName(ctxt, &prefix);
9282 if (name == NULL) {
9283 xmlFree(prefix);
9284 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9285 }
9286 ctxt->comp->last = -1;
9287 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9288 xmlFree(prefix);
9289 xmlFree(name);
9290 }
9291 SKIP_BLANKS;
9292 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9293 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9294 }
9295 }
9296
9297 /**
9298 * xmlXPathIsNodeType:
9299 * @name: a name string
9300 *
9301 * Is the name given a NodeType one.
9302 *
9303 * [38] NodeType ::= 'comment'
9304 * | 'text'
9305 * | 'processing-instruction'
9306 * | 'node'
9307 *
9308 * Returns 1 if true 0 otherwise
9309 */
9310 int
xmlXPathIsNodeType(const xmlChar * name)9311 xmlXPathIsNodeType(const xmlChar *name) {
9312 if (name == NULL)
9313 return(0);
9314
9315 if (xmlStrEqual(name, BAD_CAST "node"))
9316 return(1);
9317 if (xmlStrEqual(name, BAD_CAST "text"))
9318 return(1);
9319 if (xmlStrEqual(name, BAD_CAST "comment"))
9320 return(1);
9321 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9322 return(1);
9323 return(0);
9324 }
9325
9326 /**
9327 * xmlXPathCompFunctionCall:
9328 * @ctxt: the XPath Parser context
9329 *
9330 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9331 * [17] Argument ::= Expr
9332 *
9333 * Compile a function call, the evaluation of all arguments are
9334 * pushed on the stack
9335 */
9336 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)9337 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9338 xmlChar *name;
9339 xmlChar *prefix;
9340 int nbargs = 0;
9341 int sort = 1;
9342
9343 name = xmlXPathParseQName(ctxt, &prefix);
9344 if (name == NULL) {
9345 xmlFree(prefix);
9346 XP_ERROR(XPATH_EXPR_ERROR);
9347 }
9348 SKIP_BLANKS;
9349
9350 if (CUR != '(') {
9351 xmlFree(name);
9352 xmlFree(prefix);
9353 XP_ERROR(XPATH_EXPR_ERROR);
9354 }
9355 NEXT;
9356 SKIP_BLANKS;
9357
9358 /*
9359 * Optimization for count(): we don't need the node-set to be sorted.
9360 */
9361 if ((prefix == NULL) && (name[0] == 'c') &&
9362 xmlStrEqual(name, BAD_CAST "count"))
9363 {
9364 sort = 0;
9365 }
9366 ctxt->comp->last = -1;
9367 if (CUR != ')') {
9368 while (CUR != 0) {
9369 int op1 = ctxt->comp->last;
9370 ctxt->comp->last = -1;
9371 xmlXPathCompileExpr(ctxt, sort);
9372 if (ctxt->error != XPATH_EXPRESSION_OK) {
9373 xmlFree(name);
9374 xmlFree(prefix);
9375 return;
9376 }
9377 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9378 nbargs++;
9379 if (CUR == ')') break;
9380 if (CUR != ',') {
9381 xmlFree(name);
9382 xmlFree(prefix);
9383 XP_ERROR(XPATH_EXPR_ERROR);
9384 }
9385 NEXT;
9386 SKIP_BLANKS;
9387 }
9388 }
9389 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9390 xmlFree(prefix);
9391 xmlFree(name);
9392 }
9393 NEXT;
9394 SKIP_BLANKS;
9395 }
9396
9397 /**
9398 * xmlXPathCompPrimaryExpr:
9399 * @ctxt: the XPath Parser context
9400 *
9401 * [15] PrimaryExpr ::= VariableReference
9402 * | '(' Expr ')'
9403 * | Literal
9404 * | Number
9405 * | FunctionCall
9406 *
9407 * Compile a primary expression.
9408 */
9409 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)9410 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9411 SKIP_BLANKS;
9412 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9413 else if (CUR == '(') {
9414 NEXT;
9415 SKIP_BLANKS;
9416 xmlXPathCompileExpr(ctxt, 1);
9417 CHECK_ERROR;
9418 if (CUR != ')') {
9419 XP_ERROR(XPATH_EXPR_ERROR);
9420 }
9421 NEXT;
9422 SKIP_BLANKS;
9423 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9424 xmlXPathCompNumber(ctxt);
9425 } else if ((CUR == '\'') || (CUR == '"')) {
9426 xmlXPathCompLiteral(ctxt);
9427 } else {
9428 xmlXPathCompFunctionCall(ctxt);
9429 }
9430 SKIP_BLANKS;
9431 }
9432
9433 /**
9434 * xmlXPathCompFilterExpr:
9435 * @ctxt: the XPath Parser context
9436 *
9437 * [20] FilterExpr ::= PrimaryExpr
9438 * | FilterExpr Predicate
9439 *
9440 * Compile a filter expression.
9441 * Square brackets are used to filter expressions in the same way that
9442 * they are used in location paths. It is an error if the expression to
9443 * be filtered does not evaluate to a node-set. The context node list
9444 * used for evaluating the expression in square brackets is the node-set
9445 * to be filtered listed in document order.
9446 */
9447
9448 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)9449 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9450 xmlXPathCompPrimaryExpr(ctxt);
9451 CHECK_ERROR;
9452 SKIP_BLANKS;
9453
9454 while (CUR == '[') {
9455 xmlXPathCompPredicate(ctxt, 1);
9456 SKIP_BLANKS;
9457 }
9458
9459
9460 }
9461
9462 /**
9463 * xmlXPathScanName:
9464 * @ctxt: the XPath Parser context
9465 *
9466 * Trickery: parse an XML name but without consuming the input flow
9467 * Needed to avoid insanity in the parser state.
9468 *
9469 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9470 * CombiningChar | Extender
9471 *
9472 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9473 *
9474 * [6] Names ::= Name (S Name)*
9475 *
9476 * Returns the Name parsed or NULL
9477 */
9478
9479 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)9480 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9481 int l;
9482 int c;
9483 const xmlChar *cur;
9484 xmlChar *ret;
9485
9486 cur = ctxt->cur;
9487
9488 c = CUR_CHAR(l);
9489 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9490 (!IS_LETTER(c) && (c != '_') &&
9491 (c != ':'))) {
9492 return(NULL);
9493 }
9494
9495 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9496 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9497 (c == '.') || (c == '-') ||
9498 (c == '_') || (c == ':') ||
9499 (IS_COMBINING(c)) ||
9500 (IS_EXTENDER(c)))) {
9501 NEXTL(l);
9502 c = CUR_CHAR(l);
9503 }
9504 ret = xmlStrndup(cur, ctxt->cur - cur);
9505 if (ret == NULL)
9506 xmlXPathPErrMemory(ctxt);
9507 ctxt->cur = cur;
9508 return(ret);
9509 }
9510
9511 /**
9512 * xmlXPathCompPathExpr:
9513 * @ctxt: the XPath Parser context
9514 *
9515 * [19] PathExpr ::= LocationPath
9516 * | FilterExpr
9517 * | FilterExpr '/' RelativeLocationPath
9518 * | FilterExpr '//' RelativeLocationPath
9519 *
9520 * Compile a path expression.
9521 * The / operator and // operators combine an arbitrary expression
9522 * and a relative location path. It is an error if the expression
9523 * does not evaluate to a node-set.
9524 * The / operator does composition in the same way as when / is
9525 * used in a location path. As in location paths, // is short for
9526 * /descendant-or-self::node()/.
9527 */
9528
9529 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)9530 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9531 int lc = 1; /* Should we branch to LocationPath ? */
9532 xmlChar *name = NULL; /* we may have to preparse a name to find out */
9533
9534 SKIP_BLANKS;
9535 if ((CUR == '$') || (CUR == '(') ||
9536 (IS_ASCII_DIGIT(CUR)) ||
9537 (CUR == '\'') || (CUR == '"') ||
9538 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9539 lc = 0;
9540 } else if (CUR == '*') {
9541 /* relative or absolute location path */
9542 lc = 1;
9543 } else if (CUR == '/') {
9544 /* relative or absolute location path */
9545 lc = 1;
9546 } else if (CUR == '@') {
9547 /* relative abbreviated attribute location path */
9548 lc = 1;
9549 } else if (CUR == '.') {
9550 /* relative abbreviated attribute location path */
9551 lc = 1;
9552 } else {
9553 /*
9554 * Problem is finding if we have a name here whether it's:
9555 * - a nodetype
9556 * - a function call in which case it's followed by '('
9557 * - an axis in which case it's followed by ':'
9558 * - a element name
9559 * We do an a priori analysis here rather than having to
9560 * maintain parsed token content through the recursive function
9561 * calls. This looks uglier but makes the code easier to
9562 * read/write/debug.
9563 */
9564 SKIP_BLANKS;
9565 name = xmlXPathScanName(ctxt);
9566 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9567 lc = 1;
9568 xmlFree(name);
9569 } else if (name != NULL) {
9570 int len =xmlStrlen(name);
9571
9572
9573 while (NXT(len) != 0) {
9574 if (NXT(len) == '/') {
9575 /* element name */
9576 lc = 1;
9577 break;
9578 } else if (IS_BLANK_CH(NXT(len))) {
9579 /* ignore blanks */
9580 ;
9581 } else if (NXT(len) == ':') {
9582 lc = 1;
9583 break;
9584 } else if ((NXT(len) == '(')) {
9585 /* Node Type or Function */
9586 if (xmlXPathIsNodeType(name)) {
9587 lc = 1;
9588 #ifdef LIBXML_XPTR_LOCS_ENABLED
9589 } else if (ctxt->xptr &&
9590 xmlStrEqual(name, BAD_CAST "range-to")) {
9591 lc = 1;
9592 #endif
9593 } else {
9594 lc = 0;
9595 }
9596 break;
9597 } else if ((NXT(len) == '[')) {
9598 /* element name */
9599 lc = 1;
9600 break;
9601 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9602 (NXT(len) == '=')) {
9603 lc = 1;
9604 break;
9605 } else {
9606 lc = 1;
9607 break;
9608 }
9609 len++;
9610 }
9611 if (NXT(len) == 0) {
9612 /* element name */
9613 lc = 1;
9614 }
9615 xmlFree(name);
9616 } else {
9617 /* make sure all cases are covered explicitly */
9618 XP_ERROR(XPATH_EXPR_ERROR);
9619 }
9620 }
9621
9622 if (lc) {
9623 if (CUR == '/') {
9624 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9625 } else {
9626 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9627 }
9628 xmlXPathCompLocationPath(ctxt);
9629 } else {
9630 xmlXPathCompFilterExpr(ctxt);
9631 CHECK_ERROR;
9632 if ((CUR == '/') && (NXT(1) == '/')) {
9633 SKIP(2);
9634 SKIP_BLANKS;
9635
9636 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9637 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9638
9639 xmlXPathCompRelativeLocationPath(ctxt);
9640 } else if (CUR == '/') {
9641 xmlXPathCompRelativeLocationPath(ctxt);
9642 }
9643 }
9644 SKIP_BLANKS;
9645 }
9646
9647 /**
9648 * xmlXPathCompUnionExpr:
9649 * @ctxt: the XPath Parser context
9650 *
9651 * [18] UnionExpr ::= PathExpr
9652 * | UnionExpr '|' PathExpr
9653 *
9654 * Compile an union expression.
9655 */
9656
9657 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)9658 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9659 xmlXPathCompPathExpr(ctxt);
9660 CHECK_ERROR;
9661 SKIP_BLANKS;
9662 while (CUR == '|') {
9663 int op1 = ctxt->comp->last;
9664 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9665
9666 NEXT;
9667 SKIP_BLANKS;
9668 xmlXPathCompPathExpr(ctxt);
9669
9670 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9671
9672 SKIP_BLANKS;
9673 }
9674 }
9675
9676 /**
9677 * xmlXPathCompUnaryExpr:
9678 * @ctxt: the XPath Parser context
9679 *
9680 * [27] UnaryExpr ::= UnionExpr
9681 * | '-' UnaryExpr
9682 *
9683 * Compile an unary expression.
9684 */
9685
9686 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)9687 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9688 int minus = 0;
9689 int found = 0;
9690
9691 SKIP_BLANKS;
9692 while (CUR == '-') {
9693 minus = 1 - minus;
9694 found = 1;
9695 NEXT;
9696 SKIP_BLANKS;
9697 }
9698
9699 xmlXPathCompUnionExpr(ctxt);
9700 CHECK_ERROR;
9701 if (found) {
9702 if (minus)
9703 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9704 else
9705 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9706 }
9707 }
9708
9709 /**
9710 * xmlXPathCompMultiplicativeExpr:
9711 * @ctxt: the XPath Parser context
9712 *
9713 * [26] MultiplicativeExpr ::= UnaryExpr
9714 * | MultiplicativeExpr MultiplyOperator UnaryExpr
9715 * | MultiplicativeExpr 'div' UnaryExpr
9716 * | MultiplicativeExpr 'mod' UnaryExpr
9717 * [34] MultiplyOperator ::= '*'
9718 *
9719 * Compile an Additive expression.
9720 */
9721
9722 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)9723 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9724 xmlXPathCompUnaryExpr(ctxt);
9725 CHECK_ERROR;
9726 SKIP_BLANKS;
9727 while ((CUR == '*') ||
9728 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9729 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9730 int op = -1;
9731 int op1 = ctxt->comp->last;
9732
9733 if (CUR == '*') {
9734 op = 0;
9735 NEXT;
9736 } else if (CUR == 'd') {
9737 op = 1;
9738 SKIP(3);
9739 } else if (CUR == 'm') {
9740 op = 2;
9741 SKIP(3);
9742 }
9743 SKIP_BLANKS;
9744 xmlXPathCompUnaryExpr(ctxt);
9745 CHECK_ERROR;
9746 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9747 SKIP_BLANKS;
9748 }
9749 }
9750
9751 /**
9752 * xmlXPathCompAdditiveExpr:
9753 * @ctxt: the XPath Parser context
9754 *
9755 * [25] AdditiveExpr ::= MultiplicativeExpr
9756 * | AdditiveExpr '+' MultiplicativeExpr
9757 * | AdditiveExpr '-' MultiplicativeExpr
9758 *
9759 * Compile an Additive expression.
9760 */
9761
9762 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)9763 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9764
9765 xmlXPathCompMultiplicativeExpr(ctxt);
9766 CHECK_ERROR;
9767 SKIP_BLANKS;
9768 while ((CUR == '+') || (CUR == '-')) {
9769 int plus;
9770 int op1 = ctxt->comp->last;
9771
9772 if (CUR == '+') plus = 1;
9773 else plus = 0;
9774 NEXT;
9775 SKIP_BLANKS;
9776 xmlXPathCompMultiplicativeExpr(ctxt);
9777 CHECK_ERROR;
9778 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9779 SKIP_BLANKS;
9780 }
9781 }
9782
9783 /**
9784 * xmlXPathCompRelationalExpr:
9785 * @ctxt: the XPath Parser context
9786 *
9787 * [24] RelationalExpr ::= AdditiveExpr
9788 * | RelationalExpr '<' AdditiveExpr
9789 * | RelationalExpr '>' AdditiveExpr
9790 * | RelationalExpr '<=' AdditiveExpr
9791 * | RelationalExpr '>=' AdditiveExpr
9792 *
9793 * A <= B > C is allowed ? Answer from James, yes with
9794 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9795 * which is basically what got implemented.
9796 *
9797 * Compile a Relational expression, then push the result
9798 * on the stack
9799 */
9800
9801 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)9802 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9803 xmlXPathCompAdditiveExpr(ctxt);
9804 CHECK_ERROR;
9805 SKIP_BLANKS;
9806 while ((CUR == '<') || (CUR == '>')) {
9807 int inf, strict;
9808 int op1 = ctxt->comp->last;
9809
9810 if (CUR == '<') inf = 1;
9811 else inf = 0;
9812 if (NXT(1) == '=') strict = 0;
9813 else strict = 1;
9814 NEXT;
9815 if (!strict) NEXT;
9816 SKIP_BLANKS;
9817 xmlXPathCompAdditiveExpr(ctxt);
9818 CHECK_ERROR;
9819 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9820 SKIP_BLANKS;
9821 }
9822 }
9823
9824 /**
9825 * xmlXPathCompEqualityExpr:
9826 * @ctxt: the XPath Parser context
9827 *
9828 * [23] EqualityExpr ::= RelationalExpr
9829 * | EqualityExpr '=' RelationalExpr
9830 * | EqualityExpr '!=' RelationalExpr
9831 *
9832 * A != B != C is allowed ? Answer from James, yes with
9833 * (RelationalExpr = RelationalExpr) = RelationalExpr
9834 * (RelationalExpr != RelationalExpr) != RelationalExpr
9835 * which is basically what got implemented.
9836 *
9837 * Compile an Equality expression.
9838 *
9839 */
9840 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)9841 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9842 xmlXPathCompRelationalExpr(ctxt);
9843 CHECK_ERROR;
9844 SKIP_BLANKS;
9845 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9846 int eq;
9847 int op1 = ctxt->comp->last;
9848
9849 if (CUR == '=') eq = 1;
9850 else eq = 0;
9851 NEXT;
9852 if (!eq) NEXT;
9853 SKIP_BLANKS;
9854 xmlXPathCompRelationalExpr(ctxt);
9855 CHECK_ERROR;
9856 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9857 SKIP_BLANKS;
9858 }
9859 }
9860
9861 /**
9862 * xmlXPathCompAndExpr:
9863 * @ctxt: the XPath Parser context
9864 *
9865 * [22] AndExpr ::= EqualityExpr
9866 * | AndExpr 'and' EqualityExpr
9867 *
9868 * Compile an AND expression.
9869 *
9870 */
9871 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)9872 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9873 xmlXPathCompEqualityExpr(ctxt);
9874 CHECK_ERROR;
9875 SKIP_BLANKS;
9876 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9877 int op1 = ctxt->comp->last;
9878 SKIP(3);
9879 SKIP_BLANKS;
9880 xmlXPathCompEqualityExpr(ctxt);
9881 CHECK_ERROR;
9882 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9883 SKIP_BLANKS;
9884 }
9885 }
9886
9887 /**
9888 * xmlXPathCompileExpr:
9889 * @ctxt: the XPath Parser context
9890 *
9891 * [14] Expr ::= OrExpr
9892 * [21] OrExpr ::= AndExpr
9893 * | OrExpr 'or' AndExpr
9894 *
9895 * Parse and compile an expression
9896 */
9897 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)9898 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9899 xmlXPathContextPtr xpctxt = ctxt->context;
9900
9901 if (xpctxt != NULL) {
9902 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9903 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9904 /*
9905 * Parsing a single '(' pushes about 10 functions on the call stack
9906 * before recursing!
9907 */
9908 xpctxt->depth += 10;
9909 }
9910
9911 xmlXPathCompAndExpr(ctxt);
9912 CHECK_ERROR;
9913 SKIP_BLANKS;
9914 while ((CUR == 'o') && (NXT(1) == 'r')) {
9915 int op1 = ctxt->comp->last;
9916 SKIP(2);
9917 SKIP_BLANKS;
9918 xmlXPathCompAndExpr(ctxt);
9919 CHECK_ERROR;
9920 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9921 SKIP_BLANKS;
9922 }
9923 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9924 /* more ops could be optimized too */
9925 /*
9926 * This is the main place to eliminate sorting for
9927 * operations which don't require a sorted node-set.
9928 * E.g. count().
9929 */
9930 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9931 }
9932
9933 if (xpctxt != NULL)
9934 xpctxt->depth -= 10;
9935 }
9936
9937 /**
9938 * xmlXPathCompPredicate:
9939 * @ctxt: the XPath Parser context
9940 * @filter: act as a filter
9941 *
9942 * [8] Predicate ::= '[' PredicateExpr ']'
9943 * [9] PredicateExpr ::= Expr
9944 *
9945 * Compile a predicate expression
9946 */
9947 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)9948 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9949 int op1 = ctxt->comp->last;
9950
9951 SKIP_BLANKS;
9952 if (CUR != '[') {
9953 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9954 }
9955 NEXT;
9956 SKIP_BLANKS;
9957
9958 ctxt->comp->last = -1;
9959 /*
9960 * This call to xmlXPathCompileExpr() will deactivate sorting
9961 * of the predicate result.
9962 * TODO: Sorting is still activated for filters, since I'm not
9963 * sure if needed. Normally sorting should not be needed, since
9964 * a filter can only diminish the number of items in a sequence,
9965 * but won't change its order; so if the initial sequence is sorted,
9966 * subsequent sorting is not needed.
9967 */
9968 if (! filter)
9969 xmlXPathCompileExpr(ctxt, 0);
9970 else
9971 xmlXPathCompileExpr(ctxt, 1);
9972 CHECK_ERROR;
9973
9974 if (CUR != ']') {
9975 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9976 }
9977
9978 if (filter)
9979 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9980 else
9981 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9982
9983 NEXT;
9984 SKIP_BLANKS;
9985 }
9986
9987 /**
9988 * xmlXPathCompNodeTest:
9989 * @ctxt: the XPath Parser context
9990 * @test: pointer to a xmlXPathTestVal
9991 * @type: pointer to a xmlXPathTypeVal
9992 * @prefix: placeholder for a possible name prefix
9993 *
9994 * [7] NodeTest ::= NameTest
9995 * | NodeType '(' ')'
9996 * | 'processing-instruction' '(' Literal ')'
9997 *
9998 * [37] NameTest ::= '*'
9999 * | NCName ':' '*'
10000 * | QName
10001 * [38] NodeType ::= 'comment'
10002 * | 'text'
10003 * | 'processing-instruction'
10004 * | 'node'
10005 *
10006 * Returns the name found and updates @test, @type and @prefix appropriately
10007 */
10008 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)10009 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10010 xmlXPathTypeVal *type, xmlChar **prefix,
10011 xmlChar *name) {
10012 int blanks;
10013
10014 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10015 return(NULL);
10016 }
10017 *type = (xmlXPathTypeVal) 0;
10018 *test = (xmlXPathTestVal) 0;
10019 *prefix = NULL;
10020 SKIP_BLANKS;
10021
10022 if ((name == NULL) && (CUR == '*')) {
10023 /*
10024 * All elements
10025 */
10026 NEXT;
10027 *test = NODE_TEST_ALL;
10028 return(NULL);
10029 }
10030
10031 if (name == NULL)
10032 name = xmlXPathParseNCName(ctxt);
10033 if (name == NULL) {
10034 XP_ERRORNULL(XPATH_EXPR_ERROR);
10035 }
10036
10037 blanks = IS_BLANK_CH(CUR);
10038 SKIP_BLANKS;
10039 if (CUR == '(') {
10040 NEXT;
10041 /*
10042 * NodeType or PI search
10043 */
10044 if (xmlStrEqual(name, BAD_CAST "comment"))
10045 *type = NODE_TYPE_COMMENT;
10046 else if (xmlStrEqual(name, BAD_CAST "node"))
10047 *type = NODE_TYPE_NODE;
10048 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10049 *type = NODE_TYPE_PI;
10050 else if (xmlStrEqual(name, BAD_CAST "text"))
10051 *type = NODE_TYPE_TEXT;
10052 else {
10053 if (name != NULL)
10054 xmlFree(name);
10055 XP_ERRORNULL(XPATH_EXPR_ERROR);
10056 }
10057
10058 *test = NODE_TEST_TYPE;
10059
10060 SKIP_BLANKS;
10061 if (*type == NODE_TYPE_PI) {
10062 /*
10063 * Specific case: search a PI by name.
10064 */
10065 if (name != NULL)
10066 xmlFree(name);
10067 name = NULL;
10068 if (CUR != ')') {
10069 name = xmlXPathParseLiteral(ctxt);
10070 *test = NODE_TEST_PI;
10071 SKIP_BLANKS;
10072 }
10073 }
10074 if (CUR != ')') {
10075 if (name != NULL)
10076 xmlFree(name);
10077 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10078 }
10079 NEXT;
10080 return(name);
10081 }
10082 *test = NODE_TEST_NAME;
10083 if ((!blanks) && (CUR == ':')) {
10084 NEXT;
10085
10086 /*
10087 * Since currently the parser context don't have a
10088 * namespace list associated:
10089 * The namespace name for this prefix can be computed
10090 * only at evaluation time. The compilation is done
10091 * outside of any context.
10092 */
10093 #if 0
10094 *prefix = xmlXPathNsLookup(ctxt->context, name);
10095 if (name != NULL)
10096 xmlFree(name);
10097 if (*prefix == NULL) {
10098 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10099 }
10100 #else
10101 *prefix = name;
10102 #endif
10103
10104 if (CUR == '*') {
10105 /*
10106 * All elements
10107 */
10108 NEXT;
10109 *test = NODE_TEST_ALL;
10110 return(NULL);
10111 }
10112
10113 name = xmlXPathParseNCName(ctxt);
10114 if (name == NULL) {
10115 XP_ERRORNULL(XPATH_EXPR_ERROR);
10116 }
10117 }
10118 return(name);
10119 }
10120
10121 /**
10122 * xmlXPathIsAxisName:
10123 * @name: a preparsed name token
10124 *
10125 * [6] AxisName ::= 'ancestor'
10126 * | 'ancestor-or-self'
10127 * | 'attribute'
10128 * | 'child'
10129 * | 'descendant'
10130 * | 'descendant-or-self'
10131 * | 'following'
10132 * | 'following-sibling'
10133 * | 'namespace'
10134 * | 'parent'
10135 * | 'preceding'
10136 * | 'preceding-sibling'
10137 * | 'self'
10138 *
10139 * Returns the axis or 0
10140 */
10141 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)10142 xmlXPathIsAxisName(const xmlChar *name) {
10143 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10144 switch (name[0]) {
10145 case 'a':
10146 if (xmlStrEqual(name, BAD_CAST "ancestor"))
10147 ret = AXIS_ANCESTOR;
10148 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10149 ret = AXIS_ANCESTOR_OR_SELF;
10150 if (xmlStrEqual(name, BAD_CAST "attribute"))
10151 ret = AXIS_ATTRIBUTE;
10152 break;
10153 case 'c':
10154 if (xmlStrEqual(name, BAD_CAST "child"))
10155 ret = AXIS_CHILD;
10156 break;
10157 case 'd':
10158 if (xmlStrEqual(name, BAD_CAST "descendant"))
10159 ret = AXIS_DESCENDANT;
10160 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10161 ret = AXIS_DESCENDANT_OR_SELF;
10162 break;
10163 case 'f':
10164 if (xmlStrEqual(name, BAD_CAST "following"))
10165 ret = AXIS_FOLLOWING;
10166 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10167 ret = AXIS_FOLLOWING_SIBLING;
10168 break;
10169 case 'n':
10170 if (xmlStrEqual(name, BAD_CAST "namespace"))
10171 ret = AXIS_NAMESPACE;
10172 break;
10173 case 'p':
10174 if (xmlStrEqual(name, BAD_CAST "parent"))
10175 ret = AXIS_PARENT;
10176 if (xmlStrEqual(name, BAD_CAST "preceding"))
10177 ret = AXIS_PRECEDING;
10178 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10179 ret = AXIS_PRECEDING_SIBLING;
10180 break;
10181 case 's':
10182 if (xmlStrEqual(name, BAD_CAST "self"))
10183 ret = AXIS_SELF;
10184 break;
10185 }
10186 return(ret);
10187 }
10188
10189 /**
10190 * xmlXPathCompStep:
10191 * @ctxt: the XPath Parser context
10192 *
10193 * [4] Step ::= AxisSpecifier NodeTest Predicate*
10194 * | AbbreviatedStep
10195 *
10196 * [12] AbbreviatedStep ::= '.' | '..'
10197 *
10198 * [5] AxisSpecifier ::= AxisName '::'
10199 * | AbbreviatedAxisSpecifier
10200 *
10201 * [13] AbbreviatedAxisSpecifier ::= '@'?
10202 *
10203 * Modified for XPtr range support as:
10204 *
10205 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10206 * | AbbreviatedStep
10207 * | 'range-to' '(' Expr ')' Predicate*
10208 *
10209 * Compile one step in a Location Path
10210 * A location step of . is short for self::node(). This is
10211 * particularly useful in conjunction with //. For example, the
10212 * location path .//para is short for
10213 * self::node()/descendant-or-self::node()/child::para
10214 * and so will select all para descendant elements of the context
10215 * node.
10216 * Similarly, a location step of .. is short for parent::node().
10217 * For example, ../title is short for parent::node()/child::title
10218 * and so will select the title children of the parent of the context
10219 * node.
10220 */
10221 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)10222 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10223 #ifdef LIBXML_XPTR_LOCS_ENABLED
10224 int rangeto = 0;
10225 int op2 = -1;
10226 #endif
10227
10228 SKIP_BLANKS;
10229 if ((CUR == '.') && (NXT(1) == '.')) {
10230 SKIP(2);
10231 SKIP_BLANKS;
10232 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10233 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10234 } else if (CUR == '.') {
10235 NEXT;
10236 SKIP_BLANKS;
10237 } else {
10238 xmlChar *name = NULL;
10239 xmlChar *prefix = NULL;
10240 xmlXPathTestVal test = (xmlXPathTestVal) 0;
10241 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10242 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10243 int op1;
10244
10245 /*
10246 * The modification needed for XPointer change to the production
10247 */
10248 #ifdef LIBXML_XPTR_LOCS_ENABLED
10249 if (ctxt->xptr) {
10250 name = xmlXPathParseNCName(ctxt);
10251 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10252 op2 = ctxt->comp->last;
10253 xmlFree(name);
10254 SKIP_BLANKS;
10255 if (CUR != '(') {
10256 XP_ERROR(XPATH_EXPR_ERROR);
10257 }
10258 NEXT;
10259 SKIP_BLANKS;
10260
10261 xmlXPathCompileExpr(ctxt, 1);
10262 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10263 CHECK_ERROR;
10264
10265 SKIP_BLANKS;
10266 if (CUR != ')') {
10267 XP_ERROR(XPATH_EXPR_ERROR);
10268 }
10269 NEXT;
10270 rangeto = 1;
10271 goto eval_predicates;
10272 }
10273 }
10274 #endif
10275 if (CUR == '*') {
10276 axis = AXIS_CHILD;
10277 } else {
10278 if (name == NULL)
10279 name = xmlXPathParseNCName(ctxt);
10280 if (name != NULL) {
10281 axis = xmlXPathIsAxisName(name);
10282 if (axis != 0) {
10283 SKIP_BLANKS;
10284 if ((CUR == ':') && (NXT(1) == ':')) {
10285 SKIP(2);
10286 xmlFree(name);
10287 name = NULL;
10288 } else {
10289 /* an element name can conflict with an axis one :-\ */
10290 axis = AXIS_CHILD;
10291 }
10292 } else {
10293 axis = AXIS_CHILD;
10294 }
10295 } else if (CUR == '@') {
10296 NEXT;
10297 axis = AXIS_ATTRIBUTE;
10298 } else {
10299 axis = AXIS_CHILD;
10300 }
10301 }
10302
10303 if (ctxt->error != XPATH_EXPRESSION_OK) {
10304 xmlFree(name);
10305 return;
10306 }
10307
10308 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10309 if (test == 0)
10310 return;
10311
10312 if ((prefix != NULL) && (ctxt->context != NULL) &&
10313 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10314 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10315 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10316 }
10317 }
10318
10319 #ifdef LIBXML_XPTR_LOCS_ENABLED
10320 eval_predicates:
10321 #endif
10322 op1 = ctxt->comp->last;
10323 ctxt->comp->last = -1;
10324
10325 SKIP_BLANKS;
10326 while (CUR == '[') {
10327 xmlXPathCompPredicate(ctxt, 0);
10328 }
10329
10330 #ifdef LIBXML_XPTR_LOCS_ENABLED
10331 if (rangeto) {
10332 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10333 } else
10334 #endif
10335 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10336 test, type, (void *)prefix, (void *)name) == -1) {
10337 xmlFree(prefix);
10338 xmlFree(name);
10339 }
10340 }
10341 }
10342
10343 /**
10344 * xmlXPathCompRelativeLocationPath:
10345 * @ctxt: the XPath Parser context
10346 *
10347 * [3] RelativeLocationPath ::= Step
10348 * | RelativeLocationPath '/' Step
10349 * | AbbreviatedRelativeLocationPath
10350 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
10351 *
10352 * Compile a relative location path.
10353 */
10354 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)10355 xmlXPathCompRelativeLocationPath
10356 (xmlXPathParserContextPtr ctxt) {
10357 SKIP_BLANKS;
10358 if ((CUR == '/') && (NXT(1) == '/')) {
10359 SKIP(2);
10360 SKIP_BLANKS;
10361 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10362 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10363 } else if (CUR == '/') {
10364 NEXT;
10365 SKIP_BLANKS;
10366 }
10367 xmlXPathCompStep(ctxt);
10368 CHECK_ERROR;
10369 SKIP_BLANKS;
10370 while (CUR == '/') {
10371 if ((CUR == '/') && (NXT(1) == '/')) {
10372 SKIP(2);
10373 SKIP_BLANKS;
10374 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10375 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10376 xmlXPathCompStep(ctxt);
10377 } else if (CUR == '/') {
10378 NEXT;
10379 SKIP_BLANKS;
10380 xmlXPathCompStep(ctxt);
10381 }
10382 SKIP_BLANKS;
10383 }
10384 }
10385
10386 /**
10387 * xmlXPathCompLocationPath:
10388 * @ctxt: the XPath Parser context
10389 *
10390 * [1] LocationPath ::= RelativeLocationPath
10391 * | AbsoluteLocationPath
10392 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
10393 * | AbbreviatedAbsoluteLocationPath
10394 * [10] AbbreviatedAbsoluteLocationPath ::=
10395 * '//' RelativeLocationPath
10396 *
10397 * Compile a location path
10398 *
10399 * // is short for /descendant-or-self::node()/. For example,
10400 * //para is short for /descendant-or-self::node()/child::para and
10401 * so will select any para element in the document (even a para element
10402 * that is a document element will be selected by //para since the
10403 * document element node is a child of the root node); div//para is
10404 * short for div/descendant-or-self::node()/child::para and so will
10405 * select all para descendants of div children.
10406 */
10407 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)10408 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10409 SKIP_BLANKS;
10410 if (CUR != '/') {
10411 xmlXPathCompRelativeLocationPath(ctxt);
10412 } else {
10413 while (CUR == '/') {
10414 if ((CUR == '/') && (NXT(1) == '/')) {
10415 SKIP(2);
10416 SKIP_BLANKS;
10417 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10418 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10419 xmlXPathCompRelativeLocationPath(ctxt);
10420 } else if (CUR == '/') {
10421 NEXT;
10422 SKIP_BLANKS;
10423 if ((CUR != 0 ) &&
10424 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10425 (CUR == '@') || (CUR == '*')))
10426 xmlXPathCompRelativeLocationPath(ctxt);
10427 }
10428 CHECK_ERROR;
10429 }
10430 }
10431 }
10432
10433 /************************************************************************
10434 * *
10435 * XPath precompiled expression evaluation *
10436 * *
10437 ************************************************************************/
10438
10439 static int
10440 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10441
10442 /**
10443 * xmlXPathNodeSetFilter:
10444 * @ctxt: the XPath Parser context
10445 * @set: the node set to filter
10446 * @filterOpIndex: the index of the predicate/filter op
10447 * @minPos: minimum position in the filtered set (1-based)
10448 * @maxPos: maximum position in the filtered set (1-based)
10449 * @hasNsNodes: true if the node set may contain namespace nodes
10450 *
10451 * Filter a node set, keeping only nodes for which the predicate expression
10452 * matches. Afterwards, keep only nodes between minPos and maxPos in the
10453 * filtered result.
10454 */
10455 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)10456 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10457 xmlNodeSetPtr set,
10458 int filterOpIndex,
10459 int minPos, int maxPos,
10460 int hasNsNodes)
10461 {
10462 xmlXPathContextPtr xpctxt;
10463 xmlNodePtr oldnode;
10464 xmlDocPtr olddoc;
10465 xmlXPathStepOpPtr filterOp;
10466 int oldcs, oldpp;
10467 int i, j, pos;
10468
10469 if ((set == NULL) || (set->nodeNr == 0))
10470 return;
10471
10472 /*
10473 * Check if the node set contains a sufficient number of nodes for
10474 * the requested range.
10475 */
10476 if (set->nodeNr < minPos) {
10477 xmlXPathNodeSetClear(set, hasNsNodes);
10478 return;
10479 }
10480
10481 xpctxt = ctxt->context;
10482 oldnode = xpctxt->node;
10483 olddoc = xpctxt->doc;
10484 oldcs = xpctxt->contextSize;
10485 oldpp = xpctxt->proximityPosition;
10486 filterOp = &ctxt->comp->steps[filterOpIndex];
10487
10488 xpctxt->contextSize = set->nodeNr;
10489
10490 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10491 xmlNodePtr node = set->nodeTab[i];
10492 int res;
10493
10494 xpctxt->node = node;
10495 xpctxt->proximityPosition = i + 1;
10496
10497 /*
10498 * Also set the xpath document in case things like
10499 * key() are evaluated in the predicate.
10500 *
10501 * TODO: Get real doc for namespace nodes.
10502 */
10503 if ((node->type != XML_NAMESPACE_DECL) &&
10504 (node->doc != NULL))
10505 xpctxt->doc = node->doc;
10506
10507 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10508
10509 if (ctxt->error != XPATH_EXPRESSION_OK)
10510 break;
10511 if (res < 0) {
10512 /* Shouldn't happen */
10513 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10514 break;
10515 }
10516
10517 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10518 if (i != j) {
10519 set->nodeTab[j] = node;
10520 set->nodeTab[i] = NULL;
10521 }
10522
10523 j += 1;
10524 } else {
10525 /* Remove the entry from the initial node set. */
10526 set->nodeTab[i] = NULL;
10527 if (node->type == XML_NAMESPACE_DECL)
10528 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10529 }
10530
10531 if (res != 0) {
10532 if (pos == maxPos) {
10533 i += 1;
10534 break;
10535 }
10536
10537 pos += 1;
10538 }
10539 }
10540
10541 /* Free remaining nodes. */
10542 if (hasNsNodes) {
10543 for (; i < set->nodeNr; i++) {
10544 xmlNodePtr node = set->nodeTab[i];
10545 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10546 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10547 }
10548 }
10549
10550 set->nodeNr = j;
10551
10552 /* If too many elements were removed, shrink table to preserve memory. */
10553 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10554 (set->nodeNr < set->nodeMax / 2)) {
10555 xmlNodePtr *tmp;
10556 int nodeMax = set->nodeNr;
10557
10558 if (nodeMax < XML_NODESET_DEFAULT)
10559 nodeMax = XML_NODESET_DEFAULT;
10560 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10561 nodeMax * sizeof(xmlNodePtr));
10562 if (tmp == NULL) {
10563 xmlXPathPErrMemory(ctxt);
10564 } else {
10565 set->nodeTab = tmp;
10566 set->nodeMax = nodeMax;
10567 }
10568 }
10569
10570 xpctxt->node = oldnode;
10571 xpctxt->doc = olddoc;
10572 xpctxt->contextSize = oldcs;
10573 xpctxt->proximityPosition = oldpp;
10574 }
10575
10576 #ifdef LIBXML_XPTR_LOCS_ENABLED
10577 /**
10578 * xmlXPathLocationSetFilter:
10579 * @ctxt: the XPath Parser context
10580 * @locset: the location set to filter
10581 * @filterOpIndex: the index of the predicate/filter op
10582 * @minPos: minimum position in the filtered set (1-based)
10583 * @maxPos: maximum position in the filtered set (1-based)
10584 *
10585 * Filter a location set, keeping only nodes for which the predicate
10586 * expression matches. Afterwards, keep only nodes between minPos and maxPos
10587 * in the filtered result.
10588 */
10589 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)10590 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
10591 xmlLocationSetPtr locset,
10592 int filterOpIndex,
10593 int minPos, int maxPos)
10594 {
10595 xmlXPathContextPtr xpctxt;
10596 xmlNodePtr oldnode;
10597 xmlDocPtr olddoc;
10598 xmlXPathStepOpPtr filterOp;
10599 int oldcs, oldpp;
10600 int i, j, pos;
10601
10602 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
10603 return;
10604
10605 xpctxt = ctxt->context;
10606 oldnode = xpctxt->node;
10607 olddoc = xpctxt->doc;
10608 oldcs = xpctxt->contextSize;
10609 oldpp = xpctxt->proximityPosition;
10610 filterOp = &ctxt->comp->steps[filterOpIndex];
10611
10612 xpctxt->contextSize = locset->locNr;
10613
10614 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
10615 xmlNodePtr contextNode = locset->locTab[i]->user;
10616 int res;
10617
10618 xpctxt->node = contextNode;
10619 xpctxt->proximityPosition = i + 1;
10620
10621 /*
10622 * Also set the xpath document in case things like
10623 * key() are evaluated in the predicate.
10624 *
10625 * TODO: Get real doc for namespace nodes.
10626 */
10627 if ((contextNode->type != XML_NAMESPACE_DECL) &&
10628 (contextNode->doc != NULL))
10629 xpctxt->doc = contextNode->doc;
10630
10631 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10632
10633 if (ctxt->error != XPATH_EXPRESSION_OK)
10634 break;
10635 if (res < 0) {
10636 /* Shouldn't happen */
10637 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10638 break;
10639 }
10640
10641 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10642 if (i != j) {
10643 locset->locTab[j] = locset->locTab[i];
10644 locset->locTab[i] = NULL;
10645 }
10646
10647 j += 1;
10648 } else {
10649 /* Remove the entry from the initial location set. */
10650 xmlXPathFreeObject(locset->locTab[i]);
10651 locset->locTab[i] = NULL;
10652 }
10653
10654 if (res != 0) {
10655 if (pos == maxPos) {
10656 i += 1;
10657 break;
10658 }
10659
10660 pos += 1;
10661 }
10662 }
10663
10664 /* Free remaining nodes. */
10665 for (; i < locset->locNr; i++)
10666 xmlXPathFreeObject(locset->locTab[i]);
10667
10668 locset->locNr = j;
10669
10670 /* If too many elements were removed, shrink table to preserve memory. */
10671 if ((locset->locMax > XML_NODESET_DEFAULT) &&
10672 (locset->locNr < locset->locMax / 2)) {
10673 xmlXPathObjectPtr *tmp;
10674 int locMax = locset->locNr;
10675
10676 if (locMax < XML_NODESET_DEFAULT)
10677 locMax = XML_NODESET_DEFAULT;
10678 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
10679 locMax * sizeof(xmlXPathObjectPtr));
10680 if (tmp == NULL) {
10681 xmlXPathPErrMemory(ctxt);
10682 } else {
10683 locset->locTab = tmp;
10684 locset->locMax = locMax;
10685 }
10686 }
10687
10688 xpctxt->node = oldnode;
10689 xpctxt->doc = olddoc;
10690 xpctxt->contextSize = oldcs;
10691 xpctxt->proximityPosition = oldpp;
10692 }
10693 #endif /* LIBXML_XPTR_LOCS_ENABLED */
10694
10695 /**
10696 * xmlXPathCompOpEvalPredicate:
10697 * @ctxt: the XPath Parser context
10698 * @op: the predicate op
10699 * @set: the node set to filter
10700 * @minPos: minimum position in the filtered set (1-based)
10701 * @maxPos: maximum position in the filtered set (1-based)
10702 * @hasNsNodes: true if the node set may contain namespace nodes
10703 *
10704 * Filter a node set, keeping only nodes for which the sequence of predicate
10705 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10706 * in the filtered result.
10707 */
10708 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)10709 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10710 xmlXPathStepOpPtr op,
10711 xmlNodeSetPtr set,
10712 int minPos, int maxPos,
10713 int hasNsNodes)
10714 {
10715 if (op->ch1 != -1) {
10716 xmlXPathCompExprPtr comp = ctxt->comp;
10717 /*
10718 * Process inner predicates first.
10719 */
10720 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10721 XP_ERROR(XPATH_INVALID_OPERAND);
10722 }
10723 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10724 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10725 ctxt->context->depth += 1;
10726 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10727 1, set->nodeNr, hasNsNodes);
10728 ctxt->context->depth -= 1;
10729 CHECK_ERROR;
10730 }
10731
10732 if (op->ch2 != -1)
10733 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10734 }
10735
10736 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)10737 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10738 xmlXPathStepOpPtr op,
10739 int *maxPos)
10740 {
10741
10742 xmlXPathStepOpPtr exprOp;
10743
10744 /*
10745 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10746 */
10747
10748 /*
10749 * If not -1, then ch1 will point to:
10750 * 1) For predicates (XPATH_OP_PREDICATE):
10751 * - an inner predicate operator
10752 * 2) For filters (XPATH_OP_FILTER):
10753 * - an inner filter operator OR
10754 * - an expression selecting the node set.
10755 * E.g. "key('a', 'b')" or "(//foo | //bar)".
10756 */
10757 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10758 return(0);
10759
10760 if (op->ch2 != -1) {
10761 exprOp = &ctxt->comp->steps[op->ch2];
10762 } else
10763 return(0);
10764
10765 if ((exprOp != NULL) &&
10766 (exprOp->op == XPATH_OP_VALUE) &&
10767 (exprOp->value4 != NULL) &&
10768 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10769 {
10770 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10771
10772 /*
10773 * We have a "[n]" predicate here.
10774 * TODO: Unfortunately this simplistic test here is not
10775 * able to detect a position() predicate in compound
10776 * expressions like "[@attr = 'a" and position() = 1],
10777 * and even not the usage of position() in
10778 * "[position() = 1]"; thus - obviously - a position-range,
10779 * like it "[position() < 5]", is also not detected.
10780 * Maybe we could rewrite the AST to ease the optimization.
10781 */
10782
10783 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10784 *maxPos = (int) floatval;
10785 if (floatval == (double) *maxPos)
10786 return(1);
10787 }
10788 }
10789 return(0);
10790 }
10791
10792 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)10793 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10794 xmlXPathStepOpPtr op,
10795 xmlNodePtr * first, xmlNodePtr * last,
10796 int toBool)
10797 {
10798
10799 #define XP_TEST_HIT \
10800 if (hasAxisRange != 0) { \
10801 if (++pos == maxPos) { \
10802 if (addNode(seq, cur) < 0) \
10803 xmlXPathPErrMemory(ctxt); \
10804 goto axis_range_end; } \
10805 } else { \
10806 if (addNode(seq, cur) < 0) \
10807 xmlXPathPErrMemory(ctxt); \
10808 if (breakOnFirstHit) goto first_hit; }
10809
10810 #define XP_TEST_HIT_NS \
10811 if (hasAxisRange != 0) { \
10812 if (++pos == maxPos) { \
10813 hasNsNodes = 1; \
10814 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10815 xmlXPathPErrMemory(ctxt); \
10816 goto axis_range_end; } \
10817 } else { \
10818 hasNsNodes = 1; \
10819 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10820 xmlXPathPErrMemory(ctxt); \
10821 if (breakOnFirstHit) goto first_hit; }
10822
10823 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10824 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10825 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10826 const xmlChar *prefix = op->value4;
10827 const xmlChar *name = op->value5;
10828 const xmlChar *URI = NULL;
10829
10830 int total = 0, hasNsNodes = 0;
10831 /* The popped object holding the context nodes */
10832 xmlXPathObjectPtr obj;
10833 /* The set of context nodes for the node tests */
10834 xmlNodeSetPtr contextSeq;
10835 int contextIdx;
10836 xmlNodePtr contextNode;
10837 /* The final resulting node set wrt to all context nodes */
10838 xmlNodeSetPtr outSeq;
10839 /*
10840 * The temporary resulting node set wrt 1 context node.
10841 * Used to feed predicate evaluation.
10842 */
10843 xmlNodeSetPtr seq;
10844 xmlNodePtr cur;
10845 /* First predicate operator */
10846 xmlXPathStepOpPtr predOp;
10847 int maxPos; /* The requested position() (when a "[n]" predicate) */
10848 int hasPredicateRange, hasAxisRange, pos;
10849 int breakOnFirstHit;
10850
10851 xmlXPathTraversalFunction next = NULL;
10852 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10853 xmlXPathNodeSetMergeFunction mergeAndClear;
10854 xmlNodePtr oldContextNode;
10855 xmlXPathContextPtr xpctxt = ctxt->context;
10856
10857
10858 CHECK_TYPE0(XPATH_NODESET);
10859 obj = valuePop(ctxt);
10860 /*
10861 * Setup namespaces.
10862 */
10863 if (prefix != NULL) {
10864 URI = xmlXPathNsLookup(xpctxt, prefix);
10865 if (URI == NULL) {
10866 xmlXPathReleaseObject(xpctxt, obj);
10867 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10868 }
10869 }
10870 /*
10871 * Setup axis.
10872 *
10873 * MAYBE FUTURE TODO: merging optimizations:
10874 * - If the nodes to be traversed wrt to the initial nodes and
10875 * the current axis cannot overlap, then we could avoid searching
10876 * for duplicates during the merge.
10877 * But the question is how/when to evaluate if they cannot overlap.
10878 * Example: if we know that for two initial nodes, the one is
10879 * not in the ancestor-or-self axis of the other, then we could safely
10880 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10881 * the descendant-or-self axis.
10882 */
10883 mergeAndClear = xmlXPathNodeSetMergeAndClear;
10884 switch (axis) {
10885 case AXIS_ANCESTOR:
10886 first = NULL;
10887 next = xmlXPathNextAncestor;
10888 break;
10889 case AXIS_ANCESTOR_OR_SELF:
10890 first = NULL;
10891 next = xmlXPathNextAncestorOrSelf;
10892 break;
10893 case AXIS_ATTRIBUTE:
10894 first = NULL;
10895 last = NULL;
10896 next = xmlXPathNextAttribute;
10897 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10898 break;
10899 case AXIS_CHILD:
10900 last = NULL;
10901 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10902 (type == NODE_TYPE_NODE))
10903 {
10904 /*
10905 * Optimization if an element node type is 'element'.
10906 */
10907 next = xmlXPathNextChildElement;
10908 } else
10909 next = xmlXPathNextChild;
10910 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10911 break;
10912 case AXIS_DESCENDANT:
10913 last = NULL;
10914 next = xmlXPathNextDescendant;
10915 break;
10916 case AXIS_DESCENDANT_OR_SELF:
10917 last = NULL;
10918 next = xmlXPathNextDescendantOrSelf;
10919 break;
10920 case AXIS_FOLLOWING:
10921 last = NULL;
10922 next = xmlXPathNextFollowing;
10923 break;
10924 case AXIS_FOLLOWING_SIBLING:
10925 last = NULL;
10926 next = xmlXPathNextFollowingSibling;
10927 break;
10928 case AXIS_NAMESPACE:
10929 first = NULL;
10930 last = NULL;
10931 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10932 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10933 break;
10934 case AXIS_PARENT:
10935 first = NULL;
10936 next = xmlXPathNextParent;
10937 break;
10938 case AXIS_PRECEDING:
10939 first = NULL;
10940 next = xmlXPathNextPrecedingInternal;
10941 break;
10942 case AXIS_PRECEDING_SIBLING:
10943 first = NULL;
10944 next = xmlXPathNextPrecedingSibling;
10945 break;
10946 case AXIS_SELF:
10947 first = NULL;
10948 last = NULL;
10949 next = xmlXPathNextSelf;
10950 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10951 break;
10952 }
10953
10954 if (next == NULL) {
10955 xmlXPathReleaseObject(xpctxt, obj);
10956 return(0);
10957 }
10958 contextSeq = obj->nodesetval;
10959 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10960 valuePush(ctxt, obj);
10961 return(0);
10962 }
10963 /*
10964 * Predicate optimization ---------------------------------------------
10965 * If this step has a last predicate, which contains a position(),
10966 * then we'll optimize (although not exactly "position()", but only
10967 * the short-hand form, i.e., "[n]".
10968 *
10969 * Example - expression "/foo[parent::bar][1]":
10970 *
10971 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
10972 * ROOT -- op->ch1
10973 * PREDICATE -- op->ch2 (predOp)
10974 * PREDICATE -- predOp->ch1 = [parent::bar]
10975 * SORT
10976 * COLLECT 'parent' 'name' 'node' bar
10977 * NODE
10978 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
10979 *
10980 */
10981 maxPos = 0;
10982 predOp = NULL;
10983 hasPredicateRange = 0;
10984 hasAxisRange = 0;
10985 if (op->ch2 != -1) {
10986 /*
10987 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
10988 */
10989 predOp = &ctxt->comp->steps[op->ch2];
10990 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
10991 if (predOp->ch1 != -1) {
10992 /*
10993 * Use the next inner predicate operator.
10994 */
10995 predOp = &ctxt->comp->steps[predOp->ch1];
10996 hasPredicateRange = 1;
10997 } else {
10998 /*
10999 * There's no other predicate than the [n] predicate.
11000 */
11001 predOp = NULL;
11002 hasAxisRange = 1;
11003 }
11004 }
11005 }
11006 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
11007 /*
11008 * Axis traversal -----------------------------------------------------
11009 */
11010 /*
11011 * 2.3 Node Tests
11012 * - For the attribute axis, the principal node type is attribute.
11013 * - For the namespace axis, the principal node type is namespace.
11014 * - For other axes, the principal node type is element.
11015 *
11016 * A node test * is true for any node of the
11017 * principal node type. For example, child::* will
11018 * select all element children of the context node
11019 */
11020 oldContextNode = xpctxt->node;
11021 addNode = xmlXPathNodeSetAddUnique;
11022 outSeq = NULL;
11023 seq = NULL;
11024 contextNode = NULL;
11025 contextIdx = 0;
11026
11027
11028 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
11029 (ctxt->error == XPATH_EXPRESSION_OK)) {
11030 xpctxt->node = contextSeq->nodeTab[contextIdx++];
11031
11032 if (seq == NULL) {
11033 seq = xmlXPathNodeSetCreate(NULL);
11034 if (seq == NULL) {
11035 xmlXPathPErrMemory(ctxt);
11036 total = 0;
11037 goto error;
11038 }
11039 }
11040 /*
11041 * Traverse the axis and test the nodes.
11042 */
11043 pos = 0;
11044 cur = NULL;
11045 hasNsNodes = 0;
11046 do {
11047 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11048 goto error;
11049
11050 cur = next(ctxt, cur);
11051 if (cur == NULL)
11052 break;
11053
11054 /*
11055 * QUESTION TODO: What does the "first" and "last" stuff do?
11056 */
11057 if ((first != NULL) && (*first != NULL)) {
11058 if (*first == cur)
11059 break;
11060 if (((total % 256) == 0) &&
11061 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11062 (xmlXPathCmpNodesExt(*first, cur) >= 0))
11063 #else
11064 (xmlXPathCmpNodes(*first, cur) >= 0))
11065 #endif
11066 {
11067 break;
11068 }
11069 }
11070 if ((last != NULL) && (*last != NULL)) {
11071 if (*last == cur)
11072 break;
11073 if (((total % 256) == 0) &&
11074 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11075 (xmlXPathCmpNodesExt(cur, *last) >= 0))
11076 #else
11077 (xmlXPathCmpNodes(cur, *last) >= 0))
11078 #endif
11079 {
11080 break;
11081 }
11082 }
11083
11084 total++;
11085
11086 switch (test) {
11087 case NODE_TEST_NONE:
11088 total = 0;
11089 goto error;
11090 case NODE_TEST_TYPE:
11091 if (type == NODE_TYPE_NODE) {
11092 switch (cur->type) {
11093 case XML_DOCUMENT_NODE:
11094 case XML_HTML_DOCUMENT_NODE:
11095 case XML_ELEMENT_NODE:
11096 case XML_ATTRIBUTE_NODE:
11097 case XML_PI_NODE:
11098 case XML_COMMENT_NODE:
11099 case XML_CDATA_SECTION_NODE:
11100 case XML_TEXT_NODE:
11101 XP_TEST_HIT
11102 break;
11103 case XML_NAMESPACE_DECL: {
11104 if (axis == AXIS_NAMESPACE) {
11105 XP_TEST_HIT_NS
11106 } else {
11107 hasNsNodes = 1;
11108 XP_TEST_HIT
11109 }
11110 break;
11111 }
11112 default:
11113 break;
11114 }
11115 } else if (cur->type == (xmlElementType) type) {
11116 if (cur->type == XML_NAMESPACE_DECL)
11117 XP_TEST_HIT_NS
11118 else
11119 XP_TEST_HIT
11120 } else if ((type == NODE_TYPE_TEXT) &&
11121 (cur->type == XML_CDATA_SECTION_NODE))
11122 {
11123 XP_TEST_HIT
11124 }
11125 break;
11126 case NODE_TEST_PI:
11127 if ((cur->type == XML_PI_NODE) &&
11128 ((name == NULL) || xmlStrEqual(name, cur->name)))
11129 {
11130 XP_TEST_HIT
11131 }
11132 break;
11133 case NODE_TEST_ALL:
11134 if (axis == AXIS_ATTRIBUTE) {
11135 if (cur->type == XML_ATTRIBUTE_NODE)
11136 {
11137 if (prefix == NULL)
11138 {
11139 XP_TEST_HIT
11140 } else if ((cur->ns != NULL) &&
11141 (xmlStrEqual(URI, cur->ns->href)))
11142 {
11143 XP_TEST_HIT
11144 }
11145 }
11146 } else if (axis == AXIS_NAMESPACE) {
11147 if (cur->type == XML_NAMESPACE_DECL)
11148 {
11149 XP_TEST_HIT_NS
11150 }
11151 } else {
11152 if (cur->type == XML_ELEMENT_NODE) {
11153 if (prefix == NULL)
11154 {
11155 XP_TEST_HIT
11156
11157 } else if ((cur->ns != NULL) &&
11158 (xmlStrEqual(URI, cur->ns->href)))
11159 {
11160 XP_TEST_HIT
11161 }
11162 }
11163 }
11164 break;
11165 case NODE_TEST_NS:{
11166 /* TODO */
11167 break;
11168 }
11169 case NODE_TEST_NAME:
11170 if (axis == AXIS_ATTRIBUTE) {
11171 if (cur->type != XML_ATTRIBUTE_NODE)
11172 break;
11173 } else if (axis == AXIS_NAMESPACE) {
11174 if (cur->type != XML_NAMESPACE_DECL)
11175 break;
11176 } else {
11177 if (cur->type != XML_ELEMENT_NODE)
11178 break;
11179 }
11180 switch (cur->type) {
11181 case XML_ELEMENT_NODE:
11182 if (xmlStrEqual(name, cur->name)) {
11183 if (prefix == NULL) {
11184 if (cur->ns == NULL)
11185 {
11186 XP_TEST_HIT
11187 }
11188 } else {
11189 if ((cur->ns != NULL) &&
11190 (xmlStrEqual(URI, cur->ns->href)))
11191 {
11192 XP_TEST_HIT
11193 }
11194 }
11195 }
11196 break;
11197 case XML_ATTRIBUTE_NODE:{
11198 xmlAttrPtr attr = (xmlAttrPtr) cur;
11199
11200 if (xmlStrEqual(name, attr->name)) {
11201 if (prefix == NULL) {
11202 if ((attr->ns == NULL) ||
11203 (attr->ns->prefix == NULL))
11204 {
11205 XP_TEST_HIT
11206 }
11207 } else {
11208 if ((attr->ns != NULL) &&
11209 (xmlStrEqual(URI,
11210 attr->ns->href)))
11211 {
11212 XP_TEST_HIT
11213 }
11214 }
11215 }
11216 break;
11217 }
11218 case XML_NAMESPACE_DECL:
11219 if (cur->type == XML_NAMESPACE_DECL) {
11220 xmlNsPtr ns = (xmlNsPtr) cur;
11221
11222 if ((ns->prefix != NULL) && (name != NULL)
11223 && (xmlStrEqual(ns->prefix, name)))
11224 {
11225 XP_TEST_HIT_NS
11226 }
11227 }
11228 break;
11229 default:
11230 break;
11231 }
11232 break;
11233 } /* switch(test) */
11234 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
11235
11236 goto apply_predicates;
11237
11238 axis_range_end: /* ----------------------------------------------------- */
11239 /*
11240 * We have a "/foo[n]", and position() = n was reached.
11241 * Note that we can have as well "/foo/::parent::foo[1]", so
11242 * a duplicate-aware merge is still needed.
11243 * Merge with the result.
11244 */
11245 if (outSeq == NULL) {
11246 outSeq = seq;
11247 seq = NULL;
11248 } else {
11249 outSeq = mergeAndClear(outSeq, seq);
11250 if (outSeq == NULL)
11251 xmlXPathPErrMemory(ctxt);
11252 }
11253 /*
11254 * Break if only a true/false result was requested.
11255 */
11256 if (toBool)
11257 break;
11258 continue;
11259
11260 first_hit: /* ---------------------------------------------------------- */
11261 /*
11262 * Break if only a true/false result was requested and
11263 * no predicates existed and a node test succeeded.
11264 */
11265 if (outSeq == NULL) {
11266 outSeq = seq;
11267 seq = NULL;
11268 } else {
11269 outSeq = mergeAndClear(outSeq, seq);
11270 if (outSeq == NULL)
11271 xmlXPathPErrMemory(ctxt);
11272 }
11273 break;
11274
11275 apply_predicates: /* --------------------------------------------------- */
11276 if (ctxt->error != XPATH_EXPRESSION_OK)
11277 goto error;
11278
11279 /*
11280 * Apply predicates.
11281 */
11282 if ((predOp != NULL) && (seq->nodeNr > 0)) {
11283 /*
11284 * E.g. when we have a "/foo[some expression][n]".
11285 */
11286 /*
11287 * QUESTION TODO: The old predicate evaluation took into
11288 * account location-sets.
11289 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
11290 * Do we expect such a set here?
11291 * All what I learned now from the evaluation semantics
11292 * does not indicate that a location-set will be processed
11293 * here, so this looks OK.
11294 */
11295 /*
11296 * Iterate over all predicates, starting with the outermost
11297 * predicate.
11298 * TODO: Problem: we cannot execute the inner predicates first
11299 * since we cannot go back *up* the operator tree!
11300 * Options we have:
11301 * 1) Use of recursive functions (like is it currently done
11302 * via xmlXPathCompOpEval())
11303 * 2) Add a predicate evaluation information stack to the
11304 * context struct
11305 * 3) Change the way the operators are linked; we need a
11306 * "parent" field on xmlXPathStepOp
11307 *
11308 * For the moment, I'll try to solve this with a recursive
11309 * function: xmlXPathCompOpEvalPredicate().
11310 */
11311 if (hasPredicateRange != 0)
11312 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11313 hasNsNodes);
11314 else
11315 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11316 hasNsNodes);
11317
11318 if (ctxt->error != XPATH_EXPRESSION_OK) {
11319 total = 0;
11320 goto error;
11321 }
11322 }
11323
11324 if (seq->nodeNr > 0) {
11325 /*
11326 * Add to result set.
11327 */
11328 if (outSeq == NULL) {
11329 outSeq = seq;
11330 seq = NULL;
11331 } else {
11332 outSeq = mergeAndClear(outSeq, seq);
11333 if (outSeq == NULL)
11334 xmlXPathPErrMemory(ctxt);
11335 }
11336
11337 if (toBool)
11338 break;
11339 }
11340 }
11341
11342 error:
11343 if ((obj->boolval) && (obj->user != NULL)) {
11344 /*
11345 * QUESTION TODO: What does this do and why?
11346 * TODO: Do we have to do this also for the "error"
11347 * cleanup further down?
11348 */
11349 ctxt->value->boolval = 1;
11350 ctxt->value->user = obj->user;
11351 obj->user = NULL;
11352 obj->boolval = 0;
11353 }
11354 xmlXPathReleaseObject(xpctxt, obj);
11355
11356 /*
11357 * Ensure we return at least an empty set.
11358 */
11359 if (outSeq == NULL) {
11360 if ((seq != NULL) && (seq->nodeNr == 0)) {
11361 outSeq = seq;
11362 } else {
11363 outSeq = xmlXPathNodeSetCreate(NULL);
11364 if (outSeq == NULL)
11365 xmlXPathPErrMemory(ctxt);
11366 }
11367 }
11368 if ((seq != NULL) && (seq != outSeq)) {
11369 xmlXPathFreeNodeSet(seq);
11370 }
11371 /*
11372 * Hand over the result. Better to push the set also in
11373 * case of errors.
11374 */
11375 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
11376 /*
11377 * Reset the context node.
11378 */
11379 xpctxt->node = oldContextNode;
11380 /*
11381 * When traversing the namespace axis in "toBool" mode, it's
11382 * possible that tmpNsList wasn't freed.
11383 */
11384 if (xpctxt->tmpNsList != NULL) {
11385 xmlFree(xpctxt->tmpNsList);
11386 xpctxt->tmpNsList = NULL;
11387 }
11388
11389 return(total);
11390 }
11391
11392 static int
11393 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11394 xmlXPathStepOpPtr op, xmlNodePtr * first);
11395
11396 /**
11397 * xmlXPathCompOpEvalFirst:
11398 * @ctxt: the XPath parser context with the compiled expression
11399 * @op: an XPath compiled operation
11400 * @first: the first elem found so far
11401 *
11402 * Evaluate the Precompiled XPath operation searching only the first
11403 * element in document order
11404 *
11405 * Returns the number of examined objects.
11406 */
11407 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11408 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11409 xmlXPathStepOpPtr op, xmlNodePtr * first)
11410 {
11411 int total = 0, cur;
11412 xmlXPathCompExprPtr comp;
11413 xmlXPathObjectPtr arg1, arg2;
11414
11415 CHECK_ERROR0;
11416 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11417 return(0);
11418 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11419 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11420 ctxt->context->depth += 1;
11421 comp = ctxt->comp;
11422 switch (op->op) {
11423 case XPATH_OP_END:
11424 break;
11425 case XPATH_OP_UNION:
11426 total =
11427 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11428 first);
11429 CHECK_ERROR0;
11430 if ((ctxt->value != NULL)
11431 && (ctxt->value->type == XPATH_NODESET)
11432 && (ctxt->value->nodesetval != NULL)
11433 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11434 /*
11435 * limit tree traversing to first node in the result
11436 */
11437 /*
11438 * OPTIMIZE TODO: This implicitly sorts
11439 * the result, even if not needed. E.g. if the argument
11440 * of the count() function, no sorting is needed.
11441 * OPTIMIZE TODO: How do we know if the node-list wasn't
11442 * already sorted?
11443 */
11444 if (ctxt->value->nodesetval->nodeNr > 1)
11445 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11446 *first = ctxt->value->nodesetval->nodeTab[0];
11447 }
11448 cur =
11449 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11450 first);
11451 CHECK_ERROR0;
11452
11453 arg2 = valuePop(ctxt);
11454 arg1 = valuePop(ctxt);
11455 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11456 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11457 xmlXPathReleaseObject(ctxt->context, arg1);
11458 xmlXPathReleaseObject(ctxt->context, arg2);
11459 XP_ERROR0(XPATH_INVALID_TYPE);
11460 }
11461 if ((ctxt->context->opLimit != 0) &&
11462 (((arg1->nodesetval != NULL) &&
11463 (xmlXPathCheckOpLimit(ctxt,
11464 arg1->nodesetval->nodeNr) < 0)) ||
11465 ((arg2->nodesetval != NULL) &&
11466 (xmlXPathCheckOpLimit(ctxt,
11467 arg2->nodesetval->nodeNr) < 0)))) {
11468 xmlXPathReleaseObject(ctxt->context, arg1);
11469 xmlXPathReleaseObject(ctxt->context, arg2);
11470 break;
11471 }
11472
11473 if ((arg2->nodesetval != NULL) &&
11474 (arg2->nodesetval->nodeNr != 0)) {
11475 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11476 arg2->nodesetval);
11477 if (arg1->nodesetval == NULL)
11478 xmlXPathPErrMemory(ctxt);
11479 }
11480 valuePush(ctxt, arg1);
11481 xmlXPathReleaseObject(ctxt->context, arg2);
11482 /* optimizer */
11483 if (total > cur)
11484 xmlXPathCompSwap(op);
11485 total += cur;
11486 break;
11487 case XPATH_OP_ROOT:
11488 xmlXPathRoot(ctxt);
11489 break;
11490 case XPATH_OP_NODE:
11491 if (op->ch1 != -1)
11492 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11493 CHECK_ERROR0;
11494 if (op->ch2 != -1)
11495 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11496 CHECK_ERROR0;
11497 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11498 ctxt->context->node));
11499 break;
11500 case XPATH_OP_COLLECT:{
11501 if (op->ch1 == -1)
11502 break;
11503
11504 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11505 CHECK_ERROR0;
11506
11507 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11508 break;
11509 }
11510 case XPATH_OP_VALUE:
11511 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11512 break;
11513 case XPATH_OP_SORT:
11514 if (op->ch1 != -1)
11515 total +=
11516 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11517 first);
11518 CHECK_ERROR0;
11519 if ((ctxt->value != NULL)
11520 && (ctxt->value->type == XPATH_NODESET)
11521 && (ctxt->value->nodesetval != NULL)
11522 && (ctxt->value->nodesetval->nodeNr > 1))
11523 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11524 break;
11525 #ifdef XP_OPTIMIZED_FILTER_FIRST
11526 case XPATH_OP_FILTER:
11527 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11528 break;
11529 #endif
11530 default:
11531 total += xmlXPathCompOpEval(ctxt, op);
11532 break;
11533 }
11534
11535 ctxt->context->depth -= 1;
11536 return(total);
11537 }
11538
11539 /**
11540 * xmlXPathCompOpEvalLast:
11541 * @ctxt: the XPath parser context with the compiled expression
11542 * @op: an XPath compiled operation
11543 * @last: the last elem found so far
11544 *
11545 * Evaluate the Precompiled XPath operation searching only the last
11546 * element in document order
11547 *
11548 * Returns the number of nodes traversed
11549 */
11550 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)11551 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11552 xmlNodePtr * last)
11553 {
11554 int total = 0, cur;
11555 xmlXPathCompExprPtr comp;
11556 xmlXPathObjectPtr arg1, arg2;
11557
11558 CHECK_ERROR0;
11559 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11560 return(0);
11561 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11562 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11563 ctxt->context->depth += 1;
11564 comp = ctxt->comp;
11565 switch (op->op) {
11566 case XPATH_OP_END:
11567 break;
11568 case XPATH_OP_UNION:
11569 total =
11570 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11571 CHECK_ERROR0;
11572 if ((ctxt->value != NULL)
11573 && (ctxt->value->type == XPATH_NODESET)
11574 && (ctxt->value->nodesetval != NULL)
11575 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11576 /*
11577 * limit tree traversing to first node in the result
11578 */
11579 if (ctxt->value->nodesetval->nodeNr > 1)
11580 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11581 *last =
11582 ctxt->value->nodesetval->nodeTab[ctxt->value->
11583 nodesetval->nodeNr -
11584 1];
11585 }
11586 cur =
11587 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11588 CHECK_ERROR0;
11589 if ((ctxt->value != NULL)
11590 && (ctxt->value->type == XPATH_NODESET)
11591 && (ctxt->value->nodesetval != NULL)
11592 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11593 }
11594
11595 arg2 = valuePop(ctxt);
11596 arg1 = valuePop(ctxt);
11597 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11598 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11599 xmlXPathReleaseObject(ctxt->context, arg1);
11600 xmlXPathReleaseObject(ctxt->context, arg2);
11601 XP_ERROR0(XPATH_INVALID_TYPE);
11602 }
11603 if ((ctxt->context->opLimit != 0) &&
11604 (((arg1->nodesetval != NULL) &&
11605 (xmlXPathCheckOpLimit(ctxt,
11606 arg1->nodesetval->nodeNr) < 0)) ||
11607 ((arg2->nodesetval != NULL) &&
11608 (xmlXPathCheckOpLimit(ctxt,
11609 arg2->nodesetval->nodeNr) < 0)))) {
11610 xmlXPathReleaseObject(ctxt->context, arg1);
11611 xmlXPathReleaseObject(ctxt->context, arg2);
11612 break;
11613 }
11614
11615 if ((arg2->nodesetval != NULL) &&
11616 (arg2->nodesetval->nodeNr != 0)) {
11617 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11618 arg2->nodesetval);
11619 if (arg1->nodesetval == NULL)
11620 xmlXPathPErrMemory(ctxt);
11621 }
11622 valuePush(ctxt, arg1);
11623 xmlXPathReleaseObject(ctxt->context, arg2);
11624 /* optimizer */
11625 if (total > cur)
11626 xmlXPathCompSwap(op);
11627 total += cur;
11628 break;
11629 case XPATH_OP_ROOT:
11630 xmlXPathRoot(ctxt);
11631 break;
11632 case XPATH_OP_NODE:
11633 if (op->ch1 != -1)
11634 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11635 CHECK_ERROR0;
11636 if (op->ch2 != -1)
11637 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11638 CHECK_ERROR0;
11639 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11640 ctxt->context->node));
11641 break;
11642 case XPATH_OP_COLLECT:{
11643 if (op->ch1 == -1)
11644 break;
11645
11646 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11647 CHECK_ERROR0;
11648
11649 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11650 break;
11651 }
11652 case XPATH_OP_VALUE:
11653 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11654 break;
11655 case XPATH_OP_SORT:
11656 if (op->ch1 != -1)
11657 total +=
11658 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11659 last);
11660 CHECK_ERROR0;
11661 if ((ctxt->value != NULL)
11662 && (ctxt->value->type == XPATH_NODESET)
11663 && (ctxt->value->nodesetval != NULL)
11664 && (ctxt->value->nodesetval->nodeNr > 1))
11665 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11666 break;
11667 default:
11668 total += xmlXPathCompOpEval(ctxt, op);
11669 break;
11670 }
11671
11672 ctxt->context->depth -= 1;
11673 return (total);
11674 }
11675
11676 #ifdef XP_OPTIMIZED_FILTER_FIRST
11677 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)11678 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11679 xmlXPathStepOpPtr op, xmlNodePtr * first)
11680 {
11681 int total = 0;
11682 xmlXPathCompExprPtr comp;
11683 xmlXPathObjectPtr obj;
11684 xmlNodeSetPtr set;
11685
11686 CHECK_ERROR0;
11687 comp = ctxt->comp;
11688 /*
11689 * Optimization for ()[last()] selection i.e. the last elem
11690 */
11691 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11692 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11693 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11694 int f = comp->steps[op->ch2].ch1;
11695
11696 if ((f != -1) &&
11697 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11698 (comp->steps[f].value5 == NULL) &&
11699 (comp->steps[f].value == 0) &&
11700 (comp->steps[f].value4 != NULL) &&
11701 (xmlStrEqual
11702 (comp->steps[f].value4, BAD_CAST "last"))) {
11703 xmlNodePtr last = NULL;
11704
11705 total +=
11706 xmlXPathCompOpEvalLast(ctxt,
11707 &comp->steps[op->ch1],
11708 &last);
11709 CHECK_ERROR0;
11710 /*
11711 * The nodeset should be in document order,
11712 * Keep only the last value
11713 */
11714 if ((ctxt->value != NULL) &&
11715 (ctxt->value->type == XPATH_NODESET) &&
11716 (ctxt->value->nodesetval != NULL) &&
11717 (ctxt->value->nodesetval->nodeTab != NULL) &&
11718 (ctxt->value->nodesetval->nodeNr > 1)) {
11719 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11720 *first = *(ctxt->value->nodesetval->nodeTab);
11721 }
11722 return (total);
11723 }
11724 }
11725
11726 if (op->ch1 != -1)
11727 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11728 CHECK_ERROR0;
11729 if (op->ch2 == -1)
11730 return (total);
11731 if (ctxt->value == NULL)
11732 return (total);
11733
11734 #ifdef LIBXML_XPTR_LOCS_ENABLED
11735 /*
11736 * Hum are we filtering the result of an XPointer expression
11737 */
11738 if (ctxt->value->type == XPATH_LOCATIONSET) {
11739 xmlLocationSetPtr locset = ctxt->value->user;
11740
11741 if (locset != NULL) {
11742 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
11743 if (locset->locNr > 0)
11744 *first = (xmlNodePtr) locset->locTab[0]->user;
11745 }
11746
11747 return (total);
11748 }
11749 #endif /* LIBXML_XPTR_LOCS_ENABLED */
11750
11751 /*
11752 * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11753 * the stack. We have to temporarily remove the nodeset object from the
11754 * stack to avoid freeing it prematurely.
11755 */
11756 CHECK_TYPE0(XPATH_NODESET);
11757 obj = valuePop(ctxt);
11758 set = obj->nodesetval;
11759 if (set != NULL) {
11760 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11761 if (set->nodeNr > 0)
11762 *first = set->nodeTab[0];
11763 }
11764 valuePush(ctxt, obj);
11765
11766 return (total);
11767 }
11768 #endif /* XP_OPTIMIZED_FILTER_FIRST */
11769
11770 /**
11771 * xmlXPathCompOpEval:
11772 * @ctxt: the XPath parser context with the compiled expression
11773 * @op: an XPath compiled operation
11774 *
11775 * Evaluate the Precompiled XPath operation
11776 * Returns the number of nodes traversed
11777 */
11778 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)11779 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11780 {
11781 int total = 0;
11782 int equal, ret;
11783 xmlXPathCompExprPtr comp;
11784 xmlXPathObjectPtr arg1, arg2;
11785
11786 CHECK_ERROR0;
11787 if (OP_LIMIT_EXCEEDED(ctxt, 1))
11788 return(0);
11789 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11790 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11791 ctxt->context->depth += 1;
11792 comp = ctxt->comp;
11793 switch (op->op) {
11794 case XPATH_OP_END:
11795 break;
11796 case XPATH_OP_AND:
11797 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11798 CHECK_ERROR0;
11799 xmlXPathBooleanFunction(ctxt, 1);
11800 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11801 break;
11802 arg2 = valuePop(ctxt);
11803 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11804 if (ctxt->error) {
11805 xmlXPathFreeObject(arg2);
11806 break;
11807 }
11808 xmlXPathBooleanFunction(ctxt, 1);
11809 if (ctxt->value != NULL)
11810 ctxt->value->boolval &= arg2->boolval;
11811 xmlXPathReleaseObject(ctxt->context, arg2);
11812 break;
11813 case XPATH_OP_OR:
11814 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11815 CHECK_ERROR0;
11816 xmlXPathBooleanFunction(ctxt, 1);
11817 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11818 break;
11819 arg2 = valuePop(ctxt);
11820 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11821 if (ctxt->error) {
11822 xmlXPathFreeObject(arg2);
11823 break;
11824 }
11825 xmlXPathBooleanFunction(ctxt, 1);
11826 if (ctxt->value != NULL)
11827 ctxt->value->boolval |= arg2->boolval;
11828 xmlXPathReleaseObject(ctxt->context, arg2);
11829 break;
11830 case XPATH_OP_EQUAL:
11831 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11832 CHECK_ERROR0;
11833 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11834 CHECK_ERROR0;
11835 if (op->value)
11836 equal = xmlXPathEqualValues(ctxt);
11837 else
11838 equal = xmlXPathNotEqualValues(ctxt);
11839 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11840 break;
11841 case XPATH_OP_CMP:
11842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11843 CHECK_ERROR0;
11844 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11845 CHECK_ERROR0;
11846 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11847 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11848 break;
11849 case XPATH_OP_PLUS:
11850 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11851 CHECK_ERROR0;
11852 if (op->ch2 != -1) {
11853 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11854 }
11855 CHECK_ERROR0;
11856 if (op->value == 0)
11857 xmlXPathSubValues(ctxt);
11858 else if (op->value == 1)
11859 xmlXPathAddValues(ctxt);
11860 else if (op->value == 2)
11861 xmlXPathValueFlipSign(ctxt);
11862 else if (op->value == 3) {
11863 CAST_TO_NUMBER;
11864 CHECK_TYPE0(XPATH_NUMBER);
11865 }
11866 break;
11867 case XPATH_OP_MULT:
11868 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11869 CHECK_ERROR0;
11870 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11871 CHECK_ERROR0;
11872 if (op->value == 0)
11873 xmlXPathMultValues(ctxt);
11874 else if (op->value == 1)
11875 xmlXPathDivValues(ctxt);
11876 else if (op->value == 2)
11877 xmlXPathModValues(ctxt);
11878 break;
11879 case XPATH_OP_UNION:
11880 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11881 CHECK_ERROR0;
11882 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11883 CHECK_ERROR0;
11884
11885 arg2 = valuePop(ctxt);
11886 arg1 = valuePop(ctxt);
11887 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11888 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11889 xmlXPathReleaseObject(ctxt->context, arg1);
11890 xmlXPathReleaseObject(ctxt->context, arg2);
11891 XP_ERROR0(XPATH_INVALID_TYPE);
11892 }
11893 if ((ctxt->context->opLimit != 0) &&
11894 (((arg1->nodesetval != NULL) &&
11895 (xmlXPathCheckOpLimit(ctxt,
11896 arg1->nodesetval->nodeNr) < 0)) ||
11897 ((arg2->nodesetval != NULL) &&
11898 (xmlXPathCheckOpLimit(ctxt,
11899 arg2->nodesetval->nodeNr) < 0)))) {
11900 xmlXPathReleaseObject(ctxt->context, arg1);
11901 xmlXPathReleaseObject(ctxt->context, arg2);
11902 break;
11903 }
11904
11905 if (((arg2->nodesetval != NULL) &&
11906 (arg2->nodesetval->nodeNr != 0)))
11907 {
11908 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11909 arg2->nodesetval);
11910 if (arg1->nodesetval == NULL)
11911 xmlXPathPErrMemory(ctxt);
11912 }
11913
11914 valuePush(ctxt, arg1);
11915 xmlXPathReleaseObject(ctxt->context, arg2);
11916 break;
11917 case XPATH_OP_ROOT:
11918 xmlXPathRoot(ctxt);
11919 break;
11920 case XPATH_OP_NODE:
11921 if (op->ch1 != -1)
11922 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11923 CHECK_ERROR0;
11924 if (op->ch2 != -1)
11925 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11926 CHECK_ERROR0;
11927 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11928 ctxt->context->node));
11929 break;
11930 case XPATH_OP_COLLECT:{
11931 if (op->ch1 == -1)
11932 break;
11933
11934 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11935 CHECK_ERROR0;
11936
11937 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11938 break;
11939 }
11940 case XPATH_OP_VALUE:
11941 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11942 break;
11943 case XPATH_OP_VARIABLE:{
11944 xmlXPathObjectPtr val;
11945
11946 if (op->ch1 != -1)
11947 total +=
11948 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11949 if (op->value5 == NULL) {
11950 val = xmlXPathVariableLookup(ctxt->context, op->value4);
11951 if (val == NULL)
11952 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11953 valuePush(ctxt, val);
11954 } else {
11955 const xmlChar *URI;
11956
11957 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11958 if (URI == NULL) {
11959 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11960 break;
11961 }
11962 val = xmlXPathVariableLookupNS(ctxt->context,
11963 op->value4, URI);
11964 if (val == NULL)
11965 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11966 valuePush(ctxt, val);
11967 }
11968 break;
11969 }
11970 case XPATH_OP_FUNCTION:{
11971 xmlXPathFunction func;
11972 const xmlChar *oldFunc, *oldFuncURI;
11973 int i;
11974 int frame;
11975
11976 frame = ctxt->valueNr;
11977 if (op->ch1 != -1) {
11978 total +=
11979 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11980 if (ctxt->error != XPATH_EXPRESSION_OK)
11981 break;
11982 }
11983 if (ctxt->valueNr < frame + op->value)
11984 XP_ERROR0(XPATH_INVALID_OPERAND);
11985 for (i = 0; i < op->value; i++) {
11986 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
11987 XP_ERROR0(XPATH_INVALID_OPERAND);
11988 }
11989 if (op->cache != NULL)
11990 func = op->cache;
11991 else {
11992 const xmlChar *URI = NULL;
11993
11994 if (op->value5 == NULL)
11995 func =
11996 xmlXPathFunctionLookup(ctxt->context,
11997 op->value4);
11998 else {
11999 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12000 if (URI == NULL)
12001 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12002 func = xmlXPathFunctionLookupNS(ctxt->context,
12003 op->value4, URI);
12004 }
12005 if (func == NULL)
12006 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
12007 op->cache = func;
12008 op->cacheURI = (void *) URI;
12009 }
12010 oldFunc = ctxt->context->function;
12011 oldFuncURI = ctxt->context->functionURI;
12012 ctxt->context->function = op->value4;
12013 ctxt->context->functionURI = op->cacheURI;
12014 func(ctxt, op->value);
12015 ctxt->context->function = oldFunc;
12016 ctxt->context->functionURI = oldFuncURI;
12017 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
12018 (ctxt->valueNr != frame + 1))
12019 XP_ERROR0(XPATH_STACK_ERROR);
12020 break;
12021 }
12022 case XPATH_OP_ARG:
12023 if (op->ch1 != -1) {
12024 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12025 CHECK_ERROR0;
12026 }
12027 if (op->ch2 != -1) {
12028 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12029 CHECK_ERROR0;
12030 }
12031 break;
12032 case XPATH_OP_PREDICATE:
12033 case XPATH_OP_FILTER:{
12034 xmlXPathObjectPtr obj;
12035 xmlNodeSetPtr set;
12036
12037 /*
12038 * Optimization for ()[1] selection i.e. the first elem
12039 */
12040 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12041 #ifdef XP_OPTIMIZED_FILTER_FIRST
12042 /*
12043 * FILTER TODO: Can we assume that the inner processing
12044 * will result in an ordered list if we have an
12045 * XPATH_OP_FILTER?
12046 * What about an additional field or flag on
12047 * xmlXPathObject like @sorted ? This way we wouldn't need
12048 * to assume anything, so it would be more robust and
12049 * easier to optimize.
12050 */
12051 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12052 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12053 #else
12054 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12055 #endif
12056 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
12057 xmlXPathObjectPtr val;
12058
12059 val = comp->steps[op->ch2].value4;
12060 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12061 (val->floatval == 1.0)) {
12062 xmlNodePtr first = NULL;
12063
12064 total +=
12065 xmlXPathCompOpEvalFirst(ctxt,
12066 &comp->steps[op->ch1],
12067 &first);
12068 CHECK_ERROR0;
12069 /*
12070 * The nodeset should be in document order,
12071 * Keep only the first value
12072 */
12073 if ((ctxt->value != NULL) &&
12074 (ctxt->value->type == XPATH_NODESET) &&
12075 (ctxt->value->nodesetval != NULL) &&
12076 (ctxt->value->nodesetval->nodeNr > 1))
12077 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
12078 1, 1);
12079 break;
12080 }
12081 }
12082 /*
12083 * Optimization for ()[last()] selection i.e. the last elem
12084 */
12085 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12086 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12087 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12088 int f = comp->steps[op->ch2].ch1;
12089
12090 if ((f != -1) &&
12091 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12092 (comp->steps[f].value5 == NULL) &&
12093 (comp->steps[f].value == 0) &&
12094 (comp->steps[f].value4 != NULL) &&
12095 (xmlStrEqual
12096 (comp->steps[f].value4, BAD_CAST "last"))) {
12097 xmlNodePtr last = NULL;
12098
12099 total +=
12100 xmlXPathCompOpEvalLast(ctxt,
12101 &comp->steps[op->ch1],
12102 &last);
12103 CHECK_ERROR0;
12104 /*
12105 * The nodeset should be in document order,
12106 * Keep only the last value
12107 */
12108 if ((ctxt->value != NULL) &&
12109 (ctxt->value->type == XPATH_NODESET) &&
12110 (ctxt->value->nodesetval != NULL) &&
12111 (ctxt->value->nodesetval->nodeTab != NULL) &&
12112 (ctxt->value->nodesetval->nodeNr > 1))
12113 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12114 break;
12115 }
12116 }
12117 /*
12118 * Process inner predicates first.
12119 * Example "index[parent::book][1]":
12120 * ...
12121 * PREDICATE <-- we are here "[1]"
12122 * PREDICATE <-- process "[parent::book]" first
12123 * SORT
12124 * COLLECT 'parent' 'name' 'node' book
12125 * NODE
12126 * ELEM Object is a number : 1
12127 */
12128 if (op->ch1 != -1)
12129 total +=
12130 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12131 CHECK_ERROR0;
12132 if (op->ch2 == -1)
12133 break;
12134 if (ctxt->value == NULL)
12135 break;
12136
12137 #ifdef LIBXML_XPTR_LOCS_ENABLED
12138 /*
12139 * Hum are we filtering the result of an XPointer expression
12140 */
12141 if (ctxt->value->type == XPATH_LOCATIONSET) {
12142 xmlLocationSetPtr locset = ctxt->value->user;
12143 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
12144 1, locset->locNr);
12145 break;
12146 }
12147 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12148
12149 /*
12150 * In case of errors, xmlXPathNodeSetFilter can pop additional
12151 * nodes from the stack. We have to temporarily remove the
12152 * nodeset object from the stack to avoid freeing it
12153 * prematurely.
12154 */
12155 CHECK_TYPE0(XPATH_NODESET);
12156 obj = valuePop(ctxt);
12157 set = obj->nodesetval;
12158 if (set != NULL)
12159 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
12160 1, set->nodeNr, 1);
12161 valuePush(ctxt, obj);
12162 break;
12163 }
12164 case XPATH_OP_SORT:
12165 if (op->ch1 != -1)
12166 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12167 CHECK_ERROR0;
12168 if ((ctxt->value != NULL) &&
12169 (ctxt->value->type == XPATH_NODESET) &&
12170 (ctxt->value->nodesetval != NULL) &&
12171 (ctxt->value->nodesetval->nodeNr > 1))
12172 {
12173 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12174 }
12175 break;
12176 #ifdef LIBXML_XPTR_LOCS_ENABLED
12177 case XPATH_OP_RANGETO:{
12178 xmlXPathObjectPtr range;
12179 xmlXPathObjectPtr res, obj;
12180 xmlXPathObjectPtr tmp;
12181 xmlLocationSetPtr newlocset = NULL;
12182 xmlLocationSetPtr oldlocset;
12183 xmlNodeSetPtr oldset;
12184 xmlNodePtr oldnode = ctxt->context->node;
12185 int oldcs = ctxt->context->contextSize;
12186 int oldpp = ctxt->context->proximityPosition;
12187 int i, j;
12188
12189 if (op->ch1 != -1) {
12190 total +=
12191 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12192 CHECK_ERROR0;
12193 }
12194 if (ctxt->value == NULL) {
12195 XP_ERROR0(XPATH_INVALID_OPERAND);
12196 }
12197 if (op->ch2 == -1)
12198 break;
12199
12200 if (ctxt->value->type == XPATH_LOCATIONSET) {
12201 /*
12202 * Extract the old locset, and then evaluate the result of the
12203 * expression for all the element in the locset. use it to grow
12204 * up a new locset.
12205 */
12206 CHECK_TYPE0(XPATH_LOCATIONSET);
12207
12208 if ((ctxt->value->user == NULL) ||
12209 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
12210 break;
12211
12212 obj = valuePop(ctxt);
12213 oldlocset = obj->user;
12214
12215 newlocset = xmlXPtrLocationSetCreate(NULL);
12216
12217 for (i = 0; i < oldlocset->locNr; i++) {
12218 /*
12219 * Run the evaluation with a node list made of a
12220 * single item in the nodelocset.
12221 */
12222 ctxt->context->node = oldlocset->locTab[i]->user;
12223 ctxt->context->contextSize = oldlocset->locNr;
12224 ctxt->context->proximityPosition = i + 1;
12225 tmp = xmlXPathCacheNewNodeSet(ctxt,
12226 ctxt->context->node);
12227 valuePush(ctxt, tmp);
12228
12229 if (op->ch2 != -1)
12230 total +=
12231 xmlXPathCompOpEval(ctxt,
12232 &comp->steps[op->ch2]);
12233 if (ctxt->error != XPATH_EXPRESSION_OK) {
12234 xmlXPtrFreeLocationSet(newlocset);
12235 goto rangeto_error;
12236 }
12237
12238 res = valuePop(ctxt);
12239 if (res->type == XPATH_LOCATIONSET) {
12240 xmlLocationSetPtr rloc =
12241 (xmlLocationSetPtr)res->user;
12242 for (j=0; j<rloc->locNr; j++) {
12243 range = xmlXPtrNewRange(
12244 oldlocset->locTab[i]->user,
12245 oldlocset->locTab[i]->index,
12246 rloc->locTab[j]->user2,
12247 rloc->locTab[j]->index2);
12248 if (range != NULL) {
12249 xmlXPtrLocationSetAdd(newlocset, range);
12250 }
12251 }
12252 } else {
12253 range = xmlXPtrNewRangeNodeObject(
12254 (xmlNodePtr)oldlocset->locTab[i]->user, res);
12255 if (range != NULL) {
12256 xmlXPtrLocationSetAdd(newlocset,range);
12257 }
12258 }
12259
12260 /*
12261 * Cleanup
12262 */
12263 if (res != NULL) {
12264 xmlXPathReleaseObject(ctxt->context, res);
12265 }
12266 if (ctxt->value == tmp) {
12267 res = valuePop(ctxt);
12268 xmlXPathReleaseObject(ctxt->context, res);
12269 }
12270 }
12271 } else { /* Not a location set */
12272 CHECK_TYPE0(XPATH_NODESET);
12273 obj = valuePop(ctxt);
12274 oldset = obj->nodesetval;
12275
12276 newlocset = xmlXPtrLocationSetCreate(NULL);
12277
12278 if (oldset != NULL) {
12279 for (i = 0; i < oldset->nodeNr; i++) {
12280 /*
12281 * Run the evaluation with a node list made of a single item
12282 * in the nodeset.
12283 */
12284 ctxt->context->node = oldset->nodeTab[i];
12285 /*
12286 * OPTIMIZE TODO: Avoid recreation for every iteration.
12287 */
12288 tmp = xmlXPathCacheNewNodeSet(ctxt,
12289 ctxt->context->node);
12290 valuePush(ctxt, tmp);
12291
12292 if (op->ch2 != -1)
12293 total +=
12294 xmlXPathCompOpEval(ctxt,
12295 &comp->steps[op->ch2]);
12296 if (ctxt->error != XPATH_EXPRESSION_OK) {
12297 xmlXPtrFreeLocationSet(newlocset);
12298 goto rangeto_error;
12299 }
12300
12301 res = valuePop(ctxt);
12302 range =
12303 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
12304 res);
12305 if (range != NULL) {
12306 xmlXPtrLocationSetAdd(newlocset, range);
12307 }
12308
12309 /*
12310 * Cleanup
12311 */
12312 if (res != NULL) {
12313 xmlXPathReleaseObject(ctxt->context, res);
12314 }
12315 if (ctxt->value == tmp) {
12316 res = valuePop(ctxt);
12317 xmlXPathReleaseObject(ctxt->context, res);
12318 }
12319 }
12320 }
12321 }
12322
12323 /*
12324 * The result is used as the new evaluation set.
12325 */
12326 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12327 rangeto_error:
12328 xmlXPathReleaseObject(ctxt->context, obj);
12329 ctxt->context->node = oldnode;
12330 ctxt->context->contextSize = oldcs;
12331 ctxt->context->proximityPosition = oldpp;
12332 break;
12333 }
12334 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12335 default:
12336 XP_ERROR0(XPATH_INVALID_OPERAND);
12337 break;
12338 }
12339
12340 ctxt->context->depth -= 1;
12341 return (total);
12342 }
12343
12344 /**
12345 * xmlXPathCompOpEvalToBoolean:
12346 * @ctxt: the XPath parser context
12347 *
12348 * Evaluates if the expression evaluates to true.
12349 *
12350 * Returns 1 if true, 0 if false and -1 on API or internal errors.
12351 */
12352 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)12353 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
12354 xmlXPathStepOpPtr op,
12355 int isPredicate)
12356 {
12357 xmlXPathObjectPtr resObj = NULL;
12358
12359 start:
12360 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12361 return(0);
12362 /* comp = ctxt->comp; */
12363 switch (op->op) {
12364 case XPATH_OP_END:
12365 return (0);
12366 case XPATH_OP_VALUE:
12367 resObj = (xmlXPathObjectPtr) op->value4;
12368 if (isPredicate)
12369 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
12370 return(xmlXPathCastToBoolean(resObj));
12371 case XPATH_OP_SORT:
12372 /*
12373 * We don't need sorting for boolean results. Skip this one.
12374 */
12375 if (op->ch1 != -1) {
12376 op = &ctxt->comp->steps[op->ch1];
12377 goto start;
12378 }
12379 return(0);
12380 case XPATH_OP_COLLECT:
12381 if (op->ch1 == -1)
12382 return(0);
12383
12384 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
12385 if (ctxt->error != XPATH_EXPRESSION_OK)
12386 return(-1);
12387
12388 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
12389 if (ctxt->error != XPATH_EXPRESSION_OK)
12390 return(-1);
12391
12392 resObj = valuePop(ctxt);
12393 if (resObj == NULL)
12394 return(-1);
12395 break;
12396 default:
12397 /*
12398 * Fallback to call xmlXPathCompOpEval().
12399 */
12400 xmlXPathCompOpEval(ctxt, op);
12401 if (ctxt->error != XPATH_EXPRESSION_OK)
12402 return(-1);
12403
12404 resObj = valuePop(ctxt);
12405 if (resObj == NULL)
12406 return(-1);
12407 break;
12408 }
12409
12410 if (resObj) {
12411 int res;
12412
12413 if (resObj->type == XPATH_BOOLEAN) {
12414 res = resObj->boolval;
12415 } else if (isPredicate) {
12416 /*
12417 * For predicates a result of type "number" is handled
12418 * differently:
12419 * SPEC XPath 1.0:
12420 * "If the result is a number, the result will be converted
12421 * to true if the number is equal to the context position
12422 * and will be converted to false otherwise;"
12423 */
12424 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
12425 } else {
12426 res = xmlXPathCastToBoolean(resObj);
12427 }
12428 xmlXPathReleaseObject(ctxt->context, resObj);
12429 return(res);
12430 }
12431
12432 return(0);
12433 }
12434
12435 #ifdef XPATH_STREAMING
12436 /**
12437 * xmlXPathRunStreamEval:
12438 * @pctxt: the XPath parser context with the compiled expression
12439 *
12440 * Evaluate the Precompiled Streamable XPath expression in the given context.
12441 */
12442 static int
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)12443 xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
12444 xmlXPathObjectPtr *resultSeq, int toBool)
12445 {
12446 int max_depth, min_depth;
12447 int from_root;
12448 int ret, depth;
12449 int eval_all_nodes;
12450 xmlNodePtr cur = NULL, limit = NULL;
12451 xmlStreamCtxtPtr patstream = NULL;
12452 xmlXPathContextPtr ctxt = pctxt->context;
12453
12454 if ((ctxt == NULL) || (comp == NULL))
12455 return(-1);
12456 max_depth = xmlPatternMaxDepth(comp);
12457 if (max_depth == -1)
12458 return(-1);
12459 if (max_depth == -2)
12460 max_depth = 10000;
12461 min_depth = xmlPatternMinDepth(comp);
12462 if (min_depth == -1)
12463 return(-1);
12464 from_root = xmlPatternFromRoot(comp);
12465 if (from_root < 0)
12466 return(-1);
12467 #if 0
12468 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
12469 #endif
12470
12471 if (! toBool) {
12472 if (resultSeq == NULL)
12473 return(-1);
12474 *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
12475 if (*resultSeq == NULL)
12476 return(-1);
12477 }
12478
12479 /*
12480 * handle the special cases of "/" amd "." being matched
12481 */
12482 if (min_depth == 0) {
12483 int res;
12484
12485 if (from_root) {
12486 /* Select "/" */
12487 if (toBool)
12488 return(1);
12489 res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12490 (xmlNodePtr) ctxt->doc);
12491 } else {
12492 /* Select "self::node()" */
12493 if (toBool)
12494 return(1);
12495 res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12496 ctxt->node);
12497 }
12498
12499 if (res < 0)
12500 xmlXPathPErrMemory(pctxt);
12501 }
12502 if (max_depth == 0) {
12503 return(0);
12504 }
12505
12506 if (from_root) {
12507 cur = (xmlNodePtr)ctxt->doc;
12508 } else if (ctxt->node != NULL) {
12509 switch (ctxt->node->type) {
12510 case XML_ELEMENT_NODE:
12511 case XML_DOCUMENT_NODE:
12512 case XML_DOCUMENT_FRAG_NODE:
12513 case XML_HTML_DOCUMENT_NODE:
12514 cur = ctxt->node;
12515 break;
12516 case XML_ATTRIBUTE_NODE:
12517 case XML_TEXT_NODE:
12518 case XML_CDATA_SECTION_NODE:
12519 case XML_ENTITY_REF_NODE:
12520 case XML_ENTITY_NODE:
12521 case XML_PI_NODE:
12522 case XML_COMMENT_NODE:
12523 case XML_NOTATION_NODE:
12524 case XML_DTD_NODE:
12525 case XML_DOCUMENT_TYPE_NODE:
12526 case XML_ELEMENT_DECL:
12527 case XML_ATTRIBUTE_DECL:
12528 case XML_ENTITY_DECL:
12529 case XML_NAMESPACE_DECL:
12530 case XML_XINCLUDE_START:
12531 case XML_XINCLUDE_END:
12532 break;
12533 }
12534 limit = cur;
12535 }
12536 if (cur == NULL) {
12537 return(0);
12538 }
12539
12540 patstream = xmlPatternGetStreamCtxt(comp);
12541 if (patstream == NULL) {
12542 xmlXPathPErrMemory(pctxt);
12543 return(-1);
12544 }
12545
12546 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12547
12548 if (from_root) {
12549 ret = xmlStreamPush(patstream, NULL, NULL);
12550 if (ret < 0) {
12551 } else if (ret == 1) {
12552 if (toBool)
12553 goto return_1;
12554 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
12555 xmlXPathPErrMemory(pctxt);
12556 }
12557 }
12558 depth = 0;
12559 goto scan_children;
12560 next_node:
12561 do {
12562 if (ctxt->opLimit != 0) {
12563 if (ctxt->opCount >= ctxt->opLimit) {
12564 xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
12565 xmlFreeStreamCtxt(patstream);
12566 return(-1);
12567 }
12568 ctxt->opCount++;
12569 }
12570
12571 switch (cur->type) {
12572 case XML_ELEMENT_NODE:
12573 case XML_TEXT_NODE:
12574 case XML_CDATA_SECTION_NODE:
12575 case XML_COMMENT_NODE:
12576 case XML_PI_NODE:
12577 if (cur->type == XML_ELEMENT_NODE) {
12578 ret = xmlStreamPush(patstream, cur->name,
12579 (cur->ns ? cur->ns->href : NULL));
12580 } else if (eval_all_nodes)
12581 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12582 else
12583 break;
12584
12585 if (ret < 0) {
12586 xmlXPathPErrMemory(pctxt);
12587 } else if (ret == 1) {
12588 if (toBool)
12589 goto return_1;
12590 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12591 cur) < 0)
12592 xmlXPathPErrMemory(pctxt);
12593 }
12594 if ((cur->children == NULL) || (depth >= max_depth)) {
12595 ret = xmlStreamPop(patstream);
12596 while (cur->next != NULL) {
12597 cur = cur->next;
12598 if ((cur->type != XML_ENTITY_DECL) &&
12599 (cur->type != XML_DTD_NODE))
12600 goto next_node;
12601 }
12602 }
12603 default:
12604 break;
12605 }
12606
12607 scan_children:
12608 if (cur->type == XML_NAMESPACE_DECL) break;
12609 if ((cur->children != NULL) && (depth < max_depth)) {
12610 /*
12611 * Do not descend on entities declarations
12612 */
12613 if (cur->children->type != XML_ENTITY_DECL) {
12614 cur = cur->children;
12615 depth++;
12616 /*
12617 * Skip DTDs
12618 */
12619 if (cur->type != XML_DTD_NODE)
12620 continue;
12621 }
12622 }
12623
12624 if (cur == limit)
12625 break;
12626
12627 while (cur->next != NULL) {
12628 cur = cur->next;
12629 if ((cur->type != XML_ENTITY_DECL) &&
12630 (cur->type != XML_DTD_NODE))
12631 goto next_node;
12632 }
12633
12634 do {
12635 cur = cur->parent;
12636 depth--;
12637 if ((cur == NULL) || (cur == limit) ||
12638 (cur->type == XML_DOCUMENT_NODE))
12639 goto done;
12640 if (cur->type == XML_ELEMENT_NODE) {
12641 ret = xmlStreamPop(patstream);
12642 } else if ((eval_all_nodes) &&
12643 ((cur->type == XML_TEXT_NODE) ||
12644 (cur->type == XML_CDATA_SECTION_NODE) ||
12645 (cur->type == XML_COMMENT_NODE) ||
12646 (cur->type == XML_PI_NODE)))
12647 {
12648 ret = xmlStreamPop(patstream);
12649 }
12650 if (cur->next != NULL) {
12651 cur = cur->next;
12652 break;
12653 }
12654 } while (cur != NULL);
12655
12656 } while ((cur != NULL) && (depth >= 0));
12657
12658 done:
12659
12660 if (patstream)
12661 xmlFreeStreamCtxt(patstream);
12662 return(0);
12663
12664 return_1:
12665 if (patstream)
12666 xmlFreeStreamCtxt(patstream);
12667 return(1);
12668 }
12669 #endif /* XPATH_STREAMING */
12670
12671 /**
12672 * xmlXPathRunEval:
12673 * @ctxt: the XPath parser context with the compiled expression
12674 * @toBool: evaluate to a boolean result
12675 *
12676 * Evaluate the Precompiled XPath expression in the given context.
12677 */
12678 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)12679 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12680 {
12681 xmlXPathCompExprPtr comp;
12682 int oldDepth;
12683
12684 if ((ctxt == NULL) || (ctxt->comp == NULL))
12685 return(-1);
12686
12687 if (ctxt->valueTab == NULL) {
12688 /* Allocate the value stack */
12689 ctxt->valueTab = (xmlXPathObjectPtr *)
12690 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12691 if (ctxt->valueTab == NULL) {
12692 xmlXPathPErrMemory(ctxt);
12693 return(-1);
12694 }
12695 ctxt->valueNr = 0;
12696 ctxt->valueMax = 10;
12697 ctxt->value = NULL;
12698 }
12699 #ifdef XPATH_STREAMING
12700 if (ctxt->comp->stream) {
12701 int res;
12702
12703 if (toBool) {
12704 /*
12705 * Evaluation to boolean result.
12706 */
12707 res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12708 if (res != -1)
12709 return(res);
12710 } else {
12711 xmlXPathObjectPtr resObj = NULL;
12712
12713 /*
12714 * Evaluation to a sequence.
12715 */
12716 res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12717
12718 if ((res != -1) && (resObj != NULL)) {
12719 valuePush(ctxt, resObj);
12720 return(0);
12721 }
12722 if (resObj != NULL)
12723 xmlXPathReleaseObject(ctxt->context, resObj);
12724 }
12725 /*
12726 * QUESTION TODO: This falls back to normal XPath evaluation
12727 * if res == -1. Is this intended?
12728 */
12729 }
12730 #endif
12731 comp = ctxt->comp;
12732 if (comp->last < 0) {
12733 xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12734 return(-1);
12735 }
12736 oldDepth = ctxt->context->depth;
12737 if (toBool)
12738 return(xmlXPathCompOpEvalToBoolean(ctxt,
12739 &comp->steps[comp->last], 0));
12740 else
12741 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12742 ctxt->context->depth = oldDepth;
12743
12744 return(0);
12745 }
12746
12747 /************************************************************************
12748 * *
12749 * Public interfaces *
12750 * *
12751 ************************************************************************/
12752
12753 /**
12754 * xmlXPathEvalPredicate:
12755 * @ctxt: the XPath context
12756 * @res: the Predicate Expression evaluation result
12757 *
12758 * Evaluate a predicate result for the current node.
12759 * A PredicateExpr is evaluated by evaluating the Expr and converting
12760 * the result to a boolean. If the result is a number, the result will
12761 * be converted to true if the number is equal to the position of the
12762 * context node in the context node list (as returned by the position
12763 * function) and will be converted to false otherwise; if the result
12764 * is not a number, then the result will be converted as if by a call
12765 * to the boolean function.
12766 *
12767 * Returns 1 if predicate is true, 0 otherwise
12768 */
12769 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)12770 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12771 if ((ctxt == NULL) || (res == NULL)) return(0);
12772 switch (res->type) {
12773 case XPATH_BOOLEAN:
12774 return(res->boolval);
12775 case XPATH_NUMBER:
12776 return(res->floatval == ctxt->proximityPosition);
12777 case XPATH_NODESET:
12778 case XPATH_XSLT_TREE:
12779 if (res->nodesetval == NULL)
12780 return(0);
12781 return(res->nodesetval->nodeNr != 0);
12782 case XPATH_STRING:
12783 return((res->stringval != NULL) &&
12784 (xmlStrlen(res->stringval) != 0));
12785 default:
12786 break;
12787 }
12788 return(0);
12789 }
12790
12791 /**
12792 * xmlXPathEvaluatePredicateResult:
12793 * @ctxt: the XPath Parser context
12794 * @res: the Predicate Expression evaluation result
12795 *
12796 * Evaluate a predicate result for the current node.
12797 * A PredicateExpr is evaluated by evaluating the Expr and converting
12798 * the result to a boolean. If the result is a number, the result will
12799 * be converted to true if the number is equal to the position of the
12800 * context node in the context node list (as returned by the position
12801 * function) and will be converted to false otherwise; if the result
12802 * is not a number, then the result will be converted as if by a call
12803 * to the boolean function.
12804 *
12805 * Returns 1 if predicate is true, 0 otherwise
12806 */
12807 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)12808 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12809 xmlXPathObjectPtr res) {
12810 if ((ctxt == NULL) || (res == NULL)) return(0);
12811 switch (res->type) {
12812 case XPATH_BOOLEAN:
12813 return(res->boolval);
12814 case XPATH_NUMBER:
12815 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12816 return((res->floatval == ctxt->context->proximityPosition) &&
12817 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12818 #else
12819 return(res->floatval == ctxt->context->proximityPosition);
12820 #endif
12821 case XPATH_NODESET:
12822 case XPATH_XSLT_TREE:
12823 if (res->nodesetval == NULL)
12824 return(0);
12825 return(res->nodesetval->nodeNr != 0);
12826 case XPATH_STRING:
12827 return((res->stringval != NULL) && (res->stringval[0] != 0));
12828 #ifdef LIBXML_XPTR_LOCS_ENABLED
12829 case XPATH_LOCATIONSET:{
12830 xmlLocationSetPtr ptr = res->user;
12831 if (ptr == NULL)
12832 return(0);
12833 return (ptr->locNr != 0);
12834 }
12835 #endif
12836 default:
12837 break;
12838 }
12839 return(0);
12840 }
12841
12842 #ifdef XPATH_STREAMING
12843 /**
12844 * xmlXPathTryStreamCompile:
12845 * @ctxt: an XPath context
12846 * @str: the XPath expression
12847 *
12848 * Try to compile the XPath expression as a streamable subset.
12849 *
12850 * Returns the compiled expression or NULL if failed to compile.
12851 */
12852 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)12853 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12854 /*
12855 * Optimization: use streaming patterns when the XPath expression can
12856 * be compiled to a stream lookup
12857 */
12858 xmlPatternPtr stream;
12859 xmlXPathCompExprPtr comp;
12860 xmlDictPtr dict = NULL;
12861 const xmlChar **namespaces = NULL;
12862 xmlNsPtr ns;
12863 int i, j;
12864
12865 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12866 (!xmlStrchr(str, '@'))) {
12867 const xmlChar *tmp;
12868 int res;
12869
12870 /*
12871 * We don't try to handle expressions using the verbose axis
12872 * specifiers ("::"), just the simplified form at this point.
12873 * Additionally, if there is no list of namespaces available and
12874 * there's a ":" in the expression, indicating a prefixed QName,
12875 * then we won't try to compile either. xmlPatterncompile() needs
12876 * to have a list of namespaces at compilation time in order to
12877 * compile prefixed name tests.
12878 */
12879 tmp = xmlStrchr(str, ':');
12880 if ((tmp != NULL) &&
12881 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12882 return(NULL);
12883
12884 if (ctxt != NULL) {
12885 dict = ctxt->dict;
12886 if (ctxt->nsNr > 0) {
12887 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12888 if (namespaces == NULL) {
12889 xmlXPathErrMemory(ctxt);
12890 return(NULL);
12891 }
12892 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12893 ns = ctxt->namespaces[j];
12894 namespaces[i++] = ns->href;
12895 namespaces[i++] = ns->prefix;
12896 }
12897 namespaces[i++] = NULL;
12898 namespaces[i] = NULL;
12899 }
12900 }
12901
12902 res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12903 &stream);
12904 if (namespaces != NULL) {
12905 xmlFree((xmlChar **)namespaces);
12906 }
12907 if (res < 0) {
12908 xmlXPathErrMemory(ctxt);
12909 return(NULL);
12910 }
12911 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12912 comp = xmlXPathNewCompExpr();
12913 if (comp == NULL) {
12914 xmlXPathErrMemory(ctxt);
12915 xmlFreePattern(stream);
12916 return(NULL);
12917 }
12918 comp->stream = stream;
12919 comp->dict = dict;
12920 if (comp->dict)
12921 xmlDictReference(comp->dict);
12922 return(comp);
12923 }
12924 xmlFreePattern(stream);
12925 }
12926 return(NULL);
12927 }
12928 #endif /* XPATH_STREAMING */
12929
12930 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)12931 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12932 xmlXPathStepOpPtr op)
12933 {
12934 xmlXPathCompExprPtr comp = pctxt->comp;
12935 xmlXPathContextPtr ctxt;
12936
12937 /*
12938 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12939 * internal representation.
12940 */
12941
12942 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12943 (op->ch1 != -1) &&
12944 (op->ch2 == -1 /* no predicate */))
12945 {
12946 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12947
12948 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12949 ((xmlXPathAxisVal) prevop->value ==
12950 AXIS_DESCENDANT_OR_SELF) &&
12951 (prevop->ch2 == -1) &&
12952 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12953 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12954 {
12955 /*
12956 * This is a "descendant-or-self::node()" without predicates.
12957 * Try to eliminate it.
12958 */
12959
12960 switch ((xmlXPathAxisVal) op->value) {
12961 case AXIS_CHILD:
12962 case AXIS_DESCENDANT:
12963 /*
12964 * Convert "descendant-or-self::node()/child::" or
12965 * "descendant-or-self::node()/descendant::" to
12966 * "descendant::"
12967 */
12968 op->ch1 = prevop->ch1;
12969 op->value = AXIS_DESCENDANT;
12970 break;
12971 case AXIS_SELF:
12972 case AXIS_DESCENDANT_OR_SELF:
12973 /*
12974 * Convert "descendant-or-self::node()/self::" or
12975 * "descendant-or-self::node()/descendant-or-self::" to
12976 * to "descendant-or-self::"
12977 */
12978 op->ch1 = prevop->ch1;
12979 op->value = AXIS_DESCENDANT_OR_SELF;
12980 break;
12981 default:
12982 break;
12983 }
12984 }
12985 }
12986
12987 /* OP_VALUE has invalid ch1. */
12988 if (op->op == XPATH_OP_VALUE)
12989 return;
12990
12991 /* Recurse */
12992 ctxt = pctxt->context;
12993 if (ctxt != NULL) {
12994 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
12995 return;
12996 ctxt->depth += 1;
12997 }
12998 if (op->ch1 != -1)
12999 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
13000 if (op->ch2 != -1)
13001 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
13002 if (ctxt != NULL)
13003 ctxt->depth -= 1;
13004 }
13005
13006 /**
13007 * xmlXPathCtxtCompile:
13008 * @ctxt: an XPath context
13009 * @str: the XPath expression
13010 *
13011 * Compile an XPath expression
13012 *
13013 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13014 * the caller has to free the object.
13015 */
13016 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)13017 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13018 xmlXPathParserContextPtr pctxt;
13019 xmlXPathCompExprPtr comp;
13020 int oldDepth = 0;
13021
13022 #ifdef XPATH_STREAMING
13023 comp = xmlXPathTryStreamCompile(ctxt, str);
13024 if (comp != NULL)
13025 return(comp);
13026 #endif
13027
13028 xmlInitParser();
13029
13030 pctxt = xmlXPathNewParserContext(str, ctxt);
13031 if (pctxt == NULL)
13032 return NULL;
13033 if (ctxt != NULL)
13034 oldDepth = ctxt->depth;
13035 xmlXPathCompileExpr(pctxt, 1);
13036 if (ctxt != NULL)
13037 ctxt->depth = oldDepth;
13038
13039 if( pctxt->error != XPATH_EXPRESSION_OK )
13040 {
13041 xmlXPathFreeParserContext(pctxt);
13042 return(NULL);
13043 }
13044
13045 if (*pctxt->cur != 0) {
13046 /*
13047 * aleksey: in some cases this line prints *second* error message
13048 * (see bug #78858) and probably this should be fixed.
13049 * However, we are not sure that all error messages are printed
13050 * out in other places. It's not critical so we leave it as-is for now
13051 */
13052 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13053 comp = NULL;
13054 } else {
13055 comp = pctxt->comp;
13056 if ((comp->nbStep > 1) && (comp->last >= 0)) {
13057 if (ctxt != NULL)
13058 oldDepth = ctxt->depth;
13059 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
13060 if (ctxt != NULL)
13061 ctxt->depth = oldDepth;
13062 }
13063 pctxt->comp = NULL;
13064 }
13065 xmlXPathFreeParserContext(pctxt);
13066
13067 if (comp != NULL) {
13068 comp->expr = xmlStrdup(str);
13069 }
13070 return(comp);
13071 }
13072
13073 /**
13074 * xmlXPathCompile:
13075 * @str: the XPath expression
13076 *
13077 * Compile an XPath expression
13078 *
13079 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13080 * the caller has to free the object.
13081 */
13082 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)13083 xmlXPathCompile(const xmlChar *str) {
13084 return(xmlXPathCtxtCompile(NULL, str));
13085 }
13086
13087 /**
13088 * xmlXPathCompiledEvalInternal:
13089 * @comp: the compiled XPath expression
13090 * @ctxt: the XPath context
13091 * @resObj: the resulting XPath object or NULL
13092 * @toBool: 1 if only a boolean result is requested
13093 *
13094 * Evaluate the Precompiled XPath expression in the given context.
13095 * The caller has to free @resObj.
13096 *
13097 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13098 * the caller has to free the object.
13099 */
13100 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)13101 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
13102 xmlXPathContextPtr ctxt,
13103 xmlXPathObjectPtr *resObjPtr,
13104 int toBool)
13105 {
13106 xmlXPathParserContextPtr pctxt;
13107 xmlXPathObjectPtr resObj = NULL;
13108 #ifndef LIBXML_THREAD_ENABLED
13109 static int reentance = 0;
13110 #endif
13111 int res;
13112
13113 if (comp == NULL)
13114 return(-1);
13115 xmlInitParser();
13116
13117 xmlResetError(&ctxt->lastError);
13118
13119 #ifndef LIBXML_THREAD_ENABLED
13120 reentance++;
13121 if (reentance > 1)
13122 xmlXPathDisableOptimizer = 1;
13123 #endif
13124
13125 pctxt = xmlXPathCompParserContext(comp, ctxt);
13126 if (pctxt == NULL)
13127 return(-1);
13128 res = xmlXPathRunEval(pctxt, toBool);
13129
13130 if (pctxt->error == XPATH_EXPRESSION_OK) {
13131 if (pctxt->valueNr != ((toBool) ? 0 : 1))
13132 xmlXPathErr(pctxt, XPATH_STACK_ERROR);
13133 else if (!toBool)
13134 resObj = valuePop(pctxt);
13135 }
13136
13137 if (resObjPtr)
13138 *resObjPtr = resObj;
13139 else
13140 xmlXPathReleaseObject(ctxt, resObj);
13141
13142 pctxt->comp = NULL;
13143 xmlXPathFreeParserContext(pctxt);
13144 #ifndef LIBXML_THREAD_ENABLED
13145 reentance--;
13146 #endif
13147
13148 return(res);
13149 }
13150
13151 /**
13152 * xmlXPathCompiledEval:
13153 * @comp: the compiled XPath expression
13154 * @ctx: the XPath context
13155 *
13156 * Evaluate the Precompiled XPath expression in the given context.
13157 *
13158 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13159 * the caller has to free the object.
13160 */
13161 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)13162 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
13163 {
13164 xmlXPathObjectPtr res = NULL;
13165
13166 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
13167 return(res);
13168 }
13169
13170 /**
13171 * xmlXPathCompiledEvalToBoolean:
13172 * @comp: the compiled XPath expression
13173 * @ctxt: the XPath context
13174 *
13175 * Applies the XPath boolean() function on the result of the given
13176 * compiled expression.
13177 *
13178 * Returns 1 if the expression evaluated to true, 0 if to false and
13179 * -1 in API and internal errors.
13180 */
13181 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)13182 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
13183 xmlXPathContextPtr ctxt)
13184 {
13185 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
13186 }
13187
13188 /**
13189 * xmlXPathEvalExpr:
13190 * @ctxt: the XPath Parser context
13191 *
13192 * Parse and evaluate an XPath expression in the given context,
13193 * then push the result on the context stack
13194 */
13195 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)13196 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
13197 #ifdef XPATH_STREAMING
13198 xmlXPathCompExprPtr comp;
13199 #endif
13200 int oldDepth = 0;
13201
13202 if (ctxt == NULL)
13203 return;
13204 if (ctxt->context->lastError.code != 0)
13205 return;
13206
13207 #ifdef XPATH_STREAMING
13208 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13209 if ((comp == NULL) &&
13210 (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
13211 xmlXPathPErrMemory(ctxt);
13212 return;
13213 }
13214 if (comp != NULL) {
13215 if (ctxt->comp != NULL)
13216 xmlXPathFreeCompExpr(ctxt->comp);
13217 ctxt->comp = comp;
13218 } else
13219 #endif
13220 {
13221 if (ctxt->context != NULL)
13222 oldDepth = ctxt->context->depth;
13223 xmlXPathCompileExpr(ctxt, 1);
13224 if (ctxt->context != NULL)
13225 ctxt->context->depth = oldDepth;
13226 CHECK_ERROR;
13227
13228 /* Check for trailing characters. */
13229 if (*ctxt->cur != 0)
13230 XP_ERROR(XPATH_EXPR_ERROR);
13231
13232 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
13233 if (ctxt->context != NULL)
13234 oldDepth = ctxt->context->depth;
13235 xmlXPathOptimizeExpression(ctxt,
13236 &ctxt->comp->steps[ctxt->comp->last]);
13237 if (ctxt->context != NULL)
13238 ctxt->context->depth = oldDepth;
13239 }
13240 }
13241
13242 xmlXPathRunEval(ctxt, 0);
13243 }
13244
13245 /**
13246 * xmlXPathEval:
13247 * @str: the XPath expression
13248 * @ctx: the XPath context
13249 *
13250 * Evaluate the XPath Location Path in the given context.
13251 *
13252 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13253 * the caller has to free the object.
13254 */
13255 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)13256 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13257 xmlXPathParserContextPtr ctxt;
13258 xmlXPathObjectPtr res;
13259
13260 if (ctx == NULL)
13261 return(NULL);
13262
13263 xmlInitParser();
13264
13265 xmlResetError(&ctx->lastError);
13266
13267 ctxt = xmlXPathNewParserContext(str, ctx);
13268 if (ctxt == NULL)
13269 return NULL;
13270 xmlXPathEvalExpr(ctxt);
13271
13272 if (ctxt->error != XPATH_EXPRESSION_OK) {
13273 res = NULL;
13274 } else if (ctxt->valueNr != 1) {
13275 xmlXPathErr(ctxt, XPATH_STACK_ERROR);
13276 res = NULL;
13277 } else {
13278 res = valuePop(ctxt);
13279 }
13280
13281 xmlXPathFreeParserContext(ctxt);
13282 return(res);
13283 }
13284
13285 /**
13286 * xmlXPathSetContextNode:
13287 * @node: the node to to use as the context node
13288 * @ctx: the XPath context
13289 *
13290 * Sets 'node' as the context node. The node must be in the same
13291 * document as that associated with the context.
13292 *
13293 * Returns -1 in case of error or 0 if successful
13294 */
13295 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)13296 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
13297 if ((node == NULL) || (ctx == NULL))
13298 return(-1);
13299
13300 if (node->doc == ctx->doc) {
13301 ctx->node = node;
13302 return(0);
13303 }
13304 return(-1);
13305 }
13306
13307 /**
13308 * xmlXPathNodeEval:
13309 * @node: the node to to use as the context node
13310 * @str: the XPath expression
13311 * @ctx: the XPath context
13312 *
13313 * Evaluate the XPath Location Path in the given context. The node 'node'
13314 * is set as the context node. The context node is not restored.
13315 *
13316 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13317 * the caller has to free the object.
13318 */
13319 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)13320 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
13321 if (str == NULL)
13322 return(NULL);
13323 if (xmlXPathSetContextNode(node, ctx) < 0)
13324 return(NULL);
13325 return(xmlXPathEval(str, ctx));
13326 }
13327
13328 /**
13329 * xmlXPathEvalExpression:
13330 * @str: the XPath expression
13331 * @ctxt: the XPath context
13332 *
13333 * Alias for xmlXPathEval().
13334 *
13335 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13336 * the caller has to free the object.
13337 */
13338 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)13339 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13340 return(xmlXPathEval(str, ctxt));
13341 }
13342
13343 /************************************************************************
13344 * *
13345 * Extra functions not pertaining to the XPath spec *
13346 * *
13347 ************************************************************************/
13348 /**
13349 * xmlXPathEscapeUriFunction:
13350 * @ctxt: the XPath Parser context
13351 * @nargs: the number of arguments
13352 *
13353 * Implement the escape-uri() XPath function
13354 * string escape-uri(string $str, bool $escape-reserved)
13355 *
13356 * This function applies the URI escaping rules defined in section 2 of [RFC
13357 * 2396] to the string supplied as $uri-part, which typically represents all
13358 * or part of a URI. The effect of the function is to replace any special
13359 * character in the string by an escape sequence of the form %xx%yy...,
13360 * where xxyy... is the hexadecimal representation of the octets used to
13361 * represent the character in UTF-8.
13362 *
13363 * The set of characters that are escaped depends on the setting of the
13364 * boolean argument $escape-reserved.
13365 *
13366 * If $escape-reserved is true, all characters are escaped other than lower
13367 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13368 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13369 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13370 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13371 * A-F).
13372 *
13373 * If $escape-reserved is false, the behavior differs in that characters
13374 * referred to in [RFC 2396] as reserved characters are not escaped. These
13375 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13376 *
13377 * [RFC 2396] does not define whether escaped URIs should use lower case or
13378 * upper case for hexadecimal digits. To ensure that escaped URIs can be
13379 * compared using string comparison functions, this function must always use
13380 * the upper-case letters A-F.
13381 *
13382 * Generally, $escape-reserved should be set to true when escaping a string
13383 * that is to form a single part of a URI, and to false when escaping an
13384 * entire URI or URI reference.
13385 *
13386 * In the case of non-ascii characters, the string is encoded according to
13387 * utf-8 and then converted according to RFC 2396.
13388 *
13389 * Examples
13390 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
13391 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
13392 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
13393 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
13394 *
13395 */
13396 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)13397 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
13398 xmlXPathObjectPtr str;
13399 int escape_reserved;
13400 xmlBufPtr target;
13401 xmlChar *cptr;
13402 xmlChar escape[4];
13403
13404 CHECK_ARITY(2);
13405
13406 escape_reserved = xmlXPathPopBoolean(ctxt);
13407
13408 CAST_TO_STRING;
13409 str = valuePop(ctxt);
13410
13411 target = xmlBufCreate();
13412
13413 escape[0] = '%';
13414 escape[3] = 0;
13415
13416 if (target) {
13417 for (cptr = str->stringval; *cptr; cptr++) {
13418 if ((*cptr >= 'A' && *cptr <= 'Z') ||
13419 (*cptr >= 'a' && *cptr <= 'z') ||
13420 (*cptr >= '0' && *cptr <= '9') ||
13421 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
13422 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
13423 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
13424 (*cptr == '%' &&
13425 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
13426 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
13427 (cptr[1] >= '0' && cptr[1] <= '9')) &&
13428 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
13429 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
13430 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
13431 (!escape_reserved &&
13432 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
13433 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
13434 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
13435 *cptr == ','))) {
13436 xmlBufAdd(target, cptr, 1);
13437 } else {
13438 if ((*cptr >> 4) < 10)
13439 escape[1] = '0' + (*cptr >> 4);
13440 else
13441 escape[1] = 'A' - 10 + (*cptr >> 4);
13442 if ((*cptr & 0xF) < 10)
13443 escape[2] = '0' + (*cptr & 0xF);
13444 else
13445 escape[2] = 'A' - 10 + (*cptr & 0xF);
13446
13447 xmlBufAdd(target, &escape[0], 3);
13448 }
13449 }
13450 }
13451 valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
13452 xmlBufFree(target);
13453 xmlXPathReleaseObject(ctxt->context, str);
13454 }
13455
13456 /**
13457 * xmlXPathRegisterAllFunctions:
13458 * @ctxt: the XPath context
13459 *
13460 * Registers all default XPath functions in this context
13461 */
13462 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)13463 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
13464 {
13465 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
13466 xmlXPathBooleanFunction);
13467 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
13468 xmlXPathCeilingFunction);
13469 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
13470 xmlXPathCountFunction);
13471 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
13472 xmlXPathConcatFunction);
13473 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
13474 xmlXPathContainsFunction);
13475 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
13476 xmlXPathIdFunction);
13477 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
13478 xmlXPathFalseFunction);
13479 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
13480 xmlXPathFloorFunction);
13481 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
13482 xmlXPathLastFunction);
13483 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
13484 xmlXPathLangFunction);
13485 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
13486 xmlXPathLocalNameFunction);
13487 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
13488 xmlXPathNotFunction);
13489 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
13490 xmlXPathNameFunction);
13491 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
13492 xmlXPathNamespaceURIFunction);
13493 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
13494 xmlXPathNormalizeFunction);
13495 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
13496 xmlXPathNumberFunction);
13497 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13498 xmlXPathPositionFunction);
13499 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13500 xmlXPathRoundFunction);
13501 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13502 xmlXPathStringFunction);
13503 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13504 xmlXPathStringLengthFunction);
13505 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13506 xmlXPathStartsWithFunction);
13507 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13508 xmlXPathSubstringFunction);
13509 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13510 xmlXPathSubstringBeforeFunction);
13511 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13512 xmlXPathSubstringAfterFunction);
13513 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13514 xmlXPathSumFunction);
13515 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13516 xmlXPathTrueFunction);
13517 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13518 xmlXPathTranslateFunction);
13519
13520 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13521 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13522 xmlXPathEscapeUriFunction);
13523 }
13524
13525 #endif /* LIBXML_XPATH_ENABLED */
13526