1 /*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21
22 #define IN_LIBXML
23 #include "libxml.h"
24
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_MATH_H
33 #include <math.h>
34 #endif
35 #ifdef HAVE_FLOAT_H
36 #include <float.h>
37 #endif
38 #ifdef HAVE_CTYPE_H
39 #include <ctype.h>
40 #endif
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
54 #endif
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
57 #endif
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
63 #endif
64
65 #include "buf.h"
66
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
69 #endif
70
71 #define TODO \
72 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
74 __FILE__, __LINE__);
75
76 /**
77 * WITH_TIM_SORT:
78 *
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
82 */
83 #define WITH_TIM_SORT
84
85 /*
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
93 */
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
95
96 /*
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
100 */
101 #define XP_OPTIMIZED_FILTER_FIRST
102
103 /*
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
106 * created.
107 */
108 /* #define XP_DEBUG_OBJ_USAGE */
109
110 /*
111 * XPATH_MAX_STEPS:
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
115 * circumstances
116 */
117 #define XPATH_MAX_STEPS 1000000
118
119 /*
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
124 * circumstances
125 */
126 #define XPATH_MAX_STACK_DEPTH 1000000
127
128 /*
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
135 */
136 #define XPATH_MAX_NODESET_LENGTH 10000000
137
138 /*
139 * TODO:
140 * There are a few spots where some tests are done which depend upon ascii
141 * data. These should be enhanced for full UTF8 support (see particularly
142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143 */
144
145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146 /**
147 * xmlXPathCmpNodesExt:
148 * @node1: the first node
149 * @node2: the second node
150 *
151 * Compare two nodes w.r.t document order.
152 * This one is optimized for handling of non-element nodes.
153 *
154 * Returns -2 in case of error 1 if first point < second point, 0 if
155 * it's the same node, -1 otherwise
156 */
157 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159 int depth1, depth2;
160 int misc = 0, precedence1 = 0, precedence2 = 0;
161 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162 xmlNodePtr cur, root;
163 ptrdiff_t l1, l2;
164
165 if ((node1 == NULL) || (node2 == NULL))
166 return(-2);
167
168 if (node1 == node2)
169 return(0);
170
171 /*
172 * a couple of optimizations which will avoid computations in most cases
173 */
174 switch (node1->type) {
175 case XML_ELEMENT_NODE:
176 if (node2->type == XML_ELEMENT_NODE) {
177 if ((0 > (ptrdiff_t) node1->content) &&
178 (0 > (ptrdiff_t) node2->content) &&
179 (node1->doc == node2->doc))
180 {
181 l1 = -((ptrdiff_t) node1->content);
182 l2 = -((ptrdiff_t) node2->content);
183 if (l1 < l2)
184 return(1);
185 if (l1 > l2)
186 return(-1);
187 } else
188 goto turtle_comparison;
189 }
190 break;
191 case XML_ATTRIBUTE_NODE:
192 precedence1 = 1; /* element is owner */
193 miscNode1 = node1;
194 node1 = node1->parent;
195 misc = 1;
196 break;
197 case XML_TEXT_NODE:
198 case XML_CDATA_SECTION_NODE:
199 case XML_COMMENT_NODE:
200 case XML_PI_NODE: {
201 miscNode1 = node1;
202 /*
203 * Find nearest element node.
204 */
205 if (node1->prev != NULL) {
206 do {
207 node1 = node1->prev;
208 if (node1->type == XML_ELEMENT_NODE) {
209 precedence1 = 3; /* element in prev-sibl axis */
210 break;
211 }
212 if (node1->prev == NULL) {
213 precedence1 = 2; /* element is parent */
214 /*
215 * URGENT TODO: Are there any cases, where the
216 * parent of such a node is not an element node?
217 */
218 node1 = node1->parent;
219 break;
220 }
221 } while (1);
222 } else {
223 precedence1 = 2; /* element is parent */
224 node1 = node1->parent;
225 }
226 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
227 (0 <= (ptrdiff_t) node1->content)) {
228 /*
229 * Fallback for whatever case.
230 */
231 node1 = miscNode1;
232 precedence1 = 0;
233 } else
234 misc = 1;
235 }
236 break;
237 case XML_NAMESPACE_DECL:
238 /*
239 * TODO: why do we return 1 for namespace nodes?
240 */
241 return(1);
242 default:
243 break;
244 }
245 switch (node2->type) {
246 case XML_ELEMENT_NODE:
247 break;
248 case XML_ATTRIBUTE_NODE:
249 precedence2 = 1; /* element is owner */
250 miscNode2 = node2;
251 node2 = node2->parent;
252 misc = 1;
253 break;
254 case XML_TEXT_NODE:
255 case XML_CDATA_SECTION_NODE:
256 case XML_COMMENT_NODE:
257 case XML_PI_NODE: {
258 miscNode2 = node2;
259 if (node2->prev != NULL) {
260 do {
261 node2 = node2->prev;
262 if (node2->type == XML_ELEMENT_NODE) {
263 precedence2 = 3; /* element in prev-sibl axis */
264 break;
265 }
266 if (node2->prev == NULL) {
267 precedence2 = 2; /* element is parent */
268 node2 = node2->parent;
269 break;
270 }
271 } while (1);
272 } else {
273 precedence2 = 2; /* element is parent */
274 node2 = node2->parent;
275 }
276 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
277 (0 <= (ptrdiff_t) node2->content))
278 {
279 node2 = miscNode2;
280 precedence2 = 0;
281 } else
282 misc = 1;
283 }
284 break;
285 case XML_NAMESPACE_DECL:
286 return(1);
287 default:
288 break;
289 }
290 if (misc) {
291 if (node1 == node2) {
292 if (precedence1 == precedence2) {
293 /*
294 * The ugly case; but normally there aren't many
295 * adjacent non-element nodes around.
296 */
297 cur = miscNode2->prev;
298 while (cur != NULL) {
299 if (cur == miscNode1)
300 return(1);
301 if (cur->type == XML_ELEMENT_NODE)
302 return(-1);
303 cur = cur->prev;
304 }
305 return (-1);
306 } else {
307 /*
308 * Evaluate based on higher precedence wrt to the element.
309 * TODO: This assumes attributes are sorted before content.
310 * Is this 100% correct?
311 */
312 if (precedence1 < precedence2)
313 return(1);
314 else
315 return(-1);
316 }
317 }
318 /*
319 * Special case: One of the helper-elements is contained by the other.
320 * <foo>
321 * <node2>
322 * <node1>Text-1(precedence1 == 2)</node1>
323 * </node2>
324 * Text-6(precedence2 == 3)
325 * </foo>
326 */
327 if ((precedence2 == 3) && (precedence1 > 1)) {
328 cur = node1->parent;
329 while (cur) {
330 if (cur == node2)
331 return(1);
332 cur = cur->parent;
333 }
334 }
335 if ((precedence1 == 3) && (precedence2 > 1)) {
336 cur = node2->parent;
337 while (cur) {
338 if (cur == node1)
339 return(-1);
340 cur = cur->parent;
341 }
342 }
343 }
344
345 /*
346 * Speedup using document order if available.
347 */
348 if ((node1->type == XML_ELEMENT_NODE) &&
349 (node2->type == XML_ELEMENT_NODE) &&
350 (0 > (ptrdiff_t) node1->content) &&
351 (0 > (ptrdiff_t) node2->content) &&
352 (node1->doc == node2->doc)) {
353
354 l1 = -((ptrdiff_t) node1->content);
355 l2 = -((ptrdiff_t) node2->content);
356 if (l1 < l2)
357 return(1);
358 if (l1 > l2)
359 return(-1);
360 }
361
362 turtle_comparison:
363
364 if (node1 == node2->prev)
365 return(1);
366 if (node1 == node2->next)
367 return(-1);
368 /*
369 * compute depth to root
370 */
371 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372 if (cur->parent == node1)
373 return(1);
374 depth2++;
375 }
376 root = cur;
377 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378 if (cur->parent == node2)
379 return(-1);
380 depth1++;
381 }
382 /*
383 * Distinct document (or distinct entities :-( ) case.
384 */
385 if (root != cur) {
386 return(-2);
387 }
388 /*
389 * get the nearest common ancestor.
390 */
391 while (depth1 > depth2) {
392 depth1--;
393 node1 = node1->parent;
394 }
395 while (depth2 > depth1) {
396 depth2--;
397 node2 = node2->parent;
398 }
399 while (node1->parent != node2->parent) {
400 node1 = node1->parent;
401 node2 = node2->parent;
402 /* should not happen but just in case ... */
403 if ((node1 == NULL) || (node2 == NULL))
404 return(-2);
405 }
406 /*
407 * Find who's first.
408 */
409 if (node1 == node2->prev)
410 return(1);
411 if (node1 == node2->next)
412 return(-1);
413 /*
414 * Speedup using document order if available.
415 */
416 if ((node1->type == XML_ELEMENT_NODE) &&
417 (node2->type == XML_ELEMENT_NODE) &&
418 (0 > (ptrdiff_t) node1->content) &&
419 (0 > (ptrdiff_t) node2->content) &&
420 (node1->doc == node2->doc)) {
421
422 l1 = -((ptrdiff_t) node1->content);
423 l2 = -((ptrdiff_t) node2->content);
424 if (l1 < l2)
425 return(1);
426 if (l1 > l2)
427 return(-1);
428 }
429
430 for (cur = node1->next;cur != NULL;cur = cur->next)
431 if (cur == node2)
432 return(1);
433 return(-1); /* assume there is no sibling list corruption */
434 }
435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436
437 /*
438 * Wrapper for the Timsort algorithm from timsort.h
439 */
440 #ifdef WITH_TIM_SORT
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
443 /**
444 * wrap_cmp:
445 * @x: a node
446 * @y: another node
447 *
448 * Comparison function for the Timsort implementation
449 *
450 * Returns -2 in case of error -1 if first point < second point, 0 if
451 * it's the same node, +1 otherwise
452 */
453 static
454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457 {
458 int res = xmlXPathCmpNodesExt(x, y);
459 return res == -2 ? res : -res;
460 }
461 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)462 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463 {
464 int res = xmlXPathCmpNodes(x, y);
465 return res == -2 ? res : -res;
466 }
467 #endif
468 #define SORT_CMP(x, y) (wrap_cmp(x, y))
469 #include "timsort.h"
470 #endif /* WITH_TIM_SORT */
471
472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
473
474 /************************************************************************
475 * *
476 * Floating point stuff *
477 * *
478 ************************************************************************/
479
480 #ifndef INFINITY
481 #define INFINITY (DBL_MAX * DBL_MAX)
482 #endif
483
484 #ifndef NAN
485 #define NAN (INFINITY / INFINITY)
486 #endif
487
488 double xmlXPathNAN;
489 double xmlXPathPINF;
490 double xmlXPathNINF;
491
492 /**
493 * xmlXPathInit:
494 *
495 * Initialize the XPath environment
496 */
497 void
xmlXPathInit(void)498 xmlXPathInit(void) {
499 xmlXPathNAN = NAN;
500 xmlXPathPINF = INFINITY;
501 xmlXPathNINF = -INFINITY;
502 }
503
504 /**
505 * xmlXPathIsNaN:
506 * @val: a double value
507 *
508 * Returns 1 if the value is a NaN, 0 otherwise
509 */
510 int
xmlXPathIsNaN(double val)511 xmlXPathIsNaN(double val) {
512 #ifdef isnan
513 return isnan(val);
514 #else
515 return !(val == val);
516 #endif
517 }
518
519 /**
520 * xmlXPathIsInf:
521 * @val: a double value
522 *
523 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
524 */
525 int
xmlXPathIsInf(double val)526 xmlXPathIsInf(double val) {
527 #ifdef isinf
528 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
529 #else
530 if (val >= INFINITY)
531 return 1;
532 if (val <= -INFINITY)
533 return -1;
534 return 0;
535 #endif
536 }
537
538 #endif /* SCHEMAS or XPATH */
539
540 #ifdef LIBXML_XPATH_ENABLED
541
542 /*
543 * TODO: when compatibility allows remove all "fake node libxslt" strings
544 * the test should just be name[0] = ' '
545 */
546 #ifdef DEBUG_XPATH_EXPRESSION
547 #define DEBUG_STEP
548 #define DEBUG_EXPR
549 #define DEBUG_EVAL_COUNTS
550 #endif
551
552 static xmlNs xmlXPathXMLNamespaceStruct = {
553 NULL,
554 XML_NAMESPACE_DECL,
555 XML_XML_NAMESPACE,
556 BAD_CAST "xml",
557 NULL,
558 NULL
559 };
560 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
561 #ifndef LIBXML_THREAD_ENABLED
562 /*
563 * Optimizer is disabled only when threaded apps are detected while
564 * the library ain't compiled for thread safety.
565 */
566 static int xmlXPathDisableOptimizer = 0;
567 #endif
568
569 /************************************************************************
570 * *
571 * Error handling routines *
572 * *
573 ************************************************************************/
574
575 /**
576 * XP_ERRORNULL:
577 * @X: the error code
578 *
579 * Macro to raise an XPath error and return NULL.
580 */
581 #define XP_ERRORNULL(X) \
582 { xmlXPathErr(ctxt, X); return(NULL); }
583
584 /*
585 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
586 */
587 static const char *xmlXPathErrorMessages[] = {
588 "Ok\n",
589 "Number encoding\n",
590 "Unfinished literal\n",
591 "Start of literal\n",
592 "Expected $ for variable reference\n",
593 "Undefined variable\n",
594 "Invalid predicate\n",
595 "Invalid expression\n",
596 "Missing closing curly brace\n",
597 "Unregistered function\n",
598 "Invalid operand\n",
599 "Invalid type\n",
600 "Invalid number of arguments\n",
601 "Invalid context size\n",
602 "Invalid context position\n",
603 "Memory allocation error\n",
604 "Syntax error\n",
605 "Resource error\n",
606 "Sub resource error\n",
607 "Undefined namespace prefix\n",
608 "Encoding error\n",
609 "Char out of XML range\n",
610 "Invalid or incomplete context\n",
611 "Stack usage error\n",
612 "Forbidden variable\n",
613 "Operation limit exceeded\n",
614 "Recursion limit exceeded\n",
615 "?? Unknown error ??\n" /* Must be last in the list! */
616 };
617 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
618 sizeof(xmlXPathErrorMessages[0])) - 1)
619 /**
620 * xmlXPathErrMemory:
621 * @ctxt: an XPath context
622 * @extra: extra informations
623 *
624 * Handle a redefinition of attribute error
625 */
626 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)627 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
628 {
629 if (ctxt != NULL) {
630 xmlResetError(&ctxt->lastError);
631 if (extra) {
632 xmlChar buf[200];
633
634 xmlStrPrintf(buf, 200,
635 "Memory allocation failed : %s\n",
636 extra);
637 ctxt->lastError.message = (char *) xmlStrdup(buf);
638 } else {
639 ctxt->lastError.message = (char *)
640 xmlStrdup(BAD_CAST "Memory allocation failed\n");
641 }
642 ctxt->lastError.domain = XML_FROM_XPATH;
643 ctxt->lastError.code = XML_ERR_NO_MEMORY;
644 if (ctxt->error != NULL)
645 ctxt->error(ctxt->userData, &ctxt->lastError);
646 } else {
647 if (extra)
648 __xmlRaiseError(NULL, NULL, NULL,
649 NULL, NULL, XML_FROM_XPATH,
650 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
651 extra, NULL, NULL, 0, 0,
652 "Memory allocation failed : %s\n", extra);
653 else
654 __xmlRaiseError(NULL, NULL, NULL,
655 NULL, NULL, XML_FROM_XPATH,
656 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
657 NULL, NULL, NULL, 0, 0,
658 "Memory allocation failed\n");
659 }
660 }
661
662 /**
663 * xmlXPathPErrMemory:
664 * @ctxt: an XPath parser context
665 * @extra: extra informations
666 *
667 * Handle a redefinition of attribute error
668 */
669 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)670 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
671 {
672 if (ctxt == NULL)
673 xmlXPathErrMemory(NULL, extra);
674 else {
675 ctxt->error = XPATH_MEMORY_ERROR;
676 xmlXPathErrMemory(ctxt->context, extra);
677 }
678 }
679
680 /**
681 * xmlXPathErr:
682 * @ctxt: a XPath parser context
683 * @error: the error code
684 *
685 * Handle an XPath error
686 */
687 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)688 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
689 {
690 if ((error < 0) || (error > MAXERRNO))
691 error = MAXERRNO;
692 if (ctxt == NULL) {
693 __xmlRaiseError(NULL, NULL, NULL,
694 NULL, NULL, XML_FROM_XPATH,
695 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
696 XML_ERR_ERROR, NULL, 0,
697 NULL, NULL, NULL, 0, 0,
698 "%s", xmlXPathErrorMessages[error]);
699 return;
700 }
701 ctxt->error = error;
702 if (ctxt->context == NULL) {
703 __xmlRaiseError(NULL, NULL, NULL,
704 NULL, NULL, XML_FROM_XPATH,
705 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
706 XML_ERR_ERROR, NULL, 0,
707 (const char *) ctxt->base, NULL, NULL,
708 ctxt->cur - ctxt->base, 0,
709 "%s", xmlXPathErrorMessages[error]);
710 return;
711 }
712
713 /* cleanup current last error */
714 xmlResetError(&ctxt->context->lastError);
715
716 ctxt->context->lastError.domain = XML_FROM_XPATH;
717 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
718 XPATH_EXPRESSION_OK;
719 ctxt->context->lastError.level = XML_ERR_ERROR;
720 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
721 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
722 ctxt->context->lastError.node = ctxt->context->debugNode;
723 if (ctxt->context->error != NULL) {
724 ctxt->context->error(ctxt->context->userData,
725 &ctxt->context->lastError);
726 } else {
727 __xmlRaiseError(NULL, NULL, NULL,
728 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
729 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
730 XML_ERR_ERROR, NULL, 0,
731 (const char *) ctxt->base, NULL, NULL,
732 ctxt->cur - ctxt->base, 0,
733 "%s", xmlXPathErrorMessages[error]);
734 }
735
736 }
737
738 /**
739 * xmlXPatherror:
740 * @ctxt: the XPath Parser context
741 * @file: the file name
742 * @line: the line number
743 * @no: the error number
744 *
745 * Formats an error message.
746 */
747 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)748 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
749 int line ATTRIBUTE_UNUSED, int no) {
750 xmlXPathErr(ctxt, no);
751 }
752
753 /**
754 * xmlXPathCheckOpLimit:
755 * @ctxt: the XPath Parser context
756 * @opCount: the number of operations to be added
757 *
758 * Adds opCount to the running total of operations and returns -1 if the
759 * operation limit is exceeded. Returns 0 otherwise.
760 */
761 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)762 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
763 xmlXPathContextPtr xpctxt = ctxt->context;
764
765 if ((opCount > xpctxt->opLimit) ||
766 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
767 xpctxt->opCount = xpctxt->opLimit;
768 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
769 return(-1);
770 }
771
772 xpctxt->opCount += opCount;
773 return(0);
774 }
775
776 #define OP_LIMIT_EXCEEDED(ctxt, n) \
777 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
778
779 /************************************************************************
780 * *
781 * Utilities *
782 * *
783 ************************************************************************/
784
785 /**
786 * xsltPointerList:
787 *
788 * Pointer-list for various purposes.
789 */
790 typedef struct _xmlPointerList xmlPointerList;
791 typedef xmlPointerList *xmlPointerListPtr;
792 struct _xmlPointerList {
793 void **items;
794 int number;
795 int size;
796 };
797 /*
798 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
799 * and here, we should make the functions public.
800 */
801 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)802 xmlPointerListAddSize(xmlPointerListPtr list,
803 void *item,
804 int initialSize)
805 {
806 if (list->items == NULL) {
807 if (initialSize <= 0)
808 initialSize = 1;
809 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
810 if (list->items == NULL) {
811 xmlXPathErrMemory(NULL,
812 "xmlPointerListCreate: allocating item\n");
813 return(-1);
814 }
815 list->number = 0;
816 list->size = initialSize;
817 } else if (list->size <= list->number) {
818 if (list->size > 50000000) {
819 xmlXPathErrMemory(NULL,
820 "xmlPointerListAddSize: re-allocating item\n");
821 return(-1);
822 }
823 list->size *= 2;
824 list->items = (void **) xmlRealloc(list->items,
825 list->size * sizeof(void *));
826 if (list->items == NULL) {
827 xmlXPathErrMemory(NULL,
828 "xmlPointerListAddSize: re-allocating item\n");
829 list->size = 0;
830 return(-1);
831 }
832 }
833 list->items[list->number++] = item;
834 return(0);
835 }
836
837 /**
838 * xsltPointerListCreate:
839 *
840 * Creates an xsltPointerList structure.
841 *
842 * Returns a xsltPointerList structure or NULL in case of an error.
843 */
844 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)845 xmlPointerListCreate(int initialSize)
846 {
847 xmlPointerListPtr ret;
848
849 ret = xmlMalloc(sizeof(xmlPointerList));
850 if (ret == NULL) {
851 xmlXPathErrMemory(NULL,
852 "xmlPointerListCreate: allocating item\n");
853 return (NULL);
854 }
855 memset(ret, 0, sizeof(xmlPointerList));
856 if (initialSize > 0) {
857 xmlPointerListAddSize(ret, NULL, initialSize);
858 ret->number = 0;
859 }
860 return (ret);
861 }
862
863 /**
864 * xsltPointerListFree:
865 *
866 * Frees the xsltPointerList structure. This does not free
867 * the content of the list.
868 */
869 static void
xmlPointerListFree(xmlPointerListPtr list)870 xmlPointerListFree(xmlPointerListPtr list)
871 {
872 if (list == NULL)
873 return;
874 if (list->items != NULL)
875 xmlFree(list->items);
876 xmlFree(list);
877 }
878
879 /************************************************************************
880 * *
881 * Parser Types *
882 * *
883 ************************************************************************/
884
885 /*
886 * Types are private:
887 */
888
889 typedef enum {
890 XPATH_OP_END=0,
891 XPATH_OP_AND,
892 XPATH_OP_OR,
893 XPATH_OP_EQUAL,
894 XPATH_OP_CMP,
895 XPATH_OP_PLUS,
896 XPATH_OP_MULT,
897 XPATH_OP_UNION,
898 XPATH_OP_ROOT,
899 XPATH_OP_NODE,
900 XPATH_OP_COLLECT,
901 XPATH_OP_VALUE, /* 11 */
902 XPATH_OP_VARIABLE,
903 XPATH_OP_FUNCTION,
904 XPATH_OP_ARG,
905 XPATH_OP_PREDICATE,
906 XPATH_OP_FILTER, /* 16 */
907 XPATH_OP_SORT /* 17 */
908 #ifdef LIBXML_XPTR_ENABLED
909 ,XPATH_OP_RANGETO
910 #endif
911 } xmlXPathOp;
912
913 typedef enum {
914 AXIS_ANCESTOR = 1,
915 AXIS_ANCESTOR_OR_SELF,
916 AXIS_ATTRIBUTE,
917 AXIS_CHILD,
918 AXIS_DESCENDANT,
919 AXIS_DESCENDANT_OR_SELF,
920 AXIS_FOLLOWING,
921 AXIS_FOLLOWING_SIBLING,
922 AXIS_NAMESPACE,
923 AXIS_PARENT,
924 AXIS_PRECEDING,
925 AXIS_PRECEDING_SIBLING,
926 AXIS_SELF
927 } xmlXPathAxisVal;
928
929 typedef enum {
930 NODE_TEST_NONE = 0,
931 NODE_TEST_TYPE = 1,
932 NODE_TEST_PI = 2,
933 NODE_TEST_ALL = 3,
934 NODE_TEST_NS = 4,
935 NODE_TEST_NAME = 5
936 } xmlXPathTestVal;
937
938 typedef enum {
939 NODE_TYPE_NODE = 0,
940 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
941 NODE_TYPE_TEXT = XML_TEXT_NODE,
942 NODE_TYPE_PI = XML_PI_NODE
943 } xmlXPathTypeVal;
944
945 typedef struct _xmlXPathStepOp xmlXPathStepOp;
946 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
947 struct _xmlXPathStepOp {
948 xmlXPathOp op; /* The identifier of the operation */
949 int ch1; /* First child */
950 int ch2; /* Second child */
951 int value;
952 int value2;
953 int value3;
954 void *value4;
955 void *value5;
956 xmlXPathFunction cache;
957 void *cacheURI;
958 };
959
960 struct _xmlXPathCompExpr {
961 int nbStep; /* Number of steps in this expression */
962 int maxStep; /* Maximum number of steps allocated */
963 xmlXPathStepOp *steps; /* ops for computation of this expression */
964 int last; /* index of last step in expression */
965 xmlChar *expr; /* the expression being computed */
966 xmlDictPtr dict; /* the dictionary to use if any */
967 #ifdef DEBUG_EVAL_COUNTS
968 int nb;
969 xmlChar *string;
970 #endif
971 #ifdef XPATH_STREAMING
972 xmlPatternPtr stream;
973 #endif
974 };
975
976 /************************************************************************
977 * *
978 * Forward declarations *
979 * *
980 ************************************************************************/
981 static void
982 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
983 static void
984 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
985 static int
986 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
987 xmlXPathStepOpPtr op, xmlNodePtr *first);
988 static int
989 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
990 xmlXPathStepOpPtr op,
991 int isPredicate);
992 static void
993 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
994
995 /************************************************************************
996 * *
997 * Parser Type functions *
998 * *
999 ************************************************************************/
1000
1001 /**
1002 * xmlXPathNewCompExpr:
1003 *
1004 * Create a new Xpath component
1005 *
1006 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1007 */
1008 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)1009 xmlXPathNewCompExpr(void) {
1010 xmlXPathCompExprPtr cur;
1011
1012 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1013 if (cur == NULL) {
1014 xmlXPathErrMemory(NULL, "allocating component\n");
1015 return(NULL);
1016 }
1017 memset(cur, 0, sizeof(xmlXPathCompExpr));
1018 cur->maxStep = 10;
1019 cur->nbStep = 0;
1020 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1021 sizeof(xmlXPathStepOp));
1022 if (cur->steps == NULL) {
1023 xmlXPathErrMemory(NULL, "allocating steps\n");
1024 xmlFree(cur);
1025 return(NULL);
1026 }
1027 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1028 cur->last = -1;
1029 #ifdef DEBUG_EVAL_COUNTS
1030 cur->nb = 0;
1031 #endif
1032 return(cur);
1033 }
1034
1035 /**
1036 * xmlXPathFreeCompExpr:
1037 * @comp: an XPATH comp
1038 *
1039 * Free up the memory allocated by @comp
1040 */
1041 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1042 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1043 {
1044 xmlXPathStepOpPtr op;
1045 int i;
1046
1047 if (comp == NULL)
1048 return;
1049 if (comp->dict == NULL) {
1050 for (i = 0; i < comp->nbStep; i++) {
1051 op = &comp->steps[i];
1052 if (op->value4 != NULL) {
1053 if (op->op == XPATH_OP_VALUE)
1054 xmlXPathFreeObject(op->value4);
1055 else
1056 xmlFree(op->value4);
1057 }
1058 if (op->value5 != NULL)
1059 xmlFree(op->value5);
1060 }
1061 } else {
1062 for (i = 0; i < comp->nbStep; i++) {
1063 op = &comp->steps[i];
1064 if (op->value4 != NULL) {
1065 if (op->op == XPATH_OP_VALUE)
1066 xmlXPathFreeObject(op->value4);
1067 }
1068 }
1069 xmlDictFree(comp->dict);
1070 }
1071 if (comp->steps != NULL) {
1072 xmlFree(comp->steps);
1073 }
1074 #ifdef DEBUG_EVAL_COUNTS
1075 if (comp->string != NULL) {
1076 xmlFree(comp->string);
1077 }
1078 #endif
1079 #ifdef XPATH_STREAMING
1080 if (comp->stream != NULL) {
1081 xmlFreePatternList(comp->stream);
1082 }
1083 #endif
1084 if (comp->expr != NULL) {
1085 xmlFree(comp->expr);
1086 }
1087
1088 xmlFree(comp);
1089 }
1090
1091 /**
1092 * xmlXPathCompExprAdd:
1093 * @comp: the compiled expression
1094 * @ch1: first child index
1095 * @ch2: second child index
1096 * @op: an op
1097 * @value: the first int value
1098 * @value2: the second int value
1099 * @value3: the third int value
1100 * @value4: the first string value
1101 * @value5: the second string value
1102 *
1103 * Add a step to an XPath Compiled Expression
1104 *
1105 * Returns -1 in case of failure, the index otherwise
1106 */
1107 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1108 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1109 xmlXPathOp op, int value,
1110 int value2, int value3, void *value4, void *value5) {
1111 xmlXPathCompExprPtr comp = ctxt->comp;
1112 if (comp->nbStep >= comp->maxStep) {
1113 xmlXPathStepOp *real;
1114
1115 if (comp->maxStep >= XPATH_MAX_STEPS) {
1116 xmlXPathPErrMemory(ctxt, "adding step\n");
1117 return(-1);
1118 }
1119 comp->maxStep *= 2;
1120 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1121 comp->maxStep * sizeof(xmlXPathStepOp));
1122 if (real == NULL) {
1123 comp->maxStep /= 2;
1124 xmlXPathPErrMemory(ctxt, "adding step\n");
1125 return(-1);
1126 }
1127 comp->steps = real;
1128 }
1129 comp->last = comp->nbStep;
1130 comp->steps[comp->nbStep].ch1 = ch1;
1131 comp->steps[comp->nbStep].ch2 = ch2;
1132 comp->steps[comp->nbStep].op = op;
1133 comp->steps[comp->nbStep].value = value;
1134 comp->steps[comp->nbStep].value2 = value2;
1135 comp->steps[comp->nbStep].value3 = value3;
1136 if ((comp->dict != NULL) &&
1137 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1138 (op == XPATH_OP_COLLECT))) {
1139 if (value4 != NULL) {
1140 comp->steps[comp->nbStep].value4 = (xmlChar *)
1141 (void *)xmlDictLookup(comp->dict, value4, -1);
1142 xmlFree(value4);
1143 } else
1144 comp->steps[comp->nbStep].value4 = NULL;
1145 if (value5 != NULL) {
1146 comp->steps[comp->nbStep].value5 = (xmlChar *)
1147 (void *)xmlDictLookup(comp->dict, value5, -1);
1148 xmlFree(value5);
1149 } else
1150 comp->steps[comp->nbStep].value5 = NULL;
1151 } else {
1152 comp->steps[comp->nbStep].value4 = value4;
1153 comp->steps[comp->nbStep].value5 = value5;
1154 }
1155 comp->steps[comp->nbStep].cache = NULL;
1156 return(comp->nbStep++);
1157 }
1158
1159 /**
1160 * xmlXPathCompSwap:
1161 * @comp: the compiled expression
1162 * @op: operation index
1163 *
1164 * Swaps 2 operations in the compiled expression
1165 */
1166 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1167 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1168 int tmp;
1169
1170 #ifndef LIBXML_THREAD_ENABLED
1171 /*
1172 * Since this manipulates possibly shared variables, this is
1173 * disabled if one detects that the library is used in a multithreaded
1174 * application
1175 */
1176 if (xmlXPathDisableOptimizer)
1177 return;
1178 #endif
1179
1180 tmp = op->ch1;
1181 op->ch1 = op->ch2;
1182 op->ch2 = tmp;
1183 }
1184
1185 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1186 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1187 (op), (val), (val2), (val3), (val4), (val5))
1188 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1189 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1190 (op), (val), (val2), (val3), (val4), (val5))
1191
1192 #define PUSH_LEAVE_EXPR(op, val, val2) \
1193 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1194
1195 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1196 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1197
1198 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1199 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1200 (val), (val2), 0 ,NULL ,NULL)
1201
1202 /************************************************************************
1203 * *
1204 * XPath object cache structures *
1205 * *
1206 ************************************************************************/
1207
1208 /* #define XP_DEFAULT_CACHE_ON */
1209
1210 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1211
1212 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1213 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1214 struct _xmlXPathContextCache {
1215 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1216 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1217 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1218 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1219 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1220 int maxNodeset;
1221 int maxString;
1222 int maxBoolean;
1223 int maxNumber;
1224 int maxMisc;
1225 #ifdef XP_DEBUG_OBJ_USAGE
1226 int dbgCachedAll;
1227 int dbgCachedNodeset;
1228 int dbgCachedString;
1229 int dbgCachedBool;
1230 int dbgCachedNumber;
1231 int dbgCachedPoint;
1232 int dbgCachedRange;
1233 int dbgCachedLocset;
1234 int dbgCachedUsers;
1235 int dbgCachedXSLTTree;
1236 int dbgCachedUndefined;
1237
1238
1239 int dbgReusedAll;
1240 int dbgReusedNodeset;
1241 int dbgReusedString;
1242 int dbgReusedBool;
1243 int dbgReusedNumber;
1244 int dbgReusedPoint;
1245 int dbgReusedRange;
1246 int dbgReusedLocset;
1247 int dbgReusedUsers;
1248 int dbgReusedXSLTTree;
1249 int dbgReusedUndefined;
1250
1251 #endif
1252 };
1253
1254 /************************************************************************
1255 * *
1256 * Debugging related functions *
1257 * *
1258 ************************************************************************/
1259
1260 #define STRANGE \
1261 xmlGenericError(xmlGenericErrorContext, \
1262 "Internal error at %s:%d\n", \
1263 __FILE__, __LINE__);
1264
1265 #ifdef LIBXML_DEBUG_ENABLED
1266 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1267 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1268 int i;
1269 char shift[100];
1270
1271 for (i = 0;((i < depth) && (i < 25));i++)
1272 shift[2 * i] = shift[2 * i + 1] = ' ';
1273 shift[2 * i] = shift[2 * i + 1] = 0;
1274 if (cur == NULL) {
1275 fprintf(output, "%s", shift);
1276 fprintf(output, "Node is NULL !\n");
1277 return;
1278
1279 }
1280
1281 if ((cur->type == XML_DOCUMENT_NODE) ||
1282 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1283 fprintf(output, "%s", shift);
1284 fprintf(output, " /\n");
1285 } else if (cur->type == XML_ATTRIBUTE_NODE)
1286 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1287 else
1288 xmlDebugDumpOneNode(output, cur, depth);
1289 }
1290 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1291 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1292 xmlNodePtr tmp;
1293 int i;
1294 char shift[100];
1295
1296 for (i = 0;((i < depth) && (i < 25));i++)
1297 shift[2 * i] = shift[2 * i + 1] = ' ';
1298 shift[2 * i] = shift[2 * i + 1] = 0;
1299 if (cur == NULL) {
1300 fprintf(output, "%s", shift);
1301 fprintf(output, "Node is NULL !\n");
1302 return;
1303
1304 }
1305
1306 while (cur != NULL) {
1307 tmp = cur;
1308 cur = cur->next;
1309 xmlDebugDumpOneNode(output, tmp, depth);
1310 }
1311 }
1312
1313 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1314 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1315 int i;
1316 char shift[100];
1317
1318 for (i = 0;((i < depth) && (i < 25));i++)
1319 shift[2 * i] = shift[2 * i + 1] = ' ';
1320 shift[2 * i] = shift[2 * i + 1] = 0;
1321
1322 if (cur == NULL) {
1323 fprintf(output, "%s", shift);
1324 fprintf(output, "NodeSet is NULL !\n");
1325 return;
1326
1327 }
1328
1329 if (cur != NULL) {
1330 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1331 for (i = 0;i < cur->nodeNr;i++) {
1332 fprintf(output, "%s", shift);
1333 fprintf(output, "%d", i + 1);
1334 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1335 }
1336 }
1337 }
1338
1339 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1340 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1341 int i;
1342 char shift[100];
1343
1344 for (i = 0;((i < depth) && (i < 25));i++)
1345 shift[2 * i] = shift[2 * i + 1] = ' ';
1346 shift[2 * i] = shift[2 * i + 1] = 0;
1347
1348 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1349 fprintf(output, "%s", shift);
1350 fprintf(output, "Value Tree is NULL !\n");
1351 return;
1352
1353 }
1354
1355 fprintf(output, "%s", shift);
1356 fprintf(output, "%d", i + 1);
1357 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1358 }
1359 #if defined(LIBXML_XPTR_ENABLED)
1360 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1361 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1362 int i;
1363 char shift[100];
1364
1365 for (i = 0;((i < depth) && (i < 25));i++)
1366 shift[2 * i] = shift[2 * i + 1] = ' ';
1367 shift[2 * i] = shift[2 * i + 1] = 0;
1368
1369 if (cur == NULL) {
1370 fprintf(output, "%s", shift);
1371 fprintf(output, "LocationSet is NULL !\n");
1372 return;
1373
1374 }
1375
1376 for (i = 0;i < cur->locNr;i++) {
1377 fprintf(output, "%s", shift);
1378 fprintf(output, "%d : ", i + 1);
1379 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1380 }
1381 }
1382 #endif /* LIBXML_XPTR_ENABLED */
1383
1384 /**
1385 * xmlXPathDebugDumpObject:
1386 * @output: the FILE * to dump the output
1387 * @cur: the object to inspect
1388 * @depth: indentation level
1389 *
1390 * Dump the content of the object for debugging purposes
1391 */
1392 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1393 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1394 int i;
1395 char shift[100];
1396
1397 if (output == NULL) return;
1398
1399 for (i = 0;((i < depth) && (i < 25));i++)
1400 shift[2 * i] = shift[2 * i + 1] = ' ';
1401 shift[2 * i] = shift[2 * i + 1] = 0;
1402
1403
1404 fprintf(output, "%s", shift);
1405
1406 if (cur == NULL) {
1407 fprintf(output, "Object is empty (NULL)\n");
1408 return;
1409 }
1410 switch(cur->type) {
1411 case XPATH_UNDEFINED:
1412 fprintf(output, "Object is uninitialized\n");
1413 break;
1414 case XPATH_NODESET:
1415 fprintf(output, "Object is a Node Set :\n");
1416 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1417 break;
1418 case XPATH_XSLT_TREE:
1419 fprintf(output, "Object is an XSLT value tree :\n");
1420 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1421 break;
1422 case XPATH_BOOLEAN:
1423 fprintf(output, "Object is a Boolean : ");
1424 if (cur->boolval) fprintf(output, "true\n");
1425 else fprintf(output, "false\n");
1426 break;
1427 case XPATH_NUMBER:
1428 switch (xmlXPathIsInf(cur->floatval)) {
1429 case 1:
1430 fprintf(output, "Object is a number : Infinity\n");
1431 break;
1432 case -1:
1433 fprintf(output, "Object is a number : -Infinity\n");
1434 break;
1435 default:
1436 if (xmlXPathIsNaN(cur->floatval)) {
1437 fprintf(output, "Object is a number : NaN\n");
1438 } else if (cur->floatval == 0) {
1439 /* Omit sign for negative zero. */
1440 fprintf(output, "Object is a number : 0\n");
1441 } else {
1442 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1443 }
1444 }
1445 break;
1446 case XPATH_STRING:
1447 fprintf(output, "Object is a string : ");
1448 xmlDebugDumpString(output, cur->stringval);
1449 fprintf(output, "\n");
1450 break;
1451 case XPATH_POINT:
1452 fprintf(output, "Object is a point : index %d in node", cur->index);
1453 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1454 fprintf(output, "\n");
1455 break;
1456 case XPATH_RANGE:
1457 if ((cur->user2 == NULL) ||
1458 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1459 fprintf(output, "Object is a collapsed range :\n");
1460 fprintf(output, "%s", shift);
1461 if (cur->index >= 0)
1462 fprintf(output, "index %d in ", cur->index);
1463 fprintf(output, "node\n");
1464 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1465 depth + 1);
1466 } else {
1467 fprintf(output, "Object is a range :\n");
1468 fprintf(output, "%s", shift);
1469 fprintf(output, "From ");
1470 if (cur->index >= 0)
1471 fprintf(output, "index %d in ", cur->index);
1472 fprintf(output, "node\n");
1473 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1474 depth + 1);
1475 fprintf(output, "%s", shift);
1476 fprintf(output, "To ");
1477 if (cur->index2 >= 0)
1478 fprintf(output, "index %d in ", cur->index2);
1479 fprintf(output, "node\n");
1480 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1481 depth + 1);
1482 fprintf(output, "\n");
1483 }
1484 break;
1485 case XPATH_LOCATIONSET:
1486 #if defined(LIBXML_XPTR_ENABLED)
1487 fprintf(output, "Object is a Location Set:\n");
1488 xmlXPathDebugDumpLocationSet(output,
1489 (xmlLocationSetPtr) cur->user, depth);
1490 #endif
1491 break;
1492 case XPATH_USERS:
1493 fprintf(output, "Object is user defined\n");
1494 break;
1495 }
1496 }
1497
1498 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1499 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1500 xmlXPathStepOpPtr op, int depth) {
1501 int i;
1502 char shift[100];
1503
1504 for (i = 0;((i < depth) && (i < 25));i++)
1505 shift[2 * i] = shift[2 * i + 1] = ' ';
1506 shift[2 * i] = shift[2 * i + 1] = 0;
1507
1508 fprintf(output, "%s", shift);
1509 if (op == NULL) {
1510 fprintf(output, "Step is NULL\n");
1511 return;
1512 }
1513 switch (op->op) {
1514 case XPATH_OP_END:
1515 fprintf(output, "END"); break;
1516 case XPATH_OP_AND:
1517 fprintf(output, "AND"); break;
1518 case XPATH_OP_OR:
1519 fprintf(output, "OR"); break;
1520 case XPATH_OP_EQUAL:
1521 if (op->value)
1522 fprintf(output, "EQUAL =");
1523 else
1524 fprintf(output, "EQUAL !=");
1525 break;
1526 case XPATH_OP_CMP:
1527 if (op->value)
1528 fprintf(output, "CMP <");
1529 else
1530 fprintf(output, "CMP >");
1531 if (!op->value2)
1532 fprintf(output, "=");
1533 break;
1534 case XPATH_OP_PLUS:
1535 if (op->value == 0)
1536 fprintf(output, "PLUS -");
1537 else if (op->value == 1)
1538 fprintf(output, "PLUS +");
1539 else if (op->value == 2)
1540 fprintf(output, "PLUS unary -");
1541 else if (op->value == 3)
1542 fprintf(output, "PLUS unary - -");
1543 break;
1544 case XPATH_OP_MULT:
1545 if (op->value == 0)
1546 fprintf(output, "MULT *");
1547 else if (op->value == 1)
1548 fprintf(output, "MULT div");
1549 else
1550 fprintf(output, "MULT mod");
1551 break;
1552 case XPATH_OP_UNION:
1553 fprintf(output, "UNION"); break;
1554 case XPATH_OP_ROOT:
1555 fprintf(output, "ROOT"); break;
1556 case XPATH_OP_NODE:
1557 fprintf(output, "NODE"); break;
1558 case XPATH_OP_SORT:
1559 fprintf(output, "SORT"); break;
1560 case XPATH_OP_COLLECT: {
1561 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1562 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1563 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1564 const xmlChar *prefix = op->value4;
1565 const xmlChar *name = op->value5;
1566
1567 fprintf(output, "COLLECT ");
1568 switch (axis) {
1569 case AXIS_ANCESTOR:
1570 fprintf(output, " 'ancestors' "); break;
1571 case AXIS_ANCESTOR_OR_SELF:
1572 fprintf(output, " 'ancestors-or-self' "); break;
1573 case AXIS_ATTRIBUTE:
1574 fprintf(output, " 'attributes' "); break;
1575 case AXIS_CHILD:
1576 fprintf(output, " 'child' "); break;
1577 case AXIS_DESCENDANT:
1578 fprintf(output, " 'descendant' "); break;
1579 case AXIS_DESCENDANT_OR_SELF:
1580 fprintf(output, " 'descendant-or-self' "); break;
1581 case AXIS_FOLLOWING:
1582 fprintf(output, " 'following' "); break;
1583 case AXIS_FOLLOWING_SIBLING:
1584 fprintf(output, " 'following-siblings' "); break;
1585 case AXIS_NAMESPACE:
1586 fprintf(output, " 'namespace' "); break;
1587 case AXIS_PARENT:
1588 fprintf(output, " 'parent' "); break;
1589 case AXIS_PRECEDING:
1590 fprintf(output, " 'preceding' "); break;
1591 case AXIS_PRECEDING_SIBLING:
1592 fprintf(output, " 'preceding-sibling' "); break;
1593 case AXIS_SELF:
1594 fprintf(output, " 'self' "); break;
1595 }
1596 switch (test) {
1597 case NODE_TEST_NONE:
1598 fprintf(output, "'none' "); break;
1599 case NODE_TEST_TYPE:
1600 fprintf(output, "'type' "); break;
1601 case NODE_TEST_PI:
1602 fprintf(output, "'PI' "); break;
1603 case NODE_TEST_ALL:
1604 fprintf(output, "'all' "); break;
1605 case NODE_TEST_NS:
1606 fprintf(output, "'namespace' "); break;
1607 case NODE_TEST_NAME:
1608 fprintf(output, "'name' "); break;
1609 }
1610 switch (type) {
1611 case NODE_TYPE_NODE:
1612 fprintf(output, "'node' "); break;
1613 case NODE_TYPE_COMMENT:
1614 fprintf(output, "'comment' "); break;
1615 case NODE_TYPE_TEXT:
1616 fprintf(output, "'text' "); break;
1617 case NODE_TYPE_PI:
1618 fprintf(output, "'PI' "); break;
1619 }
1620 if (prefix != NULL)
1621 fprintf(output, "%s:", prefix);
1622 if (name != NULL)
1623 fprintf(output, "%s", (const char *) name);
1624 break;
1625
1626 }
1627 case XPATH_OP_VALUE: {
1628 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1629
1630 fprintf(output, "ELEM ");
1631 xmlXPathDebugDumpObject(output, object, 0);
1632 goto finish;
1633 }
1634 case XPATH_OP_VARIABLE: {
1635 const xmlChar *prefix = op->value5;
1636 const xmlChar *name = op->value4;
1637
1638 if (prefix != NULL)
1639 fprintf(output, "VARIABLE %s:%s", prefix, name);
1640 else
1641 fprintf(output, "VARIABLE %s", name);
1642 break;
1643 }
1644 case XPATH_OP_FUNCTION: {
1645 int nbargs = op->value;
1646 const xmlChar *prefix = op->value5;
1647 const xmlChar *name = op->value4;
1648
1649 if (prefix != NULL)
1650 fprintf(output, "FUNCTION %s:%s(%d args)",
1651 prefix, name, nbargs);
1652 else
1653 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1654 break;
1655 }
1656 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1657 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1658 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1659 #ifdef LIBXML_XPTR_ENABLED
1660 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1661 #endif
1662 default:
1663 fprintf(output, "UNKNOWN %d\n", op->op); return;
1664 }
1665 fprintf(output, "\n");
1666 finish:
1667 if (op->ch1 >= 0)
1668 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1669 if (op->ch2 >= 0)
1670 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1671 }
1672
1673 /**
1674 * xmlXPathDebugDumpCompExpr:
1675 * @output: the FILE * for the output
1676 * @comp: the precompiled XPath expression
1677 * @depth: the indentation level.
1678 *
1679 * Dumps the tree of the compiled XPath expression.
1680 */
1681 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1682 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1683 int depth) {
1684 int i;
1685 char shift[100];
1686
1687 if ((output == NULL) || (comp == NULL)) return;
1688
1689 for (i = 0;((i < depth) && (i < 25));i++)
1690 shift[2 * i] = shift[2 * i + 1] = ' ';
1691 shift[2 * i] = shift[2 * i + 1] = 0;
1692
1693 fprintf(output, "%s", shift);
1694
1695 #ifdef XPATH_STREAMING
1696 if (comp->stream) {
1697 fprintf(output, "Streaming Expression\n");
1698 } else
1699 #endif
1700 {
1701 fprintf(output, "Compiled Expression : %d elements\n",
1702 comp->nbStep);
1703 i = comp->last;
1704 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1705 }
1706 }
1707
1708 #ifdef XP_DEBUG_OBJ_USAGE
1709
1710 /*
1711 * XPath object usage related debugging variables.
1712 */
1713 static int xmlXPathDebugObjCounterUndefined = 0;
1714 static int xmlXPathDebugObjCounterNodeset = 0;
1715 static int xmlXPathDebugObjCounterBool = 0;
1716 static int xmlXPathDebugObjCounterNumber = 0;
1717 static int xmlXPathDebugObjCounterString = 0;
1718 static int xmlXPathDebugObjCounterPoint = 0;
1719 static int xmlXPathDebugObjCounterRange = 0;
1720 static int xmlXPathDebugObjCounterLocset = 0;
1721 static int xmlXPathDebugObjCounterUsers = 0;
1722 static int xmlXPathDebugObjCounterXSLTTree = 0;
1723 static int xmlXPathDebugObjCounterAll = 0;
1724
1725 static int xmlXPathDebugObjTotalUndefined = 0;
1726 static int xmlXPathDebugObjTotalNodeset = 0;
1727 static int xmlXPathDebugObjTotalBool = 0;
1728 static int xmlXPathDebugObjTotalNumber = 0;
1729 static int xmlXPathDebugObjTotalString = 0;
1730 static int xmlXPathDebugObjTotalPoint = 0;
1731 static int xmlXPathDebugObjTotalRange = 0;
1732 static int xmlXPathDebugObjTotalLocset = 0;
1733 static int xmlXPathDebugObjTotalUsers = 0;
1734 static int xmlXPathDebugObjTotalXSLTTree = 0;
1735 static int xmlXPathDebugObjTotalAll = 0;
1736
1737 static int xmlXPathDebugObjMaxUndefined = 0;
1738 static int xmlXPathDebugObjMaxNodeset = 0;
1739 static int xmlXPathDebugObjMaxBool = 0;
1740 static int xmlXPathDebugObjMaxNumber = 0;
1741 static int xmlXPathDebugObjMaxString = 0;
1742 static int xmlXPathDebugObjMaxPoint = 0;
1743 static int xmlXPathDebugObjMaxRange = 0;
1744 static int xmlXPathDebugObjMaxLocset = 0;
1745 static int xmlXPathDebugObjMaxUsers = 0;
1746 static int xmlXPathDebugObjMaxXSLTTree = 0;
1747 static int xmlXPathDebugObjMaxAll = 0;
1748
1749 /* REVISIT TODO: Make this static when committing */
1750 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1751 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1752 {
1753 if (ctxt != NULL) {
1754 if (ctxt->cache != NULL) {
1755 xmlXPathContextCachePtr cache =
1756 (xmlXPathContextCachePtr) ctxt->cache;
1757
1758 cache->dbgCachedAll = 0;
1759 cache->dbgCachedNodeset = 0;
1760 cache->dbgCachedString = 0;
1761 cache->dbgCachedBool = 0;
1762 cache->dbgCachedNumber = 0;
1763 cache->dbgCachedPoint = 0;
1764 cache->dbgCachedRange = 0;
1765 cache->dbgCachedLocset = 0;
1766 cache->dbgCachedUsers = 0;
1767 cache->dbgCachedXSLTTree = 0;
1768 cache->dbgCachedUndefined = 0;
1769
1770 cache->dbgReusedAll = 0;
1771 cache->dbgReusedNodeset = 0;
1772 cache->dbgReusedString = 0;
1773 cache->dbgReusedBool = 0;
1774 cache->dbgReusedNumber = 0;
1775 cache->dbgReusedPoint = 0;
1776 cache->dbgReusedRange = 0;
1777 cache->dbgReusedLocset = 0;
1778 cache->dbgReusedUsers = 0;
1779 cache->dbgReusedXSLTTree = 0;
1780 cache->dbgReusedUndefined = 0;
1781 }
1782 }
1783
1784 xmlXPathDebugObjCounterUndefined = 0;
1785 xmlXPathDebugObjCounterNodeset = 0;
1786 xmlXPathDebugObjCounterBool = 0;
1787 xmlXPathDebugObjCounterNumber = 0;
1788 xmlXPathDebugObjCounterString = 0;
1789 xmlXPathDebugObjCounterPoint = 0;
1790 xmlXPathDebugObjCounterRange = 0;
1791 xmlXPathDebugObjCounterLocset = 0;
1792 xmlXPathDebugObjCounterUsers = 0;
1793 xmlXPathDebugObjCounterXSLTTree = 0;
1794 xmlXPathDebugObjCounterAll = 0;
1795
1796 xmlXPathDebugObjTotalUndefined = 0;
1797 xmlXPathDebugObjTotalNodeset = 0;
1798 xmlXPathDebugObjTotalBool = 0;
1799 xmlXPathDebugObjTotalNumber = 0;
1800 xmlXPathDebugObjTotalString = 0;
1801 xmlXPathDebugObjTotalPoint = 0;
1802 xmlXPathDebugObjTotalRange = 0;
1803 xmlXPathDebugObjTotalLocset = 0;
1804 xmlXPathDebugObjTotalUsers = 0;
1805 xmlXPathDebugObjTotalXSLTTree = 0;
1806 xmlXPathDebugObjTotalAll = 0;
1807
1808 xmlXPathDebugObjMaxUndefined = 0;
1809 xmlXPathDebugObjMaxNodeset = 0;
1810 xmlXPathDebugObjMaxBool = 0;
1811 xmlXPathDebugObjMaxNumber = 0;
1812 xmlXPathDebugObjMaxString = 0;
1813 xmlXPathDebugObjMaxPoint = 0;
1814 xmlXPathDebugObjMaxRange = 0;
1815 xmlXPathDebugObjMaxLocset = 0;
1816 xmlXPathDebugObjMaxUsers = 0;
1817 xmlXPathDebugObjMaxXSLTTree = 0;
1818 xmlXPathDebugObjMaxAll = 0;
1819
1820 }
1821
1822 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1823 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1824 xmlXPathObjectType objType)
1825 {
1826 int isCached = 0;
1827
1828 if (ctxt != NULL) {
1829 if (ctxt->cache != NULL) {
1830 xmlXPathContextCachePtr cache =
1831 (xmlXPathContextCachePtr) ctxt->cache;
1832
1833 isCached = 1;
1834
1835 cache->dbgReusedAll++;
1836 switch (objType) {
1837 case XPATH_UNDEFINED:
1838 cache->dbgReusedUndefined++;
1839 break;
1840 case XPATH_NODESET:
1841 cache->dbgReusedNodeset++;
1842 break;
1843 case XPATH_BOOLEAN:
1844 cache->dbgReusedBool++;
1845 break;
1846 case XPATH_NUMBER:
1847 cache->dbgReusedNumber++;
1848 break;
1849 case XPATH_STRING:
1850 cache->dbgReusedString++;
1851 break;
1852 case XPATH_POINT:
1853 cache->dbgReusedPoint++;
1854 break;
1855 case XPATH_RANGE:
1856 cache->dbgReusedRange++;
1857 break;
1858 case XPATH_LOCATIONSET:
1859 cache->dbgReusedLocset++;
1860 break;
1861 case XPATH_USERS:
1862 cache->dbgReusedUsers++;
1863 break;
1864 case XPATH_XSLT_TREE:
1865 cache->dbgReusedXSLTTree++;
1866 break;
1867 default:
1868 break;
1869 }
1870 }
1871 }
1872
1873 switch (objType) {
1874 case XPATH_UNDEFINED:
1875 if (! isCached)
1876 xmlXPathDebugObjTotalUndefined++;
1877 xmlXPathDebugObjCounterUndefined++;
1878 if (xmlXPathDebugObjCounterUndefined >
1879 xmlXPathDebugObjMaxUndefined)
1880 xmlXPathDebugObjMaxUndefined =
1881 xmlXPathDebugObjCounterUndefined;
1882 break;
1883 case XPATH_NODESET:
1884 if (! isCached)
1885 xmlXPathDebugObjTotalNodeset++;
1886 xmlXPathDebugObjCounterNodeset++;
1887 if (xmlXPathDebugObjCounterNodeset >
1888 xmlXPathDebugObjMaxNodeset)
1889 xmlXPathDebugObjMaxNodeset =
1890 xmlXPathDebugObjCounterNodeset;
1891 break;
1892 case XPATH_BOOLEAN:
1893 if (! isCached)
1894 xmlXPathDebugObjTotalBool++;
1895 xmlXPathDebugObjCounterBool++;
1896 if (xmlXPathDebugObjCounterBool >
1897 xmlXPathDebugObjMaxBool)
1898 xmlXPathDebugObjMaxBool =
1899 xmlXPathDebugObjCounterBool;
1900 break;
1901 case XPATH_NUMBER:
1902 if (! isCached)
1903 xmlXPathDebugObjTotalNumber++;
1904 xmlXPathDebugObjCounterNumber++;
1905 if (xmlXPathDebugObjCounterNumber >
1906 xmlXPathDebugObjMaxNumber)
1907 xmlXPathDebugObjMaxNumber =
1908 xmlXPathDebugObjCounterNumber;
1909 break;
1910 case XPATH_STRING:
1911 if (! isCached)
1912 xmlXPathDebugObjTotalString++;
1913 xmlXPathDebugObjCounterString++;
1914 if (xmlXPathDebugObjCounterString >
1915 xmlXPathDebugObjMaxString)
1916 xmlXPathDebugObjMaxString =
1917 xmlXPathDebugObjCounterString;
1918 break;
1919 case XPATH_POINT:
1920 if (! isCached)
1921 xmlXPathDebugObjTotalPoint++;
1922 xmlXPathDebugObjCounterPoint++;
1923 if (xmlXPathDebugObjCounterPoint >
1924 xmlXPathDebugObjMaxPoint)
1925 xmlXPathDebugObjMaxPoint =
1926 xmlXPathDebugObjCounterPoint;
1927 break;
1928 case XPATH_RANGE:
1929 if (! isCached)
1930 xmlXPathDebugObjTotalRange++;
1931 xmlXPathDebugObjCounterRange++;
1932 if (xmlXPathDebugObjCounterRange >
1933 xmlXPathDebugObjMaxRange)
1934 xmlXPathDebugObjMaxRange =
1935 xmlXPathDebugObjCounterRange;
1936 break;
1937 case XPATH_LOCATIONSET:
1938 if (! isCached)
1939 xmlXPathDebugObjTotalLocset++;
1940 xmlXPathDebugObjCounterLocset++;
1941 if (xmlXPathDebugObjCounterLocset >
1942 xmlXPathDebugObjMaxLocset)
1943 xmlXPathDebugObjMaxLocset =
1944 xmlXPathDebugObjCounterLocset;
1945 break;
1946 case XPATH_USERS:
1947 if (! isCached)
1948 xmlXPathDebugObjTotalUsers++;
1949 xmlXPathDebugObjCounterUsers++;
1950 if (xmlXPathDebugObjCounterUsers >
1951 xmlXPathDebugObjMaxUsers)
1952 xmlXPathDebugObjMaxUsers =
1953 xmlXPathDebugObjCounterUsers;
1954 break;
1955 case XPATH_XSLT_TREE:
1956 if (! isCached)
1957 xmlXPathDebugObjTotalXSLTTree++;
1958 xmlXPathDebugObjCounterXSLTTree++;
1959 if (xmlXPathDebugObjCounterXSLTTree >
1960 xmlXPathDebugObjMaxXSLTTree)
1961 xmlXPathDebugObjMaxXSLTTree =
1962 xmlXPathDebugObjCounterXSLTTree;
1963 break;
1964 default:
1965 break;
1966 }
1967 if (! isCached)
1968 xmlXPathDebugObjTotalAll++;
1969 xmlXPathDebugObjCounterAll++;
1970 if (xmlXPathDebugObjCounterAll >
1971 xmlXPathDebugObjMaxAll)
1972 xmlXPathDebugObjMaxAll =
1973 xmlXPathDebugObjCounterAll;
1974 }
1975
1976 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1977 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1978 xmlXPathObjectType objType)
1979 {
1980 int isCached = 0;
1981
1982 if (ctxt != NULL) {
1983 if (ctxt->cache != NULL) {
1984 xmlXPathContextCachePtr cache =
1985 (xmlXPathContextCachePtr) ctxt->cache;
1986
1987 isCached = 1;
1988
1989 cache->dbgCachedAll++;
1990 switch (objType) {
1991 case XPATH_UNDEFINED:
1992 cache->dbgCachedUndefined++;
1993 break;
1994 case XPATH_NODESET:
1995 cache->dbgCachedNodeset++;
1996 break;
1997 case XPATH_BOOLEAN:
1998 cache->dbgCachedBool++;
1999 break;
2000 case XPATH_NUMBER:
2001 cache->dbgCachedNumber++;
2002 break;
2003 case XPATH_STRING:
2004 cache->dbgCachedString++;
2005 break;
2006 case XPATH_POINT:
2007 cache->dbgCachedPoint++;
2008 break;
2009 case XPATH_RANGE:
2010 cache->dbgCachedRange++;
2011 break;
2012 case XPATH_LOCATIONSET:
2013 cache->dbgCachedLocset++;
2014 break;
2015 case XPATH_USERS:
2016 cache->dbgCachedUsers++;
2017 break;
2018 case XPATH_XSLT_TREE:
2019 cache->dbgCachedXSLTTree++;
2020 break;
2021 default:
2022 break;
2023 }
2024
2025 }
2026 }
2027 switch (objType) {
2028 case XPATH_UNDEFINED:
2029 xmlXPathDebugObjCounterUndefined--;
2030 break;
2031 case XPATH_NODESET:
2032 xmlXPathDebugObjCounterNodeset--;
2033 break;
2034 case XPATH_BOOLEAN:
2035 xmlXPathDebugObjCounterBool--;
2036 break;
2037 case XPATH_NUMBER:
2038 xmlXPathDebugObjCounterNumber--;
2039 break;
2040 case XPATH_STRING:
2041 xmlXPathDebugObjCounterString--;
2042 break;
2043 case XPATH_POINT:
2044 xmlXPathDebugObjCounterPoint--;
2045 break;
2046 case XPATH_RANGE:
2047 xmlXPathDebugObjCounterRange--;
2048 break;
2049 case XPATH_LOCATIONSET:
2050 xmlXPathDebugObjCounterLocset--;
2051 break;
2052 case XPATH_USERS:
2053 xmlXPathDebugObjCounterUsers--;
2054 break;
2055 case XPATH_XSLT_TREE:
2056 xmlXPathDebugObjCounterXSLTTree--;
2057 break;
2058 default:
2059 break;
2060 }
2061 xmlXPathDebugObjCounterAll--;
2062 }
2063
2064 /* REVISIT TODO: Make this static when committing */
2065 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2066 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2067 {
2068 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2069 reqXSLTTree, reqUndefined;
2070 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2071 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2072 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2073 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2074 int leftObjs = xmlXPathDebugObjCounterAll;
2075
2076 reqAll = xmlXPathDebugObjTotalAll;
2077 reqNodeset = xmlXPathDebugObjTotalNodeset;
2078 reqString = xmlXPathDebugObjTotalString;
2079 reqBool = xmlXPathDebugObjTotalBool;
2080 reqNumber = xmlXPathDebugObjTotalNumber;
2081 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2082 reqUndefined = xmlXPathDebugObjTotalUndefined;
2083
2084 printf("# XPath object usage:\n");
2085
2086 if (ctxt != NULL) {
2087 if (ctxt->cache != NULL) {
2088 xmlXPathContextCachePtr cache =
2089 (xmlXPathContextCachePtr) ctxt->cache;
2090
2091 reAll = cache->dbgReusedAll;
2092 reqAll += reAll;
2093 reNodeset = cache->dbgReusedNodeset;
2094 reqNodeset += reNodeset;
2095 reString = cache->dbgReusedString;
2096 reqString += reString;
2097 reBool = cache->dbgReusedBool;
2098 reqBool += reBool;
2099 reNumber = cache->dbgReusedNumber;
2100 reqNumber += reNumber;
2101 reXSLTTree = cache->dbgReusedXSLTTree;
2102 reqXSLTTree += reXSLTTree;
2103 reUndefined = cache->dbgReusedUndefined;
2104 reqUndefined += reUndefined;
2105
2106 caAll = cache->dbgCachedAll;
2107 caBool = cache->dbgCachedBool;
2108 caNodeset = cache->dbgCachedNodeset;
2109 caString = cache->dbgCachedString;
2110 caNumber = cache->dbgCachedNumber;
2111 caXSLTTree = cache->dbgCachedXSLTTree;
2112 caUndefined = cache->dbgCachedUndefined;
2113
2114 if (cache->nodesetObjs)
2115 leftObjs -= cache->nodesetObjs->number;
2116 if (cache->stringObjs)
2117 leftObjs -= cache->stringObjs->number;
2118 if (cache->booleanObjs)
2119 leftObjs -= cache->booleanObjs->number;
2120 if (cache->numberObjs)
2121 leftObjs -= cache->numberObjs->number;
2122 if (cache->miscObjs)
2123 leftObjs -= cache->miscObjs->number;
2124 }
2125 }
2126
2127 printf("# all\n");
2128 printf("# total : %d\n", reqAll);
2129 printf("# left : %d\n", leftObjs);
2130 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2131 printf("# reused : %d\n", reAll);
2132 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2133
2134 printf("# node-sets\n");
2135 printf("# total : %d\n", reqNodeset);
2136 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2137 printf("# reused : %d\n", reNodeset);
2138 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2139
2140 printf("# strings\n");
2141 printf("# total : %d\n", reqString);
2142 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2143 printf("# reused : %d\n", reString);
2144 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2145
2146 printf("# booleans\n");
2147 printf("# total : %d\n", reqBool);
2148 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2149 printf("# reused : %d\n", reBool);
2150 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2151
2152 printf("# numbers\n");
2153 printf("# total : %d\n", reqNumber);
2154 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2155 printf("# reused : %d\n", reNumber);
2156 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2157
2158 printf("# XSLT result tree fragments\n");
2159 printf("# total : %d\n", reqXSLTTree);
2160 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2161 printf("# reused : %d\n", reXSLTTree);
2162 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2163
2164 printf("# undefined\n");
2165 printf("# total : %d\n", reqUndefined);
2166 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2167 printf("# reused : %d\n", reUndefined);
2168 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2169
2170 }
2171
2172 #endif /* XP_DEBUG_OBJ_USAGE */
2173
2174 #endif /* LIBXML_DEBUG_ENABLED */
2175
2176 /************************************************************************
2177 * *
2178 * XPath object caching *
2179 * *
2180 ************************************************************************/
2181
2182 /**
2183 * xmlXPathNewCache:
2184 *
2185 * Create a new object cache
2186 *
2187 * Returns the xmlXPathCache just allocated.
2188 */
2189 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2190 xmlXPathNewCache(void)
2191 {
2192 xmlXPathContextCachePtr ret;
2193
2194 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2195 if (ret == NULL) {
2196 xmlXPathErrMemory(NULL, "creating object cache\n");
2197 return(NULL);
2198 }
2199 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2200 ret->maxNodeset = 100;
2201 ret->maxString = 100;
2202 ret->maxBoolean = 100;
2203 ret->maxNumber = 100;
2204 ret->maxMisc = 100;
2205 return(ret);
2206 }
2207
2208 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2209 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2210 {
2211 int i;
2212 xmlXPathObjectPtr obj;
2213
2214 if (list == NULL)
2215 return;
2216
2217 for (i = 0; i < list->number; i++) {
2218 obj = list->items[i];
2219 /*
2220 * Note that it is already assured that we don't need to
2221 * look out for namespace nodes in the node-set.
2222 */
2223 if (obj->nodesetval != NULL) {
2224 if (obj->nodesetval->nodeTab != NULL)
2225 xmlFree(obj->nodesetval->nodeTab);
2226 xmlFree(obj->nodesetval);
2227 }
2228 xmlFree(obj);
2229 #ifdef XP_DEBUG_OBJ_USAGE
2230 xmlXPathDebugObjCounterAll--;
2231 #endif
2232 }
2233 xmlPointerListFree(list);
2234 }
2235
2236 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2237 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2238 {
2239 if (cache == NULL)
2240 return;
2241 if (cache->nodesetObjs)
2242 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2243 if (cache->stringObjs)
2244 xmlXPathCacheFreeObjectList(cache->stringObjs);
2245 if (cache->booleanObjs)
2246 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2247 if (cache->numberObjs)
2248 xmlXPathCacheFreeObjectList(cache->numberObjs);
2249 if (cache->miscObjs)
2250 xmlXPathCacheFreeObjectList(cache->miscObjs);
2251 xmlFree(cache);
2252 }
2253
2254 /**
2255 * xmlXPathContextSetCache:
2256 *
2257 * @ctxt: the XPath context
2258 * @active: enables/disables (creates/frees) the cache
2259 * @value: a value with semantics dependent on @options
2260 * @options: options (currently only the value 0 is used)
2261 *
2262 * Creates/frees an object cache on the XPath context.
2263 * If activates XPath objects (xmlXPathObject) will be cached internally
2264 * to be reused.
2265 * @options:
2266 * 0: This will set the XPath object caching:
2267 * @value:
2268 * This will set the maximum number of XPath objects
2269 * to be cached per slot
2270 * There are 5 slots for: node-set, string, number, boolean, and
2271 * misc objects. Use <0 for the default number (100).
2272 * Other values for @options have currently no effect.
2273 *
2274 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2275 */
2276 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2277 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2278 int active,
2279 int value,
2280 int options)
2281 {
2282 if (ctxt == NULL)
2283 return(-1);
2284 if (active) {
2285 xmlXPathContextCachePtr cache;
2286
2287 if (ctxt->cache == NULL) {
2288 ctxt->cache = xmlXPathNewCache();
2289 if (ctxt->cache == NULL)
2290 return(-1);
2291 }
2292 cache = (xmlXPathContextCachePtr) ctxt->cache;
2293 if (options == 0) {
2294 if (value < 0)
2295 value = 100;
2296 cache->maxNodeset = value;
2297 cache->maxString = value;
2298 cache->maxNumber = value;
2299 cache->maxBoolean = value;
2300 cache->maxMisc = value;
2301 }
2302 } else if (ctxt->cache != NULL) {
2303 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2304 ctxt->cache = NULL;
2305 }
2306 return(0);
2307 }
2308
2309 /**
2310 * xmlXPathCacheWrapNodeSet:
2311 * @ctxt: the XPath context
2312 * @val: the NodePtr value
2313 *
2314 * This is the cached version of xmlXPathWrapNodeSet().
2315 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2316 *
2317 * Returns the created or reused object.
2318 */
2319 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2320 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2321 {
2322 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2323 xmlXPathContextCachePtr cache =
2324 (xmlXPathContextCachePtr) ctxt->cache;
2325
2326 if ((cache->miscObjs != NULL) &&
2327 (cache->miscObjs->number != 0))
2328 {
2329 xmlXPathObjectPtr ret;
2330
2331 ret = (xmlXPathObjectPtr)
2332 cache->miscObjs->items[--cache->miscObjs->number];
2333 ret->type = XPATH_NODESET;
2334 ret->nodesetval = val;
2335 #ifdef XP_DEBUG_OBJ_USAGE
2336 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2337 #endif
2338 return(ret);
2339 }
2340 }
2341
2342 return(xmlXPathWrapNodeSet(val));
2343
2344 }
2345
2346 /**
2347 * xmlXPathCacheWrapString:
2348 * @ctxt: the XPath context
2349 * @val: the xmlChar * value
2350 *
2351 * This is the cached version of xmlXPathWrapString().
2352 * Wraps the @val string into an XPath object.
2353 *
2354 * Returns the created or reused object.
2355 */
2356 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2357 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2358 {
2359 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2360 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2361
2362 if ((cache->stringObjs != NULL) &&
2363 (cache->stringObjs->number != 0))
2364 {
2365
2366 xmlXPathObjectPtr ret;
2367
2368 ret = (xmlXPathObjectPtr)
2369 cache->stringObjs->items[--cache->stringObjs->number];
2370 ret->type = XPATH_STRING;
2371 ret->stringval = val;
2372 #ifdef XP_DEBUG_OBJ_USAGE
2373 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2374 #endif
2375 return(ret);
2376 } else if ((cache->miscObjs != NULL) &&
2377 (cache->miscObjs->number != 0))
2378 {
2379 xmlXPathObjectPtr ret;
2380 /*
2381 * Fallback to misc-cache.
2382 */
2383 ret = (xmlXPathObjectPtr)
2384 cache->miscObjs->items[--cache->miscObjs->number];
2385
2386 ret->type = XPATH_STRING;
2387 ret->stringval = val;
2388 #ifdef XP_DEBUG_OBJ_USAGE
2389 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2390 #endif
2391 return(ret);
2392 }
2393 }
2394 return(xmlXPathWrapString(val));
2395 }
2396
2397 /**
2398 * xmlXPathCacheNewNodeSet:
2399 * @ctxt: the XPath context
2400 * @val: the NodePtr value
2401 *
2402 * This is the cached version of xmlXPathNewNodeSet().
2403 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2404 * it with the single Node @val
2405 *
2406 * Returns the created or reused object.
2407 */
2408 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2409 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2410 {
2411 if ((ctxt != NULL) && (ctxt->cache)) {
2412 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2413
2414 if ((cache->nodesetObjs != NULL) &&
2415 (cache->nodesetObjs->number != 0))
2416 {
2417 xmlXPathObjectPtr ret;
2418 /*
2419 * Use the nodeset-cache.
2420 */
2421 ret = (xmlXPathObjectPtr)
2422 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2423 ret->type = XPATH_NODESET;
2424 ret->boolval = 0;
2425 if (val) {
2426 if ((ret->nodesetval->nodeMax == 0) ||
2427 (val->type == XML_NAMESPACE_DECL))
2428 {
2429 /* TODO: Check memory error. */
2430 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2431 } else {
2432 ret->nodesetval->nodeTab[0] = val;
2433 ret->nodesetval->nodeNr = 1;
2434 }
2435 }
2436 #ifdef XP_DEBUG_OBJ_USAGE
2437 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2438 #endif
2439 return(ret);
2440 } else if ((cache->miscObjs != NULL) &&
2441 (cache->miscObjs->number != 0))
2442 {
2443 xmlXPathObjectPtr ret;
2444 /*
2445 * Fallback to misc-cache.
2446 */
2447
2448 ret = (xmlXPathObjectPtr)
2449 cache->miscObjs->items[--cache->miscObjs->number];
2450
2451 ret->type = XPATH_NODESET;
2452 ret->boolval = 0;
2453 ret->nodesetval = xmlXPathNodeSetCreate(val);
2454 if (ret->nodesetval == NULL) {
2455 ctxt->lastError.domain = XML_FROM_XPATH;
2456 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2457 return(NULL);
2458 }
2459 #ifdef XP_DEBUG_OBJ_USAGE
2460 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2461 #endif
2462 return(ret);
2463 }
2464 }
2465 return(xmlXPathNewNodeSet(val));
2466 }
2467
2468 /**
2469 * xmlXPathCacheNewCString:
2470 * @ctxt: the XPath context
2471 * @val: the char * value
2472 *
2473 * This is the cached version of xmlXPathNewCString().
2474 * Acquire an xmlXPathObjectPtr of type string and of value @val
2475 *
2476 * Returns the created or reused object.
2477 */
2478 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2479 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2480 {
2481 if ((ctxt != NULL) && (ctxt->cache)) {
2482 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2483
2484 if ((cache->stringObjs != NULL) &&
2485 (cache->stringObjs->number != 0))
2486 {
2487 xmlXPathObjectPtr ret;
2488
2489 ret = (xmlXPathObjectPtr)
2490 cache->stringObjs->items[--cache->stringObjs->number];
2491
2492 ret->type = XPATH_STRING;
2493 ret->stringval = xmlStrdup(BAD_CAST val);
2494 #ifdef XP_DEBUG_OBJ_USAGE
2495 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2496 #endif
2497 return(ret);
2498 } else if ((cache->miscObjs != NULL) &&
2499 (cache->miscObjs->number != 0))
2500 {
2501 xmlXPathObjectPtr ret;
2502
2503 ret = (xmlXPathObjectPtr)
2504 cache->miscObjs->items[--cache->miscObjs->number];
2505
2506 ret->type = XPATH_STRING;
2507 ret->stringval = xmlStrdup(BAD_CAST val);
2508 #ifdef XP_DEBUG_OBJ_USAGE
2509 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2510 #endif
2511 return(ret);
2512 }
2513 }
2514 return(xmlXPathNewCString(val));
2515 }
2516
2517 /**
2518 * xmlXPathCacheNewString:
2519 * @ctxt: the XPath context
2520 * @val: the xmlChar * value
2521 *
2522 * This is the cached version of xmlXPathNewString().
2523 * Acquire an xmlXPathObjectPtr of type string and of value @val
2524 *
2525 * Returns the created or reused object.
2526 */
2527 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2528 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2529 {
2530 if ((ctxt != NULL) && (ctxt->cache)) {
2531 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2532
2533 if ((cache->stringObjs != NULL) &&
2534 (cache->stringObjs->number != 0))
2535 {
2536 xmlXPathObjectPtr ret;
2537
2538 ret = (xmlXPathObjectPtr)
2539 cache->stringObjs->items[--cache->stringObjs->number];
2540 ret->type = XPATH_STRING;
2541 if (val != NULL)
2542 ret->stringval = xmlStrdup(val);
2543 else
2544 ret->stringval = xmlStrdup((const xmlChar *)"");
2545 #ifdef XP_DEBUG_OBJ_USAGE
2546 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2547 #endif
2548 return(ret);
2549 } else if ((cache->miscObjs != NULL) &&
2550 (cache->miscObjs->number != 0))
2551 {
2552 xmlXPathObjectPtr ret;
2553
2554 ret = (xmlXPathObjectPtr)
2555 cache->miscObjs->items[--cache->miscObjs->number];
2556
2557 ret->type = XPATH_STRING;
2558 if (val != NULL)
2559 ret->stringval = xmlStrdup(val);
2560 else
2561 ret->stringval = xmlStrdup((const xmlChar *)"");
2562 #ifdef XP_DEBUG_OBJ_USAGE
2563 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2564 #endif
2565 return(ret);
2566 }
2567 }
2568 return(xmlXPathNewString(val));
2569 }
2570
2571 /**
2572 * xmlXPathCacheNewBoolean:
2573 * @ctxt: the XPath context
2574 * @val: the boolean value
2575 *
2576 * This is the cached version of xmlXPathNewBoolean().
2577 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2578 *
2579 * Returns the created or reused object.
2580 */
2581 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2582 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2583 {
2584 if ((ctxt != NULL) && (ctxt->cache)) {
2585 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2586
2587 if ((cache->booleanObjs != NULL) &&
2588 (cache->booleanObjs->number != 0))
2589 {
2590 xmlXPathObjectPtr ret;
2591
2592 ret = (xmlXPathObjectPtr)
2593 cache->booleanObjs->items[--cache->booleanObjs->number];
2594 ret->type = XPATH_BOOLEAN;
2595 ret->boolval = (val != 0);
2596 #ifdef XP_DEBUG_OBJ_USAGE
2597 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2598 #endif
2599 return(ret);
2600 } else if ((cache->miscObjs != NULL) &&
2601 (cache->miscObjs->number != 0))
2602 {
2603 xmlXPathObjectPtr ret;
2604
2605 ret = (xmlXPathObjectPtr)
2606 cache->miscObjs->items[--cache->miscObjs->number];
2607
2608 ret->type = XPATH_BOOLEAN;
2609 ret->boolval = (val != 0);
2610 #ifdef XP_DEBUG_OBJ_USAGE
2611 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2612 #endif
2613 return(ret);
2614 }
2615 }
2616 return(xmlXPathNewBoolean(val));
2617 }
2618
2619 /**
2620 * xmlXPathCacheNewFloat:
2621 * @ctxt: the XPath context
2622 * @val: the double value
2623 *
2624 * This is the cached version of xmlXPathNewFloat().
2625 * Acquires an xmlXPathObjectPtr of type double and of value @val
2626 *
2627 * Returns the created or reused object.
2628 */
2629 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2630 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2631 {
2632 if ((ctxt != NULL) && (ctxt->cache)) {
2633 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2634
2635 if ((cache->numberObjs != NULL) &&
2636 (cache->numberObjs->number != 0))
2637 {
2638 xmlXPathObjectPtr ret;
2639
2640 ret = (xmlXPathObjectPtr)
2641 cache->numberObjs->items[--cache->numberObjs->number];
2642 ret->type = XPATH_NUMBER;
2643 ret->floatval = val;
2644 #ifdef XP_DEBUG_OBJ_USAGE
2645 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2646 #endif
2647 return(ret);
2648 } else if ((cache->miscObjs != NULL) &&
2649 (cache->miscObjs->number != 0))
2650 {
2651 xmlXPathObjectPtr ret;
2652
2653 ret = (xmlXPathObjectPtr)
2654 cache->miscObjs->items[--cache->miscObjs->number];
2655
2656 ret->type = XPATH_NUMBER;
2657 ret->floatval = val;
2658 #ifdef XP_DEBUG_OBJ_USAGE
2659 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2660 #endif
2661 return(ret);
2662 }
2663 }
2664 return(xmlXPathNewFloat(val));
2665 }
2666
2667 /**
2668 * xmlXPathCacheConvertString:
2669 * @ctxt: the XPath context
2670 * @val: an XPath object
2671 *
2672 * This is the cached version of xmlXPathConvertString().
2673 * Converts an existing object to its string() equivalent
2674 *
2675 * Returns a created or reused object, the old one is freed (cached)
2676 * (or the operation is done directly on @val)
2677 */
2678
2679 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2680 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2681 xmlChar *res = NULL;
2682
2683 if (val == NULL)
2684 return(xmlXPathCacheNewCString(ctxt, ""));
2685
2686 switch (val->type) {
2687 case XPATH_UNDEFINED:
2688 #ifdef DEBUG_EXPR
2689 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2690 #endif
2691 break;
2692 case XPATH_NODESET:
2693 case XPATH_XSLT_TREE:
2694 res = xmlXPathCastNodeSetToString(val->nodesetval);
2695 break;
2696 case XPATH_STRING:
2697 return(val);
2698 case XPATH_BOOLEAN:
2699 res = xmlXPathCastBooleanToString(val->boolval);
2700 break;
2701 case XPATH_NUMBER:
2702 res = xmlXPathCastNumberToString(val->floatval);
2703 break;
2704 case XPATH_USERS:
2705 case XPATH_POINT:
2706 case XPATH_RANGE:
2707 case XPATH_LOCATIONSET:
2708 TODO;
2709 break;
2710 }
2711 xmlXPathReleaseObject(ctxt, val);
2712 if (res == NULL)
2713 return(xmlXPathCacheNewCString(ctxt, ""));
2714 return(xmlXPathCacheWrapString(ctxt, res));
2715 }
2716
2717 /**
2718 * xmlXPathCacheObjectCopy:
2719 * @ctxt: the XPath context
2720 * @val: the original object
2721 *
2722 * This is the cached version of xmlXPathObjectCopy().
2723 * Acquire a copy of a given object
2724 *
2725 * Returns a created or reused created object.
2726 */
2727 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2728 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2729 {
2730 if (val == NULL)
2731 return(NULL);
2732
2733 if (XP_HAS_CACHE(ctxt)) {
2734 switch (val->type) {
2735 case XPATH_NODESET:
2736 return(xmlXPathCacheWrapNodeSet(ctxt,
2737 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2738 case XPATH_STRING:
2739 return(xmlXPathCacheNewString(ctxt, val->stringval));
2740 case XPATH_BOOLEAN:
2741 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2742 case XPATH_NUMBER:
2743 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2744 default:
2745 break;
2746 }
2747 }
2748 return(xmlXPathObjectCopy(val));
2749 }
2750
2751 /**
2752 * xmlXPathCacheConvertBoolean:
2753 * @ctxt: the XPath context
2754 * @val: an XPath object
2755 *
2756 * This is the cached version of xmlXPathConvertBoolean().
2757 * Converts an existing object to its boolean() equivalent
2758 *
2759 * Returns a created or reused object, the old one is freed (or the operation
2760 * is done directly on @val)
2761 */
2762 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2763 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2764 xmlXPathObjectPtr ret;
2765
2766 if (val == NULL)
2767 return(xmlXPathCacheNewBoolean(ctxt, 0));
2768 if (val->type == XPATH_BOOLEAN)
2769 return(val);
2770 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2771 xmlXPathReleaseObject(ctxt, val);
2772 return(ret);
2773 }
2774
2775 /**
2776 * xmlXPathCacheConvertNumber:
2777 * @ctxt: the XPath context
2778 * @val: an XPath object
2779 *
2780 * This is the cached version of xmlXPathConvertNumber().
2781 * Converts an existing object to its number() equivalent
2782 *
2783 * Returns a created or reused object, the old one is freed (or the operation
2784 * is done directly on @val)
2785 */
2786 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2787 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2788 xmlXPathObjectPtr ret;
2789
2790 if (val == NULL)
2791 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2792 if (val->type == XPATH_NUMBER)
2793 return(val);
2794 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2795 xmlXPathReleaseObject(ctxt, val);
2796 return(ret);
2797 }
2798
2799 /************************************************************************
2800 * *
2801 * Parser stacks related functions and macros *
2802 * *
2803 ************************************************************************/
2804
2805 /**
2806 * xmlXPathSetFrame:
2807 * @ctxt: an XPath parser context
2808 *
2809 * Set the callee evaluation frame
2810 *
2811 * Returns the previous frame value to be restored once done
2812 */
2813 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2814 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2815 int ret;
2816
2817 if (ctxt == NULL)
2818 return(0);
2819 ret = ctxt->valueFrame;
2820 ctxt->valueFrame = ctxt->valueNr;
2821 return(ret);
2822 }
2823
2824 /**
2825 * xmlXPathPopFrame:
2826 * @ctxt: an XPath parser context
2827 * @frame: the previous frame value
2828 *
2829 * Remove the callee evaluation frame
2830 */
2831 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2832 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2833 if (ctxt == NULL)
2834 return;
2835 if (ctxt->valueNr < ctxt->valueFrame) {
2836 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2837 }
2838 ctxt->valueFrame = frame;
2839 }
2840
2841 /**
2842 * valuePop:
2843 * @ctxt: an XPath evaluation context
2844 *
2845 * Pops the top XPath object from the value stack
2846 *
2847 * Returns the XPath object just removed
2848 */
2849 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2850 valuePop(xmlXPathParserContextPtr ctxt)
2851 {
2852 xmlXPathObjectPtr ret;
2853
2854 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2855 return (NULL);
2856
2857 if (ctxt->valueNr <= ctxt->valueFrame) {
2858 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2859 return (NULL);
2860 }
2861
2862 ctxt->valueNr--;
2863 if (ctxt->valueNr > 0)
2864 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2865 else
2866 ctxt->value = NULL;
2867 ret = ctxt->valueTab[ctxt->valueNr];
2868 ctxt->valueTab[ctxt->valueNr] = NULL;
2869 return (ret);
2870 }
2871 /**
2872 * valuePush:
2873 * @ctxt: an XPath evaluation context
2874 * @value: the XPath object
2875 *
2876 * Pushes a new XPath object on top of the value stack. If value is NULL,
2877 * a memory error is recorded in the parser context.
2878 *
2879 * Returns the number of items on the value stack, or -1 in case of error.
2880 */
2881 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2882 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2883 {
2884 if (ctxt == NULL) return(-1);
2885 if (value == NULL) {
2886 /*
2887 * A NULL value typically indicates that a memory allocation failed,
2888 * so we set ctxt->error here to propagate the error.
2889 */
2890 ctxt->error = XPATH_MEMORY_ERROR;
2891 return(-1);
2892 }
2893 if (ctxt->valueNr >= ctxt->valueMax) {
2894 xmlXPathObjectPtr *tmp;
2895
2896 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2897 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2898 return (-1);
2899 }
2900 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2901 2 * ctxt->valueMax *
2902 sizeof(ctxt->valueTab[0]));
2903 if (tmp == NULL) {
2904 xmlXPathPErrMemory(ctxt, "pushing value\n");
2905 return (-1);
2906 }
2907 ctxt->valueMax *= 2;
2908 ctxt->valueTab = tmp;
2909 }
2910 ctxt->valueTab[ctxt->valueNr] = value;
2911 ctxt->value = value;
2912 return (ctxt->valueNr++);
2913 }
2914
2915 /**
2916 * xmlXPathPopBoolean:
2917 * @ctxt: an XPath parser context
2918 *
2919 * Pops a boolean from the stack, handling conversion if needed.
2920 * Check error with #xmlXPathCheckError.
2921 *
2922 * Returns the boolean
2923 */
2924 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2925 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2926 xmlXPathObjectPtr obj;
2927 int ret;
2928
2929 obj = valuePop(ctxt);
2930 if (obj == NULL) {
2931 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932 return(0);
2933 }
2934 if (obj->type != XPATH_BOOLEAN)
2935 ret = xmlXPathCastToBoolean(obj);
2936 else
2937 ret = obj->boolval;
2938 xmlXPathReleaseObject(ctxt->context, obj);
2939 return(ret);
2940 }
2941
2942 /**
2943 * xmlXPathPopNumber:
2944 * @ctxt: an XPath parser context
2945 *
2946 * Pops a number from the stack, handling conversion if needed.
2947 * Check error with #xmlXPathCheckError.
2948 *
2949 * Returns the number
2950 */
2951 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2952 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2953 xmlXPathObjectPtr obj;
2954 double ret;
2955
2956 obj = valuePop(ctxt);
2957 if (obj == NULL) {
2958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959 return(0);
2960 }
2961 if (obj->type != XPATH_NUMBER)
2962 ret = xmlXPathCastToNumber(obj);
2963 else
2964 ret = obj->floatval;
2965 xmlXPathReleaseObject(ctxt->context, obj);
2966 return(ret);
2967 }
2968
2969 /**
2970 * xmlXPathPopString:
2971 * @ctxt: an XPath parser context
2972 *
2973 * Pops a string from the stack, handling conversion if needed.
2974 * Check error with #xmlXPathCheckError.
2975 *
2976 * Returns the string
2977 */
2978 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2979 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2980 xmlXPathObjectPtr obj;
2981 xmlChar * ret;
2982
2983 obj = valuePop(ctxt);
2984 if (obj == NULL) {
2985 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986 return(NULL);
2987 }
2988 ret = xmlXPathCastToString(obj); /* this does required strdup */
2989 /* TODO: needs refactoring somewhere else */
2990 if (obj->stringval == ret)
2991 obj->stringval = NULL;
2992 xmlXPathReleaseObject(ctxt->context, obj);
2993 return(ret);
2994 }
2995
2996 /**
2997 * xmlXPathPopNodeSet:
2998 * @ctxt: an XPath parser context
2999 *
3000 * Pops a node-set from the stack, handling conversion if needed.
3001 * Check error with #xmlXPathCheckError.
3002 *
3003 * Returns the node-set
3004 */
3005 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)3006 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3007 xmlXPathObjectPtr obj;
3008 xmlNodeSetPtr ret;
3009
3010 if (ctxt == NULL) return(NULL);
3011 if (ctxt->value == NULL) {
3012 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3013 return(NULL);
3014 }
3015 if (!xmlXPathStackIsNodeSet(ctxt)) {
3016 xmlXPathSetTypeError(ctxt);
3017 return(NULL);
3018 }
3019 obj = valuePop(ctxt);
3020 ret = obj->nodesetval;
3021 #if 0
3022 /* to fix memory leak of not clearing obj->user */
3023 if (obj->boolval && obj->user != NULL)
3024 xmlFreeNodeList((xmlNodePtr) obj->user);
3025 #endif
3026 obj->nodesetval = NULL;
3027 xmlXPathReleaseObject(ctxt->context, obj);
3028 return(ret);
3029 }
3030
3031 /**
3032 * xmlXPathPopExternal:
3033 * @ctxt: an XPath parser context
3034 *
3035 * Pops an external object from the stack, handling conversion if needed.
3036 * Check error with #xmlXPathCheckError.
3037 *
3038 * Returns the object
3039 */
3040 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3041 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3042 xmlXPathObjectPtr obj;
3043 void * ret;
3044
3045 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3046 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3047 return(NULL);
3048 }
3049 if (ctxt->value->type != XPATH_USERS) {
3050 xmlXPathSetTypeError(ctxt);
3051 return(NULL);
3052 }
3053 obj = valuePop(ctxt);
3054 ret = obj->user;
3055 obj->user = NULL;
3056 xmlXPathReleaseObject(ctxt->context, obj);
3057 return(ret);
3058 }
3059
3060 /*
3061 * Macros for accessing the content. Those should be used only by the parser,
3062 * and not exported.
3063 *
3064 * Dirty macros, i.e. one need to make assumption on the context to use them
3065 *
3066 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3067 * CUR returns the current xmlChar value, i.e. a 8 bit value
3068 * in ISO-Latin or UTF-8.
3069 * This should be used internally by the parser
3070 * only to compare to ASCII values otherwise it would break when
3071 * running with UTF-8 encoding.
3072 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3073 * to compare on ASCII based substring.
3074 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3075 * strings within the parser.
3076 * CURRENT Returns the current char value, with the full decoding of
3077 * UTF-8 if we are using this mode. It returns an int.
3078 * NEXT Skip to the next character, this does the proper decoding
3079 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3080 * It returns the pointer to the current xmlChar.
3081 */
3082
3083 #define CUR (*ctxt->cur)
3084 #define SKIP(val) ctxt->cur += (val)
3085 #define NXT(val) ctxt->cur[(val)]
3086 #define CUR_PTR ctxt->cur
3087 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3088
3089 #define COPY_BUF(l,b,i,v) \
3090 if (l == 1) b[i++] = (xmlChar) v; \
3091 else i += xmlCopyChar(l,&b[i],v)
3092
3093 #define NEXTL(l) ctxt->cur += l
3094
3095 #define SKIP_BLANKS \
3096 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3097
3098 #define CURRENT (*ctxt->cur)
3099 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3100
3101
3102 #ifndef DBL_DIG
3103 #define DBL_DIG 16
3104 #endif
3105 #ifndef DBL_EPSILON
3106 #define DBL_EPSILON 1E-9
3107 #endif
3108
3109 #define UPPER_DOUBLE 1E9
3110 #define LOWER_DOUBLE 1E-5
3111 #define LOWER_DOUBLE_EXP 5
3112
3113 #define INTEGER_DIGITS DBL_DIG
3114 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3115 #define EXPONENT_DIGITS (3 + 2)
3116
3117 /**
3118 * xmlXPathFormatNumber:
3119 * @number: number to format
3120 * @buffer: output buffer
3121 * @buffersize: size of output buffer
3122 *
3123 * Convert the number into a string representation.
3124 */
3125 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3126 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3127 {
3128 switch (xmlXPathIsInf(number)) {
3129 case 1:
3130 if (buffersize > (int)sizeof("Infinity"))
3131 snprintf(buffer, buffersize, "Infinity");
3132 break;
3133 case -1:
3134 if (buffersize > (int)sizeof("-Infinity"))
3135 snprintf(buffer, buffersize, "-Infinity");
3136 break;
3137 default:
3138 if (xmlXPathIsNaN(number)) {
3139 if (buffersize > (int)sizeof("NaN"))
3140 snprintf(buffer, buffersize, "NaN");
3141 } else if (number == 0) {
3142 /* Omit sign for negative zero. */
3143 snprintf(buffer, buffersize, "0");
3144 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3145 (number == (int) number)) {
3146 char work[30];
3147 char *ptr, *cur;
3148 int value = (int) number;
3149
3150 ptr = &buffer[0];
3151 if (value == 0) {
3152 *ptr++ = '0';
3153 } else {
3154 snprintf(work, 29, "%d", value);
3155 cur = &work[0];
3156 while ((*cur) && (ptr - buffer < buffersize)) {
3157 *ptr++ = *cur++;
3158 }
3159 }
3160 if (ptr - buffer < buffersize) {
3161 *ptr = 0;
3162 } else if (buffersize > 0) {
3163 ptr--;
3164 *ptr = 0;
3165 }
3166 } else {
3167 /*
3168 For the dimension of work,
3169 DBL_DIG is number of significant digits
3170 EXPONENT is only needed for "scientific notation"
3171 3 is sign, decimal point, and terminating zero
3172 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3173 Note that this dimension is slightly (a few characters)
3174 larger than actually necessary.
3175 */
3176 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3177 int integer_place, fraction_place;
3178 char *ptr;
3179 char *after_fraction;
3180 double absolute_value;
3181 int size;
3182
3183 absolute_value = fabs(number);
3184
3185 /*
3186 * First choose format - scientific or regular floating point.
3187 * In either case, result is in work, and after_fraction points
3188 * just past the fractional part.
3189 */
3190 if ( ((absolute_value > UPPER_DOUBLE) ||
3191 (absolute_value < LOWER_DOUBLE)) &&
3192 (absolute_value != 0.0) ) {
3193 /* Use scientific notation */
3194 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3195 fraction_place = DBL_DIG - 1;
3196 size = snprintf(work, sizeof(work),"%*.*e",
3197 integer_place, fraction_place, number);
3198 while ((size > 0) && (work[size] != 'e')) size--;
3199
3200 }
3201 else {
3202 /* Use regular notation */
3203 if (absolute_value > 0.0) {
3204 integer_place = (int)log10(absolute_value);
3205 if (integer_place > 0)
3206 fraction_place = DBL_DIG - integer_place - 1;
3207 else
3208 fraction_place = DBL_DIG - integer_place;
3209 } else {
3210 fraction_place = 1;
3211 }
3212 size = snprintf(work, sizeof(work), "%0.*f",
3213 fraction_place, number);
3214 }
3215
3216 /* Remove leading spaces sometimes inserted by snprintf */
3217 while (work[0] == ' ') {
3218 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3219 size--;
3220 }
3221
3222 /* Remove fractional trailing zeroes */
3223 after_fraction = work + size;
3224 ptr = after_fraction;
3225 while (*(--ptr) == '0')
3226 ;
3227 if (*ptr != '.')
3228 ptr++;
3229 while ((*ptr++ = *after_fraction++) != 0);
3230
3231 /* Finally copy result back to caller */
3232 size = strlen(work) + 1;
3233 if (size > buffersize) {
3234 work[buffersize - 1] = 0;
3235 size = buffersize;
3236 }
3237 memmove(buffer, work, size);
3238 }
3239 break;
3240 }
3241 }
3242
3243
3244 /************************************************************************
3245 * *
3246 * Routines to handle NodeSets *
3247 * *
3248 ************************************************************************/
3249
3250 /**
3251 * xmlXPathOrderDocElems:
3252 * @doc: an input document
3253 *
3254 * Call this routine to speed up XPath computation on static documents.
3255 * This stamps all the element nodes with the document order
3256 * Like for line information, the order is kept in the element->content
3257 * field, the value stored is actually - the node number (starting at -1)
3258 * to be able to differentiate from line numbers.
3259 *
3260 * Returns the number of elements found in the document or -1 in case
3261 * of error.
3262 */
3263 long
xmlXPathOrderDocElems(xmlDocPtr doc)3264 xmlXPathOrderDocElems(xmlDocPtr doc) {
3265 ptrdiff_t count = 0;
3266 xmlNodePtr cur;
3267
3268 if (doc == NULL)
3269 return(-1);
3270 cur = doc->children;
3271 while (cur != NULL) {
3272 if (cur->type == XML_ELEMENT_NODE) {
3273 cur->content = (void *) (-(++count));
3274 if (cur->children != NULL) {
3275 cur = cur->children;
3276 continue;
3277 }
3278 }
3279 if (cur->next != NULL) {
3280 cur = cur->next;
3281 continue;
3282 }
3283 do {
3284 cur = cur->parent;
3285 if (cur == NULL)
3286 break;
3287 if (cur == (xmlNodePtr) doc) {
3288 cur = NULL;
3289 break;
3290 }
3291 if (cur->next != NULL) {
3292 cur = cur->next;
3293 break;
3294 }
3295 } while (cur != NULL);
3296 }
3297 return((long) count);
3298 }
3299
3300 /**
3301 * xmlXPathCmpNodes:
3302 * @node1: the first node
3303 * @node2: the second node
3304 *
3305 * Compare two nodes w.r.t document order
3306 *
3307 * Returns -2 in case of error 1 if first point < second point, 0 if
3308 * it's the same node, -1 otherwise
3309 */
3310 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3311 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3312 int depth1, depth2;
3313 int attr1 = 0, attr2 = 0;
3314 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3315 xmlNodePtr cur, root;
3316
3317 if ((node1 == NULL) || (node2 == NULL))
3318 return(-2);
3319 /*
3320 * a couple of optimizations which will avoid computations in most cases
3321 */
3322 if (node1 == node2) /* trivial case */
3323 return(0);
3324 if (node1->type == XML_ATTRIBUTE_NODE) {
3325 attr1 = 1;
3326 attrNode1 = node1;
3327 node1 = node1->parent;
3328 }
3329 if (node2->type == XML_ATTRIBUTE_NODE) {
3330 attr2 = 1;
3331 attrNode2 = node2;
3332 node2 = node2->parent;
3333 }
3334 if (node1 == node2) {
3335 if (attr1 == attr2) {
3336 /* not required, but we keep attributes in order */
3337 if (attr1 != 0) {
3338 cur = attrNode2->prev;
3339 while (cur != NULL) {
3340 if (cur == attrNode1)
3341 return (1);
3342 cur = cur->prev;
3343 }
3344 return (-1);
3345 }
3346 return(0);
3347 }
3348 if (attr2 == 1)
3349 return(1);
3350 return(-1);
3351 }
3352 if ((node1->type == XML_NAMESPACE_DECL) ||
3353 (node2->type == XML_NAMESPACE_DECL))
3354 return(1);
3355 if (node1 == node2->prev)
3356 return(1);
3357 if (node1 == node2->next)
3358 return(-1);
3359
3360 /*
3361 * Speedup using document order if available.
3362 */
3363 if ((node1->type == XML_ELEMENT_NODE) &&
3364 (node2->type == XML_ELEMENT_NODE) &&
3365 (0 > (ptrdiff_t) node1->content) &&
3366 (0 > (ptrdiff_t) node2->content) &&
3367 (node1->doc == node2->doc)) {
3368 ptrdiff_t l1, l2;
3369
3370 l1 = -((ptrdiff_t) node1->content);
3371 l2 = -((ptrdiff_t) node2->content);
3372 if (l1 < l2)
3373 return(1);
3374 if (l1 > l2)
3375 return(-1);
3376 }
3377
3378 /*
3379 * compute depth to root
3380 */
3381 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3382 if (cur->parent == node1)
3383 return(1);
3384 depth2++;
3385 }
3386 root = cur;
3387 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3388 if (cur->parent == node2)
3389 return(-1);
3390 depth1++;
3391 }
3392 /*
3393 * Distinct document (or distinct entities :-( ) case.
3394 */
3395 if (root != cur) {
3396 return(-2);
3397 }
3398 /*
3399 * get the nearest common ancestor.
3400 */
3401 while (depth1 > depth2) {
3402 depth1--;
3403 node1 = node1->parent;
3404 }
3405 while (depth2 > depth1) {
3406 depth2--;
3407 node2 = node2->parent;
3408 }
3409 while (node1->parent != node2->parent) {
3410 node1 = node1->parent;
3411 node2 = node2->parent;
3412 /* should not happen but just in case ... */
3413 if ((node1 == NULL) || (node2 == NULL))
3414 return(-2);
3415 }
3416 /*
3417 * Find who's first.
3418 */
3419 if (node1 == node2->prev)
3420 return(1);
3421 if (node1 == node2->next)
3422 return(-1);
3423 /*
3424 * Speedup using document order if available.
3425 */
3426 if ((node1->type == XML_ELEMENT_NODE) &&
3427 (node2->type == XML_ELEMENT_NODE) &&
3428 (0 > (ptrdiff_t) node1->content) &&
3429 (0 > (ptrdiff_t) node2->content) &&
3430 (node1->doc == node2->doc)) {
3431 ptrdiff_t l1, l2;
3432
3433 l1 = -((ptrdiff_t) node1->content);
3434 l2 = -((ptrdiff_t) node2->content);
3435 if (l1 < l2)
3436 return(1);
3437 if (l1 > l2)
3438 return(-1);
3439 }
3440
3441 for (cur = node1->next;cur != NULL;cur = cur->next)
3442 if (cur == node2)
3443 return(1);
3444 return(-1); /* assume there is no sibling list corruption */
3445 }
3446
3447 /**
3448 * xmlXPathNodeSetSort:
3449 * @set: the node set
3450 *
3451 * Sort the node set in document order
3452 */
3453 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3454 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3455 #ifndef WITH_TIM_SORT
3456 int i, j, incr, len;
3457 xmlNodePtr tmp;
3458 #endif
3459
3460 if (set == NULL)
3461 return;
3462
3463 #ifndef WITH_TIM_SORT
3464 /*
3465 * Use the old Shell's sort implementation to sort the node-set
3466 * Timsort ought to be quite faster
3467 */
3468 len = set->nodeNr;
3469 for (incr = len / 2; incr > 0; incr /= 2) {
3470 for (i = incr; i < len; i++) {
3471 j = i - incr;
3472 while (j >= 0) {
3473 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3474 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3475 set->nodeTab[j + incr]) == -1)
3476 #else
3477 if (xmlXPathCmpNodes(set->nodeTab[j],
3478 set->nodeTab[j + incr]) == -1)
3479 #endif
3480 {
3481 tmp = set->nodeTab[j];
3482 set->nodeTab[j] = set->nodeTab[j + incr];
3483 set->nodeTab[j + incr] = tmp;
3484 j -= incr;
3485 } else
3486 break;
3487 }
3488 }
3489 }
3490 #else /* WITH_TIM_SORT */
3491 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3492 #endif /* WITH_TIM_SORT */
3493 }
3494
3495 #define XML_NODESET_DEFAULT 10
3496 /**
3497 * xmlXPathNodeSetDupNs:
3498 * @node: the parent node of the namespace XPath node
3499 * @ns: the libxml namespace declaration node.
3500 *
3501 * Namespace node in libxml don't match the XPath semantic. In a node set
3502 * the namespace nodes are duplicated and the next pointer is set to the
3503 * parent node in the XPath semantic.
3504 *
3505 * Returns the newly created object.
3506 */
3507 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3508 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3509 xmlNsPtr cur;
3510
3511 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3512 return(NULL);
3513 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3514 return((xmlNodePtr) ns);
3515
3516 /*
3517 * Allocate a new Namespace and fill the fields.
3518 */
3519 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3520 if (cur == NULL) {
3521 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3522 return(NULL);
3523 }
3524 memset(cur, 0, sizeof(xmlNs));
3525 cur->type = XML_NAMESPACE_DECL;
3526 if (ns->href != NULL)
3527 cur->href = xmlStrdup(ns->href);
3528 if (ns->prefix != NULL)
3529 cur->prefix = xmlStrdup(ns->prefix);
3530 cur->next = (xmlNsPtr) node;
3531 return((xmlNodePtr) cur);
3532 }
3533
3534 /**
3535 * xmlXPathNodeSetFreeNs:
3536 * @ns: the XPath namespace node found in a nodeset.
3537 *
3538 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3539 * the namespace nodes are duplicated and the next pointer is set to the
3540 * parent node in the XPath semantic. Check if such a node needs to be freed
3541 */
3542 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3543 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3544 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3545 return;
3546
3547 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3548 if (ns->href != NULL)
3549 xmlFree((xmlChar *)ns->href);
3550 if (ns->prefix != NULL)
3551 xmlFree((xmlChar *)ns->prefix);
3552 xmlFree(ns);
3553 }
3554 }
3555
3556 /**
3557 * xmlXPathNodeSetCreate:
3558 * @val: an initial xmlNodePtr, or NULL
3559 *
3560 * Create a new xmlNodeSetPtr of type double and of value @val
3561 *
3562 * Returns the newly created object.
3563 */
3564 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3565 xmlXPathNodeSetCreate(xmlNodePtr val) {
3566 xmlNodeSetPtr ret;
3567
3568 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3569 if (ret == NULL) {
3570 xmlXPathErrMemory(NULL, "creating nodeset\n");
3571 return(NULL);
3572 }
3573 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3574 if (val != NULL) {
3575 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3576 sizeof(xmlNodePtr));
3577 if (ret->nodeTab == NULL) {
3578 xmlXPathErrMemory(NULL, "creating nodeset\n");
3579 xmlFree(ret);
3580 return(NULL);
3581 }
3582 memset(ret->nodeTab, 0 ,
3583 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3584 ret->nodeMax = XML_NODESET_DEFAULT;
3585 if (val->type == XML_NAMESPACE_DECL) {
3586 xmlNsPtr ns = (xmlNsPtr) val;
3587
3588 /* TODO: Check memory error. */
3589 ret->nodeTab[ret->nodeNr++] =
3590 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3591 } else
3592 ret->nodeTab[ret->nodeNr++] = val;
3593 }
3594 return(ret);
3595 }
3596
3597 /**
3598 * xmlXPathNodeSetContains:
3599 * @cur: the node-set
3600 * @val: the node
3601 *
3602 * checks whether @cur contains @val
3603 *
3604 * Returns true (1) if @cur contains @val, false (0) otherwise
3605 */
3606 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3607 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3608 int i;
3609
3610 if ((cur == NULL) || (val == NULL)) return(0);
3611 if (val->type == XML_NAMESPACE_DECL) {
3612 for (i = 0; i < cur->nodeNr; i++) {
3613 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3614 xmlNsPtr ns1, ns2;
3615
3616 ns1 = (xmlNsPtr) val;
3617 ns2 = (xmlNsPtr) cur->nodeTab[i];
3618 if (ns1 == ns2)
3619 return(1);
3620 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3621 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3622 return(1);
3623 }
3624 }
3625 } else {
3626 for (i = 0; i < cur->nodeNr; i++) {
3627 if (cur->nodeTab[i] == val)
3628 return(1);
3629 }
3630 }
3631 return(0);
3632 }
3633
3634 /**
3635 * xmlXPathNodeSetAddNs:
3636 * @cur: the initial node set
3637 * @node: the hosting node
3638 * @ns: a the namespace node
3639 *
3640 * add a new namespace node to an existing NodeSet
3641 *
3642 * Returns 0 in case of success and -1 in case of error
3643 */
3644 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3645 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3646 int i;
3647
3648
3649 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3650 (ns->type != XML_NAMESPACE_DECL) ||
3651 (node->type != XML_ELEMENT_NODE))
3652 return(-1);
3653
3654 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3655 /*
3656 * prevent duplicates
3657 */
3658 for (i = 0;i < cur->nodeNr;i++) {
3659 if ((cur->nodeTab[i] != NULL) &&
3660 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3661 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3662 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3663 return(0);
3664 }
3665
3666 /*
3667 * grow the nodeTab if needed
3668 */
3669 if (cur->nodeMax == 0) {
3670 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3671 sizeof(xmlNodePtr));
3672 if (cur->nodeTab == NULL) {
3673 xmlXPathErrMemory(NULL, "growing nodeset\n");
3674 return(-1);
3675 }
3676 memset(cur->nodeTab, 0 ,
3677 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3678 cur->nodeMax = XML_NODESET_DEFAULT;
3679 } else if (cur->nodeNr == cur->nodeMax) {
3680 xmlNodePtr *temp;
3681
3682 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3683 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3684 return(-1);
3685 }
3686 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3687 sizeof(xmlNodePtr));
3688 if (temp == NULL) {
3689 xmlXPathErrMemory(NULL, "growing nodeset\n");
3690 return(-1);
3691 }
3692 cur->nodeMax *= 2;
3693 cur->nodeTab = temp;
3694 }
3695 /* TODO: Check memory error. */
3696 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3697 return(0);
3698 }
3699
3700 /**
3701 * xmlXPathNodeSetAdd:
3702 * @cur: the initial node set
3703 * @val: a new xmlNodePtr
3704 *
3705 * add a new xmlNodePtr to an existing NodeSet
3706 *
3707 * Returns 0 in case of success, and -1 in case of error
3708 */
3709 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3710 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3711 int i;
3712
3713 if ((cur == NULL) || (val == NULL)) return(-1);
3714
3715 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3716 /*
3717 * prevent duplicates
3718 */
3719 for (i = 0;i < cur->nodeNr;i++)
3720 if (cur->nodeTab[i] == val) return(0);
3721
3722 /*
3723 * grow the nodeTab if needed
3724 */
3725 if (cur->nodeMax == 0) {
3726 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3727 sizeof(xmlNodePtr));
3728 if (cur->nodeTab == NULL) {
3729 xmlXPathErrMemory(NULL, "growing nodeset\n");
3730 return(-1);
3731 }
3732 memset(cur->nodeTab, 0 ,
3733 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3734 cur->nodeMax = XML_NODESET_DEFAULT;
3735 } else if (cur->nodeNr == cur->nodeMax) {
3736 xmlNodePtr *temp;
3737
3738 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3739 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3740 return(-1);
3741 }
3742 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3743 sizeof(xmlNodePtr));
3744 if (temp == NULL) {
3745 xmlXPathErrMemory(NULL, "growing nodeset\n");
3746 return(-1);
3747 }
3748 cur->nodeMax *= 2;
3749 cur->nodeTab = temp;
3750 }
3751 if (val->type == XML_NAMESPACE_DECL) {
3752 xmlNsPtr ns = (xmlNsPtr) val;
3753
3754 /* TODO: Check memory error. */
3755 cur->nodeTab[cur->nodeNr++] =
3756 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3757 } else
3758 cur->nodeTab[cur->nodeNr++] = val;
3759 return(0);
3760 }
3761
3762 /**
3763 * xmlXPathNodeSetAddUnique:
3764 * @cur: the initial node set
3765 * @val: a new xmlNodePtr
3766 *
3767 * add a new xmlNodePtr to an existing NodeSet, optimized version
3768 * when we are sure the node is not already in the set.
3769 *
3770 * Returns 0 in case of success and -1 in case of failure
3771 */
3772 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3773 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3774 if ((cur == NULL) || (val == NULL)) return(-1);
3775
3776 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3777 /*
3778 * grow the nodeTab if needed
3779 */
3780 if (cur->nodeMax == 0) {
3781 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3782 sizeof(xmlNodePtr));
3783 if (cur->nodeTab == NULL) {
3784 xmlXPathErrMemory(NULL, "growing nodeset\n");
3785 return(-1);
3786 }
3787 memset(cur->nodeTab, 0 ,
3788 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3789 cur->nodeMax = XML_NODESET_DEFAULT;
3790 } else if (cur->nodeNr == cur->nodeMax) {
3791 xmlNodePtr *temp;
3792
3793 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3794 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3795 return(-1);
3796 }
3797 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3798 sizeof(xmlNodePtr));
3799 if (temp == NULL) {
3800 xmlXPathErrMemory(NULL, "growing nodeset\n");
3801 return(-1);
3802 }
3803 cur->nodeTab = temp;
3804 cur->nodeMax *= 2;
3805 }
3806 if (val->type == XML_NAMESPACE_DECL) {
3807 xmlNsPtr ns = (xmlNsPtr) val;
3808
3809 /* TODO: Check memory error. */
3810 cur->nodeTab[cur->nodeNr++] =
3811 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3812 } else
3813 cur->nodeTab[cur->nodeNr++] = val;
3814 return(0);
3815 }
3816
3817 /**
3818 * xmlXPathNodeSetMerge:
3819 * @val1: the first NodeSet or NULL
3820 * @val2: the second NodeSet
3821 *
3822 * Merges two nodesets, all nodes from @val2 are added to @val1
3823 * if @val1 is NULL, a new set is created and copied from @val2
3824 *
3825 * Returns @val1 once extended or NULL in case of error.
3826 */
3827 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3828 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3829 int i, j, initNr, skip;
3830 xmlNodePtr n1, n2;
3831
3832 if (val2 == NULL) return(val1);
3833 if (val1 == NULL) {
3834 val1 = xmlXPathNodeSetCreate(NULL);
3835 if (val1 == NULL)
3836 return (NULL);
3837 #if 0
3838 /*
3839 * TODO: The optimization won't work in every case, since
3840 * those nasty namespace nodes need to be added with
3841 * xmlXPathNodeSetDupNs() to the set; thus a pure
3842 * memcpy is not possible.
3843 * If there was a flag on the nodesetval, indicating that
3844 * some temporary nodes are in, that would be helpful.
3845 */
3846 /*
3847 * Optimization: Create an equally sized node-set
3848 * and memcpy the content.
3849 */
3850 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3851 if (val1 == NULL)
3852 return(NULL);
3853 if (val2->nodeNr != 0) {
3854 if (val2->nodeNr == 1)
3855 *(val1->nodeTab) = *(val2->nodeTab);
3856 else {
3857 memcpy(val1->nodeTab, val2->nodeTab,
3858 val2->nodeNr * sizeof(xmlNodePtr));
3859 }
3860 val1->nodeNr = val2->nodeNr;
3861 }
3862 return(val1);
3863 #endif
3864 }
3865
3866 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3867 initNr = val1->nodeNr;
3868
3869 for (i = 0;i < val2->nodeNr;i++) {
3870 n2 = val2->nodeTab[i];
3871 /*
3872 * check against duplicates
3873 */
3874 skip = 0;
3875 for (j = 0; j < initNr; j++) {
3876 n1 = val1->nodeTab[j];
3877 if (n1 == n2) {
3878 skip = 1;
3879 break;
3880 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3881 (n2->type == XML_NAMESPACE_DECL)) {
3882 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3883 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3884 ((xmlNsPtr) n2)->prefix)))
3885 {
3886 skip = 1;
3887 break;
3888 }
3889 }
3890 }
3891 if (skip)
3892 continue;
3893
3894 /*
3895 * grow the nodeTab if needed
3896 */
3897 if (val1->nodeMax == 0) {
3898 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3899 sizeof(xmlNodePtr));
3900 if (val1->nodeTab == NULL) {
3901 xmlXPathErrMemory(NULL, "merging nodeset\n");
3902 return(NULL);
3903 }
3904 memset(val1->nodeTab, 0 ,
3905 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906 val1->nodeMax = XML_NODESET_DEFAULT;
3907 } else if (val1->nodeNr == val1->nodeMax) {
3908 xmlNodePtr *temp;
3909
3910 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3911 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3912 return(NULL);
3913 }
3914 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3915 sizeof(xmlNodePtr));
3916 if (temp == NULL) {
3917 xmlXPathErrMemory(NULL, "merging nodeset\n");
3918 return(NULL);
3919 }
3920 val1->nodeTab = temp;
3921 val1->nodeMax *= 2;
3922 }
3923 if (n2->type == XML_NAMESPACE_DECL) {
3924 xmlNsPtr ns = (xmlNsPtr) n2;
3925
3926 /* TODO: Check memory error. */
3927 val1->nodeTab[val1->nodeNr++] =
3928 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3929 } else
3930 val1->nodeTab[val1->nodeNr++] = n2;
3931 }
3932
3933 return(val1);
3934 }
3935
3936
3937 /**
3938 * xmlXPathNodeSetMergeAndClear:
3939 * @set1: the first NodeSet or NULL
3940 * @set2: the second NodeSet
3941 *
3942 * Merges two nodesets, all nodes from @set2 are added to @set1.
3943 * Checks for duplicate nodes. Clears set2.
3944 *
3945 * Returns @set1 once extended or NULL in case of error.
3946 */
3947 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3948 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3949 {
3950 {
3951 int i, j, initNbSet1;
3952 xmlNodePtr n1, n2;
3953
3954 initNbSet1 = set1->nodeNr;
3955 for (i = 0;i < set2->nodeNr;i++) {
3956 n2 = set2->nodeTab[i];
3957 /*
3958 * Skip duplicates.
3959 */
3960 for (j = 0; j < initNbSet1; j++) {
3961 n1 = set1->nodeTab[j];
3962 if (n1 == n2) {
3963 goto skip_node;
3964 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3965 (n2->type == XML_NAMESPACE_DECL))
3966 {
3967 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3968 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3969 ((xmlNsPtr) n2)->prefix)))
3970 {
3971 /*
3972 * Free the namespace node.
3973 */
3974 set2->nodeTab[i] = NULL;
3975 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3976 goto skip_node;
3977 }
3978 }
3979 }
3980 /*
3981 * grow the nodeTab if needed
3982 */
3983 if (set1->nodeMax == 0) {
3984 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3985 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3986 if (set1->nodeTab == NULL) {
3987 xmlXPathErrMemory(NULL, "merging nodeset\n");
3988 return(NULL);
3989 }
3990 memset(set1->nodeTab, 0,
3991 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3992 set1->nodeMax = XML_NODESET_DEFAULT;
3993 } else if (set1->nodeNr >= set1->nodeMax) {
3994 xmlNodePtr *temp;
3995
3996 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3997 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3998 return(NULL);
3999 }
4000 temp = (xmlNodePtr *) xmlRealloc(
4001 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4002 if (temp == NULL) {
4003 xmlXPathErrMemory(NULL, "merging nodeset\n");
4004 return(NULL);
4005 }
4006 set1->nodeTab = temp;
4007 set1->nodeMax *= 2;
4008 }
4009 set1->nodeTab[set1->nodeNr++] = n2;
4010 skip_node:
4011 {}
4012 }
4013 }
4014 set2->nodeNr = 0;
4015 return(set1);
4016 }
4017
4018 /**
4019 * xmlXPathNodeSetMergeAndClearNoDupls:
4020 * @set1: the first NodeSet or NULL
4021 * @set2: the second NodeSet
4022 *
4023 * Merges two nodesets, all nodes from @set2 are added to @set1.
4024 * Doesn't check for duplicate nodes. Clears set2.
4025 *
4026 * Returns @set1 once extended or NULL in case of error.
4027 */
4028 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)4029 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4030 {
4031 {
4032 int i;
4033 xmlNodePtr n2;
4034
4035 for (i = 0;i < set2->nodeNr;i++) {
4036 n2 = set2->nodeTab[i];
4037 if (set1->nodeMax == 0) {
4038 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4039 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4040 if (set1->nodeTab == NULL) {
4041 xmlXPathErrMemory(NULL, "merging nodeset\n");
4042 return(NULL);
4043 }
4044 memset(set1->nodeTab, 0,
4045 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4046 set1->nodeMax = XML_NODESET_DEFAULT;
4047 } else if (set1->nodeNr >= set1->nodeMax) {
4048 xmlNodePtr *temp;
4049
4050 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4051 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4052 return(NULL);
4053 }
4054 temp = (xmlNodePtr *) xmlRealloc(
4055 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4056 if (temp == NULL) {
4057 xmlXPathErrMemory(NULL, "merging nodeset\n");
4058 return(NULL);
4059 }
4060 set1->nodeTab = temp;
4061 set1->nodeMax *= 2;
4062 }
4063 set1->nodeTab[set1->nodeNr++] = n2;
4064 }
4065 }
4066 set2->nodeNr = 0;
4067 return(set1);
4068 }
4069
4070 /**
4071 * xmlXPathNodeSetDel:
4072 * @cur: the initial node set
4073 * @val: an xmlNodePtr
4074 *
4075 * Removes an xmlNodePtr from an existing NodeSet
4076 */
4077 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4078 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4079 int i;
4080
4081 if (cur == NULL) return;
4082 if (val == NULL) return;
4083
4084 /*
4085 * find node in nodeTab
4086 */
4087 for (i = 0;i < cur->nodeNr;i++)
4088 if (cur->nodeTab[i] == val) break;
4089
4090 if (i >= cur->nodeNr) { /* not found */
4091 #ifdef DEBUG
4092 xmlGenericError(xmlGenericErrorContext,
4093 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4094 val->name);
4095 #endif
4096 return;
4097 }
4098 if ((cur->nodeTab[i] != NULL) &&
4099 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4100 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4101 cur->nodeNr--;
4102 for (;i < cur->nodeNr;i++)
4103 cur->nodeTab[i] = cur->nodeTab[i + 1];
4104 cur->nodeTab[cur->nodeNr] = NULL;
4105 }
4106
4107 /**
4108 * xmlXPathNodeSetRemove:
4109 * @cur: the initial node set
4110 * @val: the index to remove
4111 *
4112 * Removes an entry from an existing NodeSet list.
4113 */
4114 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4115 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4116 if (cur == NULL) return;
4117 if (val >= cur->nodeNr) return;
4118 if ((cur->nodeTab[val] != NULL) &&
4119 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4120 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4121 cur->nodeNr--;
4122 for (;val < cur->nodeNr;val++)
4123 cur->nodeTab[val] = cur->nodeTab[val + 1];
4124 cur->nodeTab[cur->nodeNr] = NULL;
4125 }
4126
4127 /**
4128 * xmlXPathFreeNodeSet:
4129 * @obj: the xmlNodeSetPtr to free
4130 *
4131 * Free the NodeSet compound (not the actual nodes !).
4132 */
4133 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4134 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4135 if (obj == NULL) return;
4136 if (obj->nodeTab != NULL) {
4137 int i;
4138
4139 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4140 for (i = 0;i < obj->nodeNr;i++)
4141 if ((obj->nodeTab[i] != NULL) &&
4142 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4143 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4144 xmlFree(obj->nodeTab);
4145 }
4146 xmlFree(obj);
4147 }
4148
4149 /**
4150 * xmlXPathNodeSetClearFromPos:
4151 * @set: the node set to be cleared
4152 * @pos: the start position to clear from
4153 *
4154 * Clears the list from temporary XPath objects (e.g. namespace nodes
4155 * are feed) starting with the entry at @pos, but does *not* free the list
4156 * itself. Sets the length of the list to @pos.
4157 */
4158 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4159 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4160 {
4161 if ((set == NULL) || (pos >= set->nodeNr))
4162 return;
4163 else if ((hasNsNodes)) {
4164 int i;
4165 xmlNodePtr node;
4166
4167 for (i = pos; i < set->nodeNr; i++) {
4168 node = set->nodeTab[i];
4169 if ((node != NULL) &&
4170 (node->type == XML_NAMESPACE_DECL))
4171 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4172 }
4173 }
4174 set->nodeNr = pos;
4175 }
4176
4177 /**
4178 * xmlXPathNodeSetClear:
4179 * @set: the node set to clear
4180 *
4181 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4182 * are feed), but does *not* free the list itself. Sets the length of the
4183 * list to 0.
4184 */
4185 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4186 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4187 {
4188 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4189 }
4190
4191 /**
4192 * xmlXPathNodeSetKeepLast:
4193 * @set: the node set to be cleared
4194 *
4195 * Move the last node to the first position and clear temporary XPath objects
4196 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4197 * to 1.
4198 */
4199 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4200 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4201 {
4202 int i;
4203 xmlNodePtr node;
4204
4205 if ((set == NULL) || (set->nodeNr <= 1))
4206 return;
4207 for (i = 0; i < set->nodeNr - 1; i++) {
4208 node = set->nodeTab[i];
4209 if ((node != NULL) &&
4210 (node->type == XML_NAMESPACE_DECL))
4211 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4212 }
4213 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4214 set->nodeNr = 1;
4215 }
4216
4217 /**
4218 * xmlXPathFreeValueTree:
4219 * @obj: the xmlNodeSetPtr to free
4220 *
4221 * Free the NodeSet compound and the actual tree, this is different
4222 * from xmlXPathFreeNodeSet()
4223 */
4224 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4225 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4226 int i;
4227
4228 if (obj == NULL) return;
4229
4230 if (obj->nodeTab != NULL) {
4231 for (i = 0;i < obj->nodeNr;i++) {
4232 if (obj->nodeTab[i] != NULL) {
4233 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4234 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4235 } else {
4236 xmlFreeNodeList(obj->nodeTab[i]);
4237 }
4238 }
4239 }
4240 xmlFree(obj->nodeTab);
4241 }
4242 xmlFree(obj);
4243 }
4244
4245 #if defined(DEBUG) || defined(DEBUG_STEP)
4246 /**
4247 * xmlGenericErrorContextNodeSet:
4248 * @output: a FILE * for the output
4249 * @obj: the xmlNodeSetPtr to display
4250 *
4251 * Quick display of a NodeSet
4252 */
4253 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4254 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4255 int i;
4256
4257 if (output == NULL) output = xmlGenericErrorContext;
4258 if (obj == NULL) {
4259 fprintf(output, "NodeSet == NULL !\n");
4260 return;
4261 }
4262 if (obj->nodeNr == 0) {
4263 fprintf(output, "NodeSet is empty\n");
4264 return;
4265 }
4266 if (obj->nodeTab == NULL) {
4267 fprintf(output, " nodeTab == NULL !\n");
4268 return;
4269 }
4270 for (i = 0; i < obj->nodeNr; i++) {
4271 if (obj->nodeTab[i] == NULL) {
4272 fprintf(output, " NULL !\n");
4273 return;
4274 }
4275 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4276 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4277 fprintf(output, " /");
4278 else if (obj->nodeTab[i]->name == NULL)
4279 fprintf(output, " noname!");
4280 else fprintf(output, " %s", obj->nodeTab[i]->name);
4281 }
4282 fprintf(output, "\n");
4283 }
4284 #endif
4285
4286 /**
4287 * xmlXPathNewNodeSet:
4288 * @val: the NodePtr value
4289 *
4290 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4291 * it with the single Node @val
4292 *
4293 * Returns the newly created object.
4294 */
4295 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4296 xmlXPathNewNodeSet(xmlNodePtr val) {
4297 xmlXPathObjectPtr ret;
4298
4299 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4300 if (ret == NULL) {
4301 xmlXPathErrMemory(NULL, "creating nodeset\n");
4302 return(NULL);
4303 }
4304 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4305 ret->type = XPATH_NODESET;
4306 ret->boolval = 0;
4307 /* TODO: Check memory error. */
4308 ret->nodesetval = xmlXPathNodeSetCreate(val);
4309 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4310 #ifdef XP_DEBUG_OBJ_USAGE
4311 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4312 #endif
4313 return(ret);
4314 }
4315
4316 /**
4317 * xmlXPathNewValueTree:
4318 * @val: the NodePtr value
4319 *
4320 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4321 * it with the tree root @val
4322 *
4323 * Returns the newly created object.
4324 */
4325 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4326 xmlXPathNewValueTree(xmlNodePtr val) {
4327 xmlXPathObjectPtr ret;
4328
4329 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4330 if (ret == NULL) {
4331 xmlXPathErrMemory(NULL, "creating result value tree\n");
4332 return(NULL);
4333 }
4334 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4335 ret->type = XPATH_XSLT_TREE;
4336 ret->boolval = 1;
4337 ret->user = (void *) val;
4338 ret->nodesetval = xmlXPathNodeSetCreate(val);
4339 #ifdef XP_DEBUG_OBJ_USAGE
4340 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4341 #endif
4342 return(ret);
4343 }
4344
4345 /**
4346 * xmlXPathNewNodeSetList:
4347 * @val: an existing NodeSet
4348 *
4349 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4350 * it with the Nodeset @val
4351 *
4352 * Returns the newly created object.
4353 */
4354 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4355 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4356 {
4357 xmlXPathObjectPtr ret;
4358 int i;
4359
4360 if (val == NULL)
4361 ret = NULL;
4362 else if (val->nodeTab == NULL)
4363 ret = xmlXPathNewNodeSet(NULL);
4364 else {
4365 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4366 if (ret) {
4367 for (i = 1; i < val->nodeNr; ++i) {
4368 /* TODO: Propagate memory error. */
4369 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4370 < 0) break;
4371 }
4372 }
4373 }
4374
4375 return (ret);
4376 }
4377
4378 /**
4379 * xmlXPathWrapNodeSet:
4380 * @val: the NodePtr value
4381 *
4382 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4383 *
4384 * Returns the newly created object.
4385 */
4386 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4387 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4388 xmlXPathObjectPtr ret;
4389
4390 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4391 if (ret == NULL) {
4392 xmlXPathErrMemory(NULL, "creating node set object\n");
4393 return(NULL);
4394 }
4395 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4396 ret->type = XPATH_NODESET;
4397 ret->nodesetval = val;
4398 #ifdef XP_DEBUG_OBJ_USAGE
4399 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4400 #endif
4401 return(ret);
4402 }
4403
4404 /**
4405 * xmlXPathFreeNodeSetList:
4406 * @obj: an existing NodeSetList object
4407 *
4408 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4409 * the list contrary to xmlXPathFreeObject().
4410 */
4411 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4412 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4413 if (obj == NULL) return;
4414 #ifdef XP_DEBUG_OBJ_USAGE
4415 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4416 #endif
4417 xmlFree(obj);
4418 }
4419
4420 /**
4421 * xmlXPathDifference:
4422 * @nodes1: a node-set
4423 * @nodes2: a node-set
4424 *
4425 * Implements the EXSLT - Sets difference() function:
4426 * node-set set:difference (node-set, node-set)
4427 *
4428 * Returns the difference between the two node sets, or nodes1 if
4429 * nodes2 is empty
4430 */
4431 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4432 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433 xmlNodeSetPtr ret;
4434 int i, l1;
4435 xmlNodePtr cur;
4436
4437 if (xmlXPathNodeSetIsEmpty(nodes2))
4438 return(nodes1);
4439
4440 /* TODO: Check memory error. */
4441 ret = xmlXPathNodeSetCreate(NULL);
4442 if (xmlXPathNodeSetIsEmpty(nodes1))
4443 return(ret);
4444
4445 l1 = xmlXPathNodeSetGetLength(nodes1);
4446
4447 for (i = 0; i < l1; i++) {
4448 cur = xmlXPathNodeSetItem(nodes1, i);
4449 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4450 /* TODO: Propagate memory error. */
4451 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4452 break;
4453 }
4454 }
4455 return(ret);
4456 }
4457
4458 /**
4459 * xmlXPathIntersection:
4460 * @nodes1: a node-set
4461 * @nodes2: a node-set
4462 *
4463 * Implements the EXSLT - Sets intersection() function:
4464 * node-set set:intersection (node-set, node-set)
4465 *
4466 * Returns a node set comprising the nodes that are within both the
4467 * node sets passed as arguments
4468 */
4469 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4470 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4471 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4472 int i, l1;
4473 xmlNodePtr cur;
4474
4475 if (ret == NULL)
4476 return(ret);
4477 if (xmlXPathNodeSetIsEmpty(nodes1))
4478 return(ret);
4479 if (xmlXPathNodeSetIsEmpty(nodes2))
4480 return(ret);
4481
4482 l1 = xmlXPathNodeSetGetLength(nodes1);
4483
4484 for (i = 0; i < l1; i++) {
4485 cur = xmlXPathNodeSetItem(nodes1, i);
4486 if (xmlXPathNodeSetContains(nodes2, cur)) {
4487 /* TODO: Propagate memory error. */
4488 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4489 break;
4490 }
4491 }
4492 return(ret);
4493 }
4494
4495 /**
4496 * xmlXPathDistinctSorted:
4497 * @nodes: a node-set, sorted by document order
4498 *
4499 * Implements the EXSLT - Sets distinct() function:
4500 * node-set set:distinct (node-set)
4501 *
4502 * Returns a subset of the nodes contained in @nodes, or @nodes if
4503 * it is empty
4504 */
4505 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4506 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4507 xmlNodeSetPtr ret;
4508 xmlHashTablePtr hash;
4509 int i, l;
4510 xmlChar * strval;
4511 xmlNodePtr cur;
4512
4513 if (xmlXPathNodeSetIsEmpty(nodes))
4514 return(nodes);
4515
4516 ret = xmlXPathNodeSetCreate(NULL);
4517 if (ret == NULL)
4518 return(ret);
4519 l = xmlXPathNodeSetGetLength(nodes);
4520 hash = xmlHashCreate (l);
4521 for (i = 0; i < l; i++) {
4522 cur = xmlXPathNodeSetItem(nodes, i);
4523 strval = xmlXPathCastNodeToString(cur);
4524 if (xmlHashLookup(hash, strval) == NULL) {
4525 xmlHashAddEntry(hash, strval, strval);
4526 /* TODO: Propagate memory error. */
4527 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4528 break;
4529 } else {
4530 xmlFree(strval);
4531 }
4532 }
4533 xmlHashFree(hash, xmlHashDefaultDeallocator);
4534 return(ret);
4535 }
4536
4537 /**
4538 * xmlXPathDistinct:
4539 * @nodes: a node-set
4540 *
4541 * Implements the EXSLT - Sets distinct() function:
4542 * node-set set:distinct (node-set)
4543 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4544 * is called with the sorted node-set
4545 *
4546 * Returns a subset of the nodes contained in @nodes, or @nodes if
4547 * it is empty
4548 */
4549 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4550 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4551 if (xmlXPathNodeSetIsEmpty(nodes))
4552 return(nodes);
4553
4554 xmlXPathNodeSetSort(nodes);
4555 return(xmlXPathDistinctSorted(nodes));
4556 }
4557
4558 /**
4559 * xmlXPathHasSameNodes:
4560 * @nodes1: a node-set
4561 * @nodes2: a node-set
4562 *
4563 * Implements the EXSLT - Sets has-same-nodes function:
4564 * boolean set:has-same-node(node-set, node-set)
4565 *
4566 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4567 * otherwise
4568 */
4569 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4570 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4571 int i, l;
4572 xmlNodePtr cur;
4573
4574 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4575 xmlXPathNodeSetIsEmpty(nodes2))
4576 return(0);
4577
4578 l = xmlXPathNodeSetGetLength(nodes1);
4579 for (i = 0; i < l; i++) {
4580 cur = xmlXPathNodeSetItem(nodes1, i);
4581 if (xmlXPathNodeSetContains(nodes2, cur))
4582 return(1);
4583 }
4584 return(0);
4585 }
4586
4587 /**
4588 * xmlXPathNodeLeadingSorted:
4589 * @nodes: a node-set, sorted by document order
4590 * @node: a node
4591 *
4592 * Implements the EXSLT - Sets leading() function:
4593 * node-set set:leading (node-set, node-set)
4594 *
4595 * Returns the nodes in @nodes that precede @node in document order,
4596 * @nodes if @node is NULL or an empty node-set if @nodes
4597 * doesn't contain @node
4598 */
4599 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4600 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4601 int i, l;
4602 xmlNodePtr cur;
4603 xmlNodeSetPtr ret;
4604
4605 if (node == NULL)
4606 return(nodes);
4607
4608 ret = xmlXPathNodeSetCreate(NULL);
4609 if (ret == NULL)
4610 return(ret);
4611 if (xmlXPathNodeSetIsEmpty(nodes) ||
4612 (!xmlXPathNodeSetContains(nodes, node)))
4613 return(ret);
4614
4615 l = xmlXPathNodeSetGetLength(nodes);
4616 for (i = 0; i < l; i++) {
4617 cur = xmlXPathNodeSetItem(nodes, i);
4618 if (cur == node)
4619 break;
4620 /* TODO: Propagate memory error. */
4621 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4622 break;
4623 }
4624 return(ret);
4625 }
4626
4627 /**
4628 * xmlXPathNodeLeading:
4629 * @nodes: a node-set
4630 * @node: a node
4631 *
4632 * Implements the EXSLT - Sets leading() function:
4633 * node-set set:leading (node-set, node-set)
4634 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4635 * is called.
4636 *
4637 * Returns the nodes in @nodes that precede @node in document order,
4638 * @nodes if @node is NULL or an empty node-set if @nodes
4639 * doesn't contain @node
4640 */
4641 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4642 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4643 xmlXPathNodeSetSort(nodes);
4644 return(xmlXPathNodeLeadingSorted(nodes, node));
4645 }
4646
4647 /**
4648 * xmlXPathLeadingSorted:
4649 * @nodes1: a node-set, sorted by document order
4650 * @nodes2: a node-set, sorted by document order
4651 *
4652 * Implements the EXSLT - Sets leading() function:
4653 * node-set set:leading (node-set, node-set)
4654 *
4655 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4656 * in document order, @nodes1 if @nodes2 is NULL or empty or
4657 * an empty node-set if @nodes1 doesn't contain @nodes2
4658 */
4659 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4660 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4661 if (xmlXPathNodeSetIsEmpty(nodes2))
4662 return(nodes1);
4663 return(xmlXPathNodeLeadingSorted(nodes1,
4664 xmlXPathNodeSetItem(nodes2, 1)));
4665 }
4666
4667 /**
4668 * xmlXPathLeading:
4669 * @nodes1: a node-set
4670 * @nodes2: a node-set
4671 *
4672 * Implements the EXSLT - Sets leading() function:
4673 * node-set set:leading (node-set, node-set)
4674 * @nodes1 and @nodes2 are sorted by document order, then
4675 * #exslSetsLeadingSorted is called.
4676 *
4677 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4678 * in document order, @nodes1 if @nodes2 is NULL or empty or
4679 * an empty node-set if @nodes1 doesn't contain @nodes2
4680 */
4681 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4682 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4683 if (xmlXPathNodeSetIsEmpty(nodes2))
4684 return(nodes1);
4685 if (xmlXPathNodeSetIsEmpty(nodes1))
4686 return(xmlXPathNodeSetCreate(NULL));
4687 xmlXPathNodeSetSort(nodes1);
4688 xmlXPathNodeSetSort(nodes2);
4689 return(xmlXPathNodeLeadingSorted(nodes1,
4690 xmlXPathNodeSetItem(nodes2, 1)));
4691 }
4692
4693 /**
4694 * xmlXPathNodeTrailingSorted:
4695 * @nodes: a node-set, sorted by document order
4696 * @node: a node
4697 *
4698 * Implements the EXSLT - Sets trailing() function:
4699 * node-set set:trailing (node-set, node-set)
4700 *
4701 * Returns the nodes in @nodes that follow @node in document order,
4702 * @nodes if @node is NULL or an empty node-set if @nodes
4703 * doesn't contain @node
4704 */
4705 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4706 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4707 int i, l;
4708 xmlNodePtr cur;
4709 xmlNodeSetPtr ret;
4710
4711 if (node == NULL)
4712 return(nodes);
4713
4714 ret = xmlXPathNodeSetCreate(NULL);
4715 if (ret == NULL)
4716 return(ret);
4717 if (xmlXPathNodeSetIsEmpty(nodes) ||
4718 (!xmlXPathNodeSetContains(nodes, node)))
4719 return(ret);
4720
4721 l = xmlXPathNodeSetGetLength(nodes);
4722 for (i = l - 1; i >= 0; i--) {
4723 cur = xmlXPathNodeSetItem(nodes, i);
4724 if (cur == node)
4725 break;
4726 /* TODO: Propagate memory error. */
4727 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4728 break;
4729 }
4730 xmlXPathNodeSetSort(ret); /* bug 413451 */
4731 return(ret);
4732 }
4733
4734 /**
4735 * xmlXPathNodeTrailing:
4736 * @nodes: a node-set
4737 * @node: a node
4738 *
4739 * Implements the EXSLT - Sets trailing() function:
4740 * node-set set:trailing (node-set, node-set)
4741 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4742 * is called.
4743 *
4744 * Returns the nodes in @nodes that follow @node in document order,
4745 * @nodes if @node is NULL or an empty node-set if @nodes
4746 * doesn't contain @node
4747 */
4748 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4749 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4750 xmlXPathNodeSetSort(nodes);
4751 return(xmlXPathNodeTrailingSorted(nodes, node));
4752 }
4753
4754 /**
4755 * xmlXPathTrailingSorted:
4756 * @nodes1: a node-set, sorted by document order
4757 * @nodes2: a node-set, sorted by document order
4758 *
4759 * Implements the EXSLT - Sets trailing() function:
4760 * node-set set:trailing (node-set, node-set)
4761 *
4762 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4763 * in document order, @nodes1 if @nodes2 is NULL or empty or
4764 * an empty node-set if @nodes1 doesn't contain @nodes2
4765 */
4766 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4767 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4768 if (xmlXPathNodeSetIsEmpty(nodes2))
4769 return(nodes1);
4770 return(xmlXPathNodeTrailingSorted(nodes1,
4771 xmlXPathNodeSetItem(nodes2, 0)));
4772 }
4773
4774 /**
4775 * xmlXPathTrailing:
4776 * @nodes1: a node-set
4777 * @nodes2: a node-set
4778 *
4779 * Implements the EXSLT - Sets trailing() function:
4780 * node-set set:trailing (node-set, node-set)
4781 * @nodes1 and @nodes2 are sorted by document order, then
4782 * #xmlXPathTrailingSorted is called.
4783 *
4784 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4785 * in document order, @nodes1 if @nodes2 is NULL or empty or
4786 * an empty node-set if @nodes1 doesn't contain @nodes2
4787 */
4788 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4789 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4790 if (xmlXPathNodeSetIsEmpty(nodes2))
4791 return(nodes1);
4792 if (xmlXPathNodeSetIsEmpty(nodes1))
4793 return(xmlXPathNodeSetCreate(NULL));
4794 xmlXPathNodeSetSort(nodes1);
4795 xmlXPathNodeSetSort(nodes2);
4796 return(xmlXPathNodeTrailingSorted(nodes1,
4797 xmlXPathNodeSetItem(nodes2, 0)));
4798 }
4799
4800 /************************************************************************
4801 * *
4802 * Routines to handle extra functions *
4803 * *
4804 ************************************************************************/
4805
4806 /**
4807 * xmlXPathRegisterFunc:
4808 * @ctxt: the XPath context
4809 * @name: the function name
4810 * @f: the function implementation or NULL
4811 *
4812 * Register a new function. If @f is NULL it unregisters the function
4813 *
4814 * Returns 0 in case of success, -1 in case of error
4815 */
4816 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4817 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4818 xmlXPathFunction f) {
4819 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4820 }
4821
4822 /**
4823 * xmlXPathRegisterFuncNS:
4824 * @ctxt: the XPath context
4825 * @name: the function name
4826 * @ns_uri: the function namespace URI
4827 * @f: the function implementation or NULL
4828 *
4829 * Register a new function. If @f is NULL it unregisters the function
4830 *
4831 * Returns 0 in case of success, -1 in case of error
4832 */
4833 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4834 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4835 const xmlChar *ns_uri, xmlXPathFunction f) {
4836 if (ctxt == NULL)
4837 return(-1);
4838 if (name == NULL)
4839 return(-1);
4840
4841 if (ctxt->funcHash == NULL)
4842 ctxt->funcHash = xmlHashCreate(0);
4843 if (ctxt->funcHash == NULL)
4844 return(-1);
4845 if (f == NULL)
4846 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4847 XML_IGNORE_PEDANTIC_WARNINGS
4848 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4849 XML_POP_WARNINGS
4850 }
4851
4852 /**
4853 * xmlXPathRegisterFuncLookup:
4854 * @ctxt: the XPath context
4855 * @f: the lookup function
4856 * @funcCtxt: the lookup data
4857 *
4858 * Registers an external mechanism to do function lookup.
4859 */
4860 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4861 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4862 xmlXPathFuncLookupFunc f,
4863 void *funcCtxt) {
4864 if (ctxt == NULL)
4865 return;
4866 ctxt->funcLookupFunc = f;
4867 ctxt->funcLookupData = funcCtxt;
4868 }
4869
4870 /**
4871 * xmlXPathFunctionLookup:
4872 * @ctxt: the XPath context
4873 * @name: the function name
4874 *
4875 * Search in the Function array of the context for the given
4876 * function.
4877 *
4878 * Returns the xmlXPathFunction or NULL if not found
4879 */
4880 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4881 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4882 if (ctxt == NULL)
4883 return (NULL);
4884
4885 if (ctxt->funcLookupFunc != NULL) {
4886 xmlXPathFunction ret;
4887 xmlXPathFuncLookupFunc f;
4888
4889 f = ctxt->funcLookupFunc;
4890 ret = f(ctxt->funcLookupData, name, NULL);
4891 if (ret != NULL)
4892 return(ret);
4893 }
4894 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4895 }
4896
4897 /**
4898 * xmlXPathFunctionLookupNS:
4899 * @ctxt: the XPath context
4900 * @name: the function name
4901 * @ns_uri: the function namespace URI
4902 *
4903 * Search in the Function array of the context for the given
4904 * function.
4905 *
4906 * Returns the xmlXPathFunction or NULL if not found
4907 */
4908 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4909 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4910 const xmlChar *ns_uri) {
4911 xmlXPathFunction ret;
4912
4913 if (ctxt == NULL)
4914 return(NULL);
4915 if (name == NULL)
4916 return(NULL);
4917
4918 if (ctxt->funcLookupFunc != NULL) {
4919 xmlXPathFuncLookupFunc f;
4920
4921 f = ctxt->funcLookupFunc;
4922 ret = f(ctxt->funcLookupData, name, ns_uri);
4923 if (ret != NULL)
4924 return(ret);
4925 }
4926
4927 if (ctxt->funcHash == NULL)
4928 return(NULL);
4929
4930 XML_IGNORE_PEDANTIC_WARNINGS
4931 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4932 XML_POP_WARNINGS
4933 return(ret);
4934 }
4935
4936 /**
4937 * xmlXPathRegisteredFuncsCleanup:
4938 * @ctxt: the XPath context
4939 *
4940 * Cleanup the XPath context data associated to registered functions
4941 */
4942 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4943 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4944 if (ctxt == NULL)
4945 return;
4946
4947 xmlHashFree(ctxt->funcHash, NULL);
4948 ctxt->funcHash = NULL;
4949 }
4950
4951 /************************************************************************
4952 * *
4953 * Routines to handle Variables *
4954 * *
4955 ************************************************************************/
4956
4957 /**
4958 * xmlXPathRegisterVariable:
4959 * @ctxt: the XPath context
4960 * @name: the variable name
4961 * @value: the variable value or NULL
4962 *
4963 * Register a new variable value. If @value is NULL it unregisters
4964 * the variable
4965 *
4966 * Returns 0 in case of success, -1 in case of error
4967 */
4968 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4969 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4970 xmlXPathObjectPtr value) {
4971 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4972 }
4973
4974 /**
4975 * xmlXPathRegisterVariableNS:
4976 * @ctxt: the XPath context
4977 * @name: the variable name
4978 * @ns_uri: the variable namespace URI
4979 * @value: the variable value or NULL
4980 *
4981 * Register a new variable value. If @value is NULL it unregisters
4982 * the variable
4983 *
4984 * Returns 0 in case of success, -1 in case of error
4985 */
4986 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4987 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4988 const xmlChar *ns_uri,
4989 xmlXPathObjectPtr value) {
4990 if (ctxt == NULL)
4991 return(-1);
4992 if (name == NULL)
4993 return(-1);
4994
4995 if (ctxt->varHash == NULL)
4996 ctxt->varHash = xmlHashCreate(0);
4997 if (ctxt->varHash == NULL)
4998 return(-1);
4999 if (value == NULL)
5000 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5001 xmlXPathFreeObjectEntry));
5002 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5003 (void *) value, xmlXPathFreeObjectEntry));
5004 }
5005
5006 /**
5007 * xmlXPathRegisterVariableLookup:
5008 * @ctxt: the XPath context
5009 * @f: the lookup function
5010 * @data: the lookup data
5011 *
5012 * register an external mechanism to do variable lookup
5013 */
5014 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5015 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5016 xmlXPathVariableLookupFunc f, void *data) {
5017 if (ctxt == NULL)
5018 return;
5019 ctxt->varLookupFunc = f;
5020 ctxt->varLookupData = data;
5021 }
5022
5023 /**
5024 * xmlXPathVariableLookup:
5025 * @ctxt: the XPath context
5026 * @name: the variable name
5027 *
5028 * Search in the Variable array of the context for the given
5029 * variable value.
5030 *
5031 * Returns a copy of the value or NULL if not found
5032 */
5033 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5034 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5035 if (ctxt == NULL)
5036 return(NULL);
5037
5038 if (ctxt->varLookupFunc != NULL) {
5039 xmlXPathObjectPtr ret;
5040
5041 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5042 (ctxt->varLookupData, name, NULL);
5043 return(ret);
5044 }
5045 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5046 }
5047
5048 /**
5049 * xmlXPathVariableLookupNS:
5050 * @ctxt: the XPath context
5051 * @name: the variable name
5052 * @ns_uri: the variable namespace URI
5053 *
5054 * Search in the Variable array of the context for the given
5055 * variable value.
5056 *
5057 * Returns the a copy of the value or NULL if not found
5058 */
5059 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5060 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5061 const xmlChar *ns_uri) {
5062 if (ctxt == NULL)
5063 return(NULL);
5064
5065 if (ctxt->varLookupFunc != NULL) {
5066 xmlXPathObjectPtr ret;
5067
5068 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5069 (ctxt->varLookupData, name, ns_uri);
5070 if (ret != NULL) return(ret);
5071 }
5072
5073 if (ctxt->varHash == NULL)
5074 return(NULL);
5075 if (name == NULL)
5076 return(NULL);
5077
5078 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5079 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5080 }
5081
5082 /**
5083 * xmlXPathRegisteredVariablesCleanup:
5084 * @ctxt: the XPath context
5085 *
5086 * Cleanup the XPath context data associated to registered variables
5087 */
5088 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5089 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5090 if (ctxt == NULL)
5091 return;
5092
5093 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5094 ctxt->varHash = NULL;
5095 }
5096
5097 /**
5098 * xmlXPathRegisterNs:
5099 * @ctxt: the XPath context
5100 * @prefix: the namespace prefix cannot be NULL or empty string
5101 * @ns_uri: the namespace name
5102 *
5103 * Register a new namespace. If @ns_uri is NULL it unregisters
5104 * the namespace
5105 *
5106 * Returns 0 in case of success, -1 in case of error
5107 */
5108 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5109 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5110 const xmlChar *ns_uri) {
5111 if (ctxt == NULL)
5112 return(-1);
5113 if (prefix == NULL)
5114 return(-1);
5115 if (prefix[0] == 0)
5116 return(-1);
5117
5118 if (ctxt->nsHash == NULL)
5119 ctxt->nsHash = xmlHashCreate(10);
5120 if (ctxt->nsHash == NULL)
5121 return(-1);
5122 if (ns_uri == NULL)
5123 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5124 xmlHashDefaultDeallocator));
5125 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5126 xmlHashDefaultDeallocator));
5127 }
5128
5129 /**
5130 * xmlXPathNsLookup:
5131 * @ctxt: the XPath context
5132 * @prefix: the namespace prefix value
5133 *
5134 * Search in the namespace declaration array of the context for the given
5135 * namespace name associated to the given prefix
5136 *
5137 * Returns the value or NULL if not found
5138 */
5139 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5140 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5141 if (ctxt == NULL)
5142 return(NULL);
5143 if (prefix == NULL)
5144 return(NULL);
5145
5146 #ifdef XML_XML_NAMESPACE
5147 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5148 return(XML_XML_NAMESPACE);
5149 #endif
5150
5151 if (ctxt->namespaces != NULL) {
5152 int i;
5153
5154 for (i = 0;i < ctxt->nsNr;i++) {
5155 if ((ctxt->namespaces[i] != NULL) &&
5156 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5157 return(ctxt->namespaces[i]->href);
5158 }
5159 }
5160
5161 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5162 }
5163
5164 /**
5165 * xmlXPathRegisteredNsCleanup:
5166 * @ctxt: the XPath context
5167 *
5168 * Cleanup the XPath context data associated to registered variables
5169 */
5170 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5171 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5172 if (ctxt == NULL)
5173 return;
5174
5175 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5176 ctxt->nsHash = NULL;
5177 }
5178
5179 /************************************************************************
5180 * *
5181 * Routines to handle Values *
5182 * *
5183 ************************************************************************/
5184
5185 /* Allocations are terrible, one needs to optimize all this !!! */
5186
5187 /**
5188 * xmlXPathNewFloat:
5189 * @val: the double value
5190 *
5191 * Create a new xmlXPathObjectPtr of type double and of value @val
5192 *
5193 * Returns the newly created object.
5194 */
5195 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5196 xmlXPathNewFloat(double val) {
5197 xmlXPathObjectPtr ret;
5198
5199 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5200 if (ret == NULL) {
5201 xmlXPathErrMemory(NULL, "creating float object\n");
5202 return(NULL);
5203 }
5204 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5205 ret->type = XPATH_NUMBER;
5206 ret->floatval = val;
5207 #ifdef XP_DEBUG_OBJ_USAGE
5208 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5209 #endif
5210 return(ret);
5211 }
5212
5213 /**
5214 * xmlXPathNewBoolean:
5215 * @val: the boolean value
5216 *
5217 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5218 *
5219 * Returns the newly created object.
5220 */
5221 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5222 xmlXPathNewBoolean(int val) {
5223 xmlXPathObjectPtr ret;
5224
5225 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5226 if (ret == NULL) {
5227 xmlXPathErrMemory(NULL, "creating boolean object\n");
5228 return(NULL);
5229 }
5230 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5231 ret->type = XPATH_BOOLEAN;
5232 ret->boolval = (val != 0);
5233 #ifdef XP_DEBUG_OBJ_USAGE
5234 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5235 #endif
5236 return(ret);
5237 }
5238
5239 /**
5240 * xmlXPathNewString:
5241 * @val: the xmlChar * value
5242 *
5243 * Create a new xmlXPathObjectPtr of type string and of value @val
5244 *
5245 * Returns the newly created object.
5246 */
5247 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5248 xmlXPathNewString(const xmlChar *val) {
5249 xmlXPathObjectPtr ret;
5250
5251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252 if (ret == NULL) {
5253 xmlXPathErrMemory(NULL, "creating string object\n");
5254 return(NULL);
5255 }
5256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257 ret->type = XPATH_STRING;
5258 if (val != NULL)
5259 ret->stringval = xmlStrdup(val);
5260 else
5261 ret->stringval = xmlStrdup((const xmlChar *)"");
5262 #ifdef XP_DEBUG_OBJ_USAGE
5263 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5264 #endif
5265 return(ret);
5266 }
5267
5268 /**
5269 * xmlXPathWrapString:
5270 * @val: the xmlChar * value
5271 *
5272 * Wraps the @val string into an XPath object.
5273 *
5274 * Returns the newly created object.
5275 */
5276 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5277 xmlXPathWrapString (xmlChar *val) {
5278 xmlXPathObjectPtr ret;
5279
5280 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281 if (ret == NULL) {
5282 xmlXPathErrMemory(NULL, "creating string object\n");
5283 return(NULL);
5284 }
5285 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5286 ret->type = XPATH_STRING;
5287 ret->stringval = val;
5288 #ifdef XP_DEBUG_OBJ_USAGE
5289 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5290 #endif
5291 return(ret);
5292 }
5293
5294 /**
5295 * xmlXPathNewCString:
5296 * @val: the char * value
5297 *
5298 * Create a new xmlXPathObjectPtr of type string and of value @val
5299 *
5300 * Returns the newly created object.
5301 */
5302 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5303 xmlXPathNewCString(const char *val) {
5304 xmlXPathObjectPtr ret;
5305
5306 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5307 if (ret == NULL) {
5308 xmlXPathErrMemory(NULL, "creating string object\n");
5309 return(NULL);
5310 }
5311 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5312 ret->type = XPATH_STRING;
5313 ret->stringval = xmlStrdup(BAD_CAST val);
5314 #ifdef XP_DEBUG_OBJ_USAGE
5315 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5316 #endif
5317 return(ret);
5318 }
5319
5320 /**
5321 * xmlXPathWrapCString:
5322 * @val: the char * value
5323 *
5324 * Wraps a string into an XPath object.
5325 *
5326 * Returns the newly created object.
5327 */
5328 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5329 xmlXPathWrapCString (char * val) {
5330 return(xmlXPathWrapString((xmlChar *)(val)));
5331 }
5332
5333 /**
5334 * xmlXPathWrapExternal:
5335 * @val: the user data
5336 *
5337 * Wraps the @val data into an XPath object.
5338 *
5339 * Returns the newly created object.
5340 */
5341 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5342 xmlXPathWrapExternal (void *val) {
5343 xmlXPathObjectPtr ret;
5344
5345 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5346 if (ret == NULL) {
5347 xmlXPathErrMemory(NULL, "creating user object\n");
5348 return(NULL);
5349 }
5350 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5351 ret->type = XPATH_USERS;
5352 ret->user = val;
5353 #ifdef XP_DEBUG_OBJ_USAGE
5354 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5355 #endif
5356 return(ret);
5357 }
5358
5359 /**
5360 * xmlXPathObjectCopy:
5361 * @val: the original object
5362 *
5363 * allocate a new copy of a given object
5364 *
5365 * Returns the newly created object.
5366 */
5367 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5368 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5369 xmlXPathObjectPtr ret;
5370
5371 if (val == NULL)
5372 return(NULL);
5373
5374 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5375 if (ret == NULL) {
5376 xmlXPathErrMemory(NULL, "copying object\n");
5377 return(NULL);
5378 }
5379 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5380 #ifdef XP_DEBUG_OBJ_USAGE
5381 xmlXPathDebugObjUsageRequested(NULL, val->type);
5382 #endif
5383 switch (val->type) {
5384 case XPATH_BOOLEAN:
5385 case XPATH_NUMBER:
5386 case XPATH_POINT:
5387 case XPATH_RANGE:
5388 break;
5389 case XPATH_STRING:
5390 ret->stringval = xmlStrdup(val->stringval);
5391 break;
5392 case XPATH_XSLT_TREE:
5393 #if 0
5394 /*
5395 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5396 this previous handling is no longer correct, and can cause some serious
5397 problems (ref. bug 145547)
5398 */
5399 if ((val->nodesetval != NULL) &&
5400 (val->nodesetval->nodeTab != NULL)) {
5401 xmlNodePtr cur, tmp;
5402 xmlDocPtr top;
5403
5404 ret->boolval = 1;
5405 top = xmlNewDoc(NULL);
5406 top->name = (char *)
5407 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5408 ret->user = top;
5409 if (top != NULL) {
5410 top->doc = top;
5411 cur = val->nodesetval->nodeTab[0]->children;
5412 while (cur != NULL) {
5413 tmp = xmlDocCopyNode(cur, top, 1);
5414 xmlAddChild((xmlNodePtr) top, tmp);
5415 cur = cur->next;
5416 }
5417 }
5418
5419 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5420 } else
5421 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5422 /* Deallocate the copied tree value */
5423 break;
5424 #endif
5425 case XPATH_NODESET:
5426 /* TODO: Check memory error. */
5427 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5428 /* Do not deallocate the copied tree value */
5429 ret->boolval = 0;
5430 break;
5431 case XPATH_LOCATIONSET:
5432 #ifdef LIBXML_XPTR_ENABLED
5433 {
5434 xmlLocationSetPtr loc = val->user;
5435 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5436 break;
5437 }
5438 #endif
5439 case XPATH_USERS:
5440 ret->user = val->user;
5441 break;
5442 case XPATH_UNDEFINED:
5443 xmlGenericError(xmlGenericErrorContext,
5444 "xmlXPathObjectCopy: unsupported type %d\n",
5445 val->type);
5446 break;
5447 }
5448 return(ret);
5449 }
5450
5451 /**
5452 * xmlXPathFreeObject:
5453 * @obj: the object to free
5454 *
5455 * Free up an xmlXPathObjectPtr object.
5456 */
5457 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5458 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5459 if (obj == NULL) return;
5460 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5461 if (obj->boolval) {
5462 #if 0
5463 if (obj->user != NULL) {
5464 xmlXPathFreeNodeSet(obj->nodesetval);
5465 xmlFreeNodeList((xmlNodePtr) obj->user);
5466 } else
5467 #endif
5468 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5469 if (obj->nodesetval != NULL)
5470 xmlXPathFreeValueTree(obj->nodesetval);
5471 } else {
5472 if (obj->nodesetval != NULL)
5473 xmlXPathFreeNodeSet(obj->nodesetval);
5474 }
5475 #ifdef LIBXML_XPTR_ENABLED
5476 } else if (obj->type == XPATH_LOCATIONSET) {
5477 if (obj->user != NULL)
5478 xmlXPtrFreeLocationSet(obj->user);
5479 #endif
5480 } else if (obj->type == XPATH_STRING) {
5481 if (obj->stringval != NULL)
5482 xmlFree(obj->stringval);
5483 }
5484 #ifdef XP_DEBUG_OBJ_USAGE
5485 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5486 #endif
5487 xmlFree(obj);
5488 }
5489
5490 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5491 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5492 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5493 }
5494
5495 /**
5496 * xmlXPathReleaseObject:
5497 * @obj: the xmlXPathObjectPtr to free or to cache
5498 *
5499 * Depending on the state of the cache this frees the given
5500 * XPath object or stores it in the cache.
5501 */
5502 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5503 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5504 {
5505 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5506 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5507 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5508
5509 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5510
5511 if (obj == NULL)
5512 return;
5513 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5514 xmlXPathFreeObject(obj);
5515 } else {
5516 xmlXPathContextCachePtr cache =
5517 (xmlXPathContextCachePtr) ctxt->cache;
5518
5519 switch (obj->type) {
5520 case XPATH_NODESET:
5521 case XPATH_XSLT_TREE:
5522 if (obj->nodesetval != NULL) {
5523 if (obj->boolval) {
5524 /*
5525 * It looks like the @boolval is used for
5526 * evaluation if this an XSLT Result Tree Fragment.
5527 * TODO: Check if this assumption is correct.
5528 */
5529 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5530 xmlXPathFreeValueTree(obj->nodesetval);
5531 obj->nodesetval = NULL;
5532 } else if ((obj->nodesetval->nodeMax <= 40) &&
5533 (XP_CACHE_WANTS(cache->nodesetObjs,
5534 cache->maxNodeset)))
5535 {
5536 XP_CACHE_ADD(cache->nodesetObjs, obj);
5537 goto obj_cached;
5538 } else {
5539 xmlXPathFreeNodeSet(obj->nodesetval);
5540 obj->nodesetval = NULL;
5541 }
5542 }
5543 break;
5544 case XPATH_STRING:
5545 if (obj->stringval != NULL)
5546 xmlFree(obj->stringval);
5547
5548 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5549 XP_CACHE_ADD(cache->stringObjs, obj);
5550 goto obj_cached;
5551 }
5552 break;
5553 case XPATH_BOOLEAN:
5554 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5555 XP_CACHE_ADD(cache->booleanObjs, obj);
5556 goto obj_cached;
5557 }
5558 break;
5559 case XPATH_NUMBER:
5560 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5561 XP_CACHE_ADD(cache->numberObjs, obj);
5562 goto obj_cached;
5563 }
5564 break;
5565 #ifdef LIBXML_XPTR_ENABLED
5566 case XPATH_LOCATIONSET:
5567 if (obj->user != NULL) {
5568 xmlXPtrFreeLocationSet(obj->user);
5569 }
5570 goto free_obj;
5571 #endif
5572 default:
5573 goto free_obj;
5574 }
5575
5576 /*
5577 * Fallback to adding to the misc-objects slot.
5578 */
5579 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5580 XP_CACHE_ADD(cache->miscObjs, obj);
5581 } else
5582 goto free_obj;
5583
5584 obj_cached:
5585
5586 #ifdef XP_DEBUG_OBJ_USAGE
5587 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5588 #endif
5589
5590 if (obj->nodesetval != NULL) {
5591 xmlNodeSetPtr tmpset = obj->nodesetval;
5592
5593 /*
5594 * TODO: Due to those nasty ns-nodes, we need to traverse
5595 * the list and free the ns-nodes.
5596 * URGENT TODO: Check if it's actually slowing things down.
5597 * Maybe we shouldn't try to preserve the list.
5598 */
5599 if (tmpset->nodeNr > 1) {
5600 int i;
5601 xmlNodePtr node;
5602
5603 for (i = 0; i < tmpset->nodeNr; i++) {
5604 node = tmpset->nodeTab[i];
5605 if ((node != NULL) &&
5606 (node->type == XML_NAMESPACE_DECL))
5607 {
5608 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5609 }
5610 }
5611 } else if (tmpset->nodeNr == 1) {
5612 if ((tmpset->nodeTab[0] != NULL) &&
5613 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5614 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5615 }
5616 tmpset->nodeNr = 0;
5617 memset(obj, 0, sizeof(xmlXPathObject));
5618 obj->nodesetval = tmpset;
5619 } else
5620 memset(obj, 0, sizeof(xmlXPathObject));
5621
5622 return;
5623
5624 free_obj:
5625 /*
5626 * Cache is full; free the object.
5627 */
5628 if (obj->nodesetval != NULL)
5629 xmlXPathFreeNodeSet(obj->nodesetval);
5630 #ifdef XP_DEBUG_OBJ_USAGE
5631 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5632 #endif
5633 xmlFree(obj);
5634 }
5635 return;
5636 }
5637
5638
5639 /************************************************************************
5640 * *
5641 * Type Casting Routines *
5642 * *
5643 ************************************************************************/
5644
5645 /**
5646 * xmlXPathCastBooleanToString:
5647 * @val: a boolean
5648 *
5649 * Converts a boolean to its string value.
5650 *
5651 * Returns a newly allocated string.
5652 */
5653 xmlChar *
xmlXPathCastBooleanToString(int val)5654 xmlXPathCastBooleanToString (int val) {
5655 xmlChar *ret;
5656 if (val)
5657 ret = xmlStrdup((const xmlChar *) "true");
5658 else
5659 ret = xmlStrdup((const xmlChar *) "false");
5660 return(ret);
5661 }
5662
5663 /**
5664 * xmlXPathCastNumberToString:
5665 * @val: a number
5666 *
5667 * Converts a number to its string value.
5668 *
5669 * Returns a newly allocated string.
5670 */
5671 xmlChar *
xmlXPathCastNumberToString(double val)5672 xmlXPathCastNumberToString (double val) {
5673 xmlChar *ret;
5674 switch (xmlXPathIsInf(val)) {
5675 case 1:
5676 ret = xmlStrdup((const xmlChar *) "Infinity");
5677 break;
5678 case -1:
5679 ret = xmlStrdup((const xmlChar *) "-Infinity");
5680 break;
5681 default:
5682 if (xmlXPathIsNaN(val)) {
5683 ret = xmlStrdup((const xmlChar *) "NaN");
5684 } else if (val == 0) {
5685 /* Omit sign for negative zero. */
5686 ret = xmlStrdup((const xmlChar *) "0");
5687 } else {
5688 /* could be improved */
5689 char buf[100];
5690 xmlXPathFormatNumber(val, buf, 99);
5691 buf[99] = 0;
5692 ret = xmlStrdup((const xmlChar *) buf);
5693 }
5694 }
5695 return(ret);
5696 }
5697
5698 /**
5699 * xmlXPathCastNodeToString:
5700 * @node: a node
5701 *
5702 * Converts a node to its string value.
5703 *
5704 * Returns a newly allocated string.
5705 */
5706 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5707 xmlXPathCastNodeToString (xmlNodePtr node) {
5708 xmlChar *ret;
5709 if ((ret = xmlNodeGetContent(node)) == NULL)
5710 ret = xmlStrdup((const xmlChar *) "");
5711 return(ret);
5712 }
5713
5714 /**
5715 * xmlXPathCastNodeSetToString:
5716 * @ns: a node-set
5717 *
5718 * Converts a node-set to its string value.
5719 *
5720 * Returns a newly allocated string.
5721 */
5722 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5723 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5724 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5725 return(xmlStrdup((const xmlChar *) ""));
5726
5727 if (ns->nodeNr > 1)
5728 xmlXPathNodeSetSort(ns);
5729 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5730 }
5731
5732 /**
5733 * xmlXPathCastToString:
5734 * @val: an XPath object
5735 *
5736 * Converts an existing object to its string() equivalent
5737 *
5738 * Returns the allocated string value of the object, NULL in case of error.
5739 * It's up to the caller to free the string memory with xmlFree().
5740 */
5741 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5742 xmlXPathCastToString(xmlXPathObjectPtr val) {
5743 xmlChar *ret = NULL;
5744
5745 if (val == NULL)
5746 return(xmlStrdup((const xmlChar *) ""));
5747 switch (val->type) {
5748 case XPATH_UNDEFINED:
5749 #ifdef DEBUG_EXPR
5750 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5751 #endif
5752 ret = xmlStrdup((const xmlChar *) "");
5753 break;
5754 case XPATH_NODESET:
5755 case XPATH_XSLT_TREE:
5756 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5757 break;
5758 case XPATH_STRING:
5759 return(xmlStrdup(val->stringval));
5760 case XPATH_BOOLEAN:
5761 ret = xmlXPathCastBooleanToString(val->boolval);
5762 break;
5763 case XPATH_NUMBER: {
5764 ret = xmlXPathCastNumberToString(val->floatval);
5765 break;
5766 }
5767 case XPATH_USERS:
5768 case XPATH_POINT:
5769 case XPATH_RANGE:
5770 case XPATH_LOCATIONSET:
5771 TODO
5772 ret = xmlStrdup((const xmlChar *) "");
5773 break;
5774 }
5775 return(ret);
5776 }
5777
5778 /**
5779 * xmlXPathConvertString:
5780 * @val: an XPath object
5781 *
5782 * Converts an existing object to its string() equivalent
5783 *
5784 * Returns the new object, the old one is freed (or the operation
5785 * is done directly on @val)
5786 */
5787 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5788 xmlXPathConvertString(xmlXPathObjectPtr val) {
5789 xmlChar *res = NULL;
5790
5791 if (val == NULL)
5792 return(xmlXPathNewCString(""));
5793
5794 switch (val->type) {
5795 case XPATH_UNDEFINED:
5796 #ifdef DEBUG_EXPR
5797 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5798 #endif
5799 break;
5800 case XPATH_NODESET:
5801 case XPATH_XSLT_TREE:
5802 res = xmlXPathCastNodeSetToString(val->nodesetval);
5803 break;
5804 case XPATH_STRING:
5805 return(val);
5806 case XPATH_BOOLEAN:
5807 res = xmlXPathCastBooleanToString(val->boolval);
5808 break;
5809 case XPATH_NUMBER:
5810 res = xmlXPathCastNumberToString(val->floatval);
5811 break;
5812 case XPATH_USERS:
5813 case XPATH_POINT:
5814 case XPATH_RANGE:
5815 case XPATH_LOCATIONSET:
5816 TODO;
5817 break;
5818 }
5819 xmlXPathFreeObject(val);
5820 if (res == NULL)
5821 return(xmlXPathNewCString(""));
5822 return(xmlXPathWrapString(res));
5823 }
5824
5825 /**
5826 * xmlXPathCastBooleanToNumber:
5827 * @val: a boolean
5828 *
5829 * Converts a boolean to its number value
5830 *
5831 * Returns the number value
5832 */
5833 double
xmlXPathCastBooleanToNumber(int val)5834 xmlXPathCastBooleanToNumber(int val) {
5835 if (val)
5836 return(1.0);
5837 return(0.0);
5838 }
5839
5840 /**
5841 * xmlXPathCastStringToNumber:
5842 * @val: a string
5843 *
5844 * Converts a string to its number value
5845 *
5846 * Returns the number value
5847 */
5848 double
xmlXPathCastStringToNumber(const xmlChar * val)5849 xmlXPathCastStringToNumber(const xmlChar * val) {
5850 return(xmlXPathStringEvalNumber(val));
5851 }
5852
5853 /**
5854 * xmlXPathCastNodeToNumber:
5855 * @node: a node
5856 *
5857 * Converts a node to its number value
5858 *
5859 * Returns the number value
5860 */
5861 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5862 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5863 xmlChar *strval;
5864 double ret;
5865
5866 if (node == NULL)
5867 return(NAN);
5868 strval = xmlXPathCastNodeToString(node);
5869 if (strval == NULL)
5870 return(NAN);
5871 ret = xmlXPathCastStringToNumber(strval);
5872 xmlFree(strval);
5873
5874 return(ret);
5875 }
5876
5877 /**
5878 * xmlXPathCastNodeSetToNumber:
5879 * @ns: a node-set
5880 *
5881 * Converts a node-set to its number value
5882 *
5883 * Returns the number value
5884 */
5885 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5886 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5887 xmlChar *str;
5888 double ret;
5889
5890 if (ns == NULL)
5891 return(NAN);
5892 str = xmlXPathCastNodeSetToString(ns);
5893 ret = xmlXPathCastStringToNumber(str);
5894 xmlFree(str);
5895 return(ret);
5896 }
5897
5898 /**
5899 * xmlXPathCastToNumber:
5900 * @val: an XPath object
5901 *
5902 * Converts an XPath object to its number value
5903 *
5904 * Returns the number value
5905 */
5906 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5907 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5908 double ret = 0.0;
5909
5910 if (val == NULL)
5911 return(NAN);
5912 switch (val->type) {
5913 case XPATH_UNDEFINED:
5914 #ifdef DEBUG_EXPR
5915 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5916 #endif
5917 ret = NAN;
5918 break;
5919 case XPATH_NODESET:
5920 case XPATH_XSLT_TREE:
5921 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5922 break;
5923 case XPATH_STRING:
5924 ret = xmlXPathCastStringToNumber(val->stringval);
5925 break;
5926 case XPATH_NUMBER:
5927 ret = val->floatval;
5928 break;
5929 case XPATH_BOOLEAN:
5930 ret = xmlXPathCastBooleanToNumber(val->boolval);
5931 break;
5932 case XPATH_USERS:
5933 case XPATH_POINT:
5934 case XPATH_RANGE:
5935 case XPATH_LOCATIONSET:
5936 TODO;
5937 ret = NAN;
5938 break;
5939 }
5940 return(ret);
5941 }
5942
5943 /**
5944 * xmlXPathConvertNumber:
5945 * @val: an XPath object
5946 *
5947 * Converts an existing object to its number() equivalent
5948 *
5949 * Returns the new object, the old one is freed (or the operation
5950 * is done directly on @val)
5951 */
5952 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5953 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5954 xmlXPathObjectPtr ret;
5955
5956 if (val == NULL)
5957 return(xmlXPathNewFloat(0.0));
5958 if (val->type == XPATH_NUMBER)
5959 return(val);
5960 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5961 xmlXPathFreeObject(val);
5962 return(ret);
5963 }
5964
5965 /**
5966 * xmlXPathCastNumberToBoolean:
5967 * @val: a number
5968 *
5969 * Converts a number to its boolean value
5970 *
5971 * Returns the boolean value
5972 */
5973 int
xmlXPathCastNumberToBoolean(double val)5974 xmlXPathCastNumberToBoolean (double val) {
5975 if (xmlXPathIsNaN(val) || (val == 0.0))
5976 return(0);
5977 return(1);
5978 }
5979
5980 /**
5981 * xmlXPathCastStringToBoolean:
5982 * @val: a string
5983 *
5984 * Converts a string to its boolean value
5985 *
5986 * Returns the boolean value
5987 */
5988 int
xmlXPathCastStringToBoolean(const xmlChar * val)5989 xmlXPathCastStringToBoolean (const xmlChar *val) {
5990 if ((val == NULL) || (xmlStrlen(val) == 0))
5991 return(0);
5992 return(1);
5993 }
5994
5995 /**
5996 * xmlXPathCastNodeSetToBoolean:
5997 * @ns: a node-set
5998 *
5999 * Converts a node-set to its boolean value
6000 *
6001 * Returns the boolean value
6002 */
6003 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6004 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005 if ((ns == NULL) || (ns->nodeNr == 0))
6006 return(0);
6007 return(1);
6008 }
6009
6010 /**
6011 * xmlXPathCastToBoolean:
6012 * @val: an XPath object
6013 *
6014 * Converts an XPath object to its boolean value
6015 *
6016 * Returns the boolean value
6017 */
6018 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6019 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020 int ret = 0;
6021
6022 if (val == NULL)
6023 return(0);
6024 switch (val->type) {
6025 case XPATH_UNDEFINED:
6026 #ifdef DEBUG_EXPR
6027 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6028 #endif
6029 ret = 0;
6030 break;
6031 case XPATH_NODESET:
6032 case XPATH_XSLT_TREE:
6033 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034 break;
6035 case XPATH_STRING:
6036 ret = xmlXPathCastStringToBoolean(val->stringval);
6037 break;
6038 case XPATH_NUMBER:
6039 ret = xmlXPathCastNumberToBoolean(val->floatval);
6040 break;
6041 case XPATH_BOOLEAN:
6042 ret = val->boolval;
6043 break;
6044 case XPATH_USERS:
6045 case XPATH_POINT:
6046 case XPATH_RANGE:
6047 case XPATH_LOCATIONSET:
6048 TODO;
6049 ret = 0;
6050 break;
6051 }
6052 return(ret);
6053 }
6054
6055
6056 /**
6057 * xmlXPathConvertBoolean:
6058 * @val: an XPath object
6059 *
6060 * Converts an existing object to its boolean() equivalent
6061 *
6062 * Returns the new object, the old one is freed (or the operation
6063 * is done directly on @val)
6064 */
6065 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6066 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6067 xmlXPathObjectPtr ret;
6068
6069 if (val == NULL)
6070 return(xmlXPathNewBoolean(0));
6071 if (val->type == XPATH_BOOLEAN)
6072 return(val);
6073 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6074 xmlXPathFreeObject(val);
6075 return(ret);
6076 }
6077
6078 /************************************************************************
6079 * *
6080 * Routines to handle XPath contexts *
6081 * *
6082 ************************************************************************/
6083
6084 /**
6085 * xmlXPathNewContext:
6086 * @doc: the XML document
6087 *
6088 * Create a new xmlXPathContext
6089 *
6090 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6091 */
6092 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6093 xmlXPathNewContext(xmlDocPtr doc) {
6094 xmlXPathContextPtr ret;
6095
6096 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6097 if (ret == NULL) {
6098 xmlXPathErrMemory(NULL, "creating context\n");
6099 return(NULL);
6100 }
6101 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6102 ret->doc = doc;
6103 ret->node = NULL;
6104
6105 ret->varHash = NULL;
6106
6107 ret->nb_types = 0;
6108 ret->max_types = 0;
6109 ret->types = NULL;
6110
6111 ret->funcHash = xmlHashCreate(0);
6112
6113 ret->nb_axis = 0;
6114 ret->max_axis = 0;
6115 ret->axis = NULL;
6116
6117 ret->nsHash = NULL;
6118 ret->user = NULL;
6119
6120 ret->contextSize = -1;
6121 ret->proximityPosition = -1;
6122
6123 ret->maxDepth = INT_MAX;
6124 ret->maxParserDepth = INT_MAX;
6125
6126 #ifdef XP_DEFAULT_CACHE_ON
6127 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6128 xmlXPathFreeContext(ret);
6129 return(NULL);
6130 }
6131 #endif
6132
6133 xmlXPathRegisterAllFunctions(ret);
6134
6135 return(ret);
6136 }
6137
6138 /**
6139 * xmlXPathFreeContext:
6140 * @ctxt: the context to free
6141 *
6142 * Free up an xmlXPathContext
6143 */
6144 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6145 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6146 if (ctxt == NULL) return;
6147
6148 if (ctxt->cache != NULL)
6149 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6150 xmlXPathRegisteredNsCleanup(ctxt);
6151 xmlXPathRegisteredFuncsCleanup(ctxt);
6152 xmlXPathRegisteredVariablesCleanup(ctxt);
6153 xmlResetError(&ctxt->lastError);
6154 xmlFree(ctxt);
6155 }
6156
6157 /************************************************************************
6158 * *
6159 * Routines to handle XPath parser contexts *
6160 * *
6161 ************************************************************************/
6162
6163 #define CHECK_CTXT(ctxt) \
6164 if (ctxt == NULL) { \
6165 __xmlRaiseError(NULL, NULL, NULL, \
6166 NULL, NULL, XML_FROM_XPATH, \
6167 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6168 __FILE__, __LINE__, \
6169 NULL, NULL, NULL, 0, 0, \
6170 "NULL context pointer\n"); \
6171 return(NULL); \
6172 } \
6173
6174 #define CHECK_CTXT_NEG(ctxt) \
6175 if (ctxt == NULL) { \
6176 __xmlRaiseError(NULL, NULL, NULL, \
6177 NULL, NULL, XML_FROM_XPATH, \
6178 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6179 __FILE__, __LINE__, \
6180 NULL, NULL, NULL, 0, 0, \
6181 "NULL context pointer\n"); \
6182 return(-1); \
6183 } \
6184
6185
6186 #define CHECK_CONTEXT(ctxt) \
6187 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6188 (ctxt->doc->children == NULL)) { \
6189 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6190 return(NULL); \
6191 }
6192
6193
6194 /**
6195 * xmlXPathNewParserContext:
6196 * @str: the XPath expression
6197 * @ctxt: the XPath context
6198 *
6199 * Create a new xmlXPathParserContext
6200 *
6201 * Returns the xmlXPathParserContext just allocated.
6202 */
6203 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6204 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6205 xmlXPathParserContextPtr ret;
6206
6207 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6208 if (ret == NULL) {
6209 xmlXPathErrMemory(ctxt, "creating parser context\n");
6210 return(NULL);
6211 }
6212 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6213 ret->cur = ret->base = str;
6214 ret->context = ctxt;
6215
6216 ret->comp = xmlXPathNewCompExpr();
6217 if (ret->comp == NULL) {
6218 xmlFree(ret->valueTab);
6219 xmlFree(ret);
6220 return(NULL);
6221 }
6222 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6223 ret->comp->dict = ctxt->dict;
6224 xmlDictReference(ret->comp->dict);
6225 }
6226
6227 return(ret);
6228 }
6229
6230 /**
6231 * xmlXPathCompParserContext:
6232 * @comp: the XPath compiled expression
6233 * @ctxt: the XPath context
6234 *
6235 * Create a new xmlXPathParserContext when processing a compiled expression
6236 *
6237 * Returns the xmlXPathParserContext just allocated.
6238 */
6239 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6240 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6241 xmlXPathParserContextPtr ret;
6242
6243 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6244 if (ret == NULL) {
6245 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6246 return(NULL);
6247 }
6248 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6249
6250 /* Allocate the value stack */
6251 ret->valueTab = (xmlXPathObjectPtr *)
6252 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6253 if (ret->valueTab == NULL) {
6254 xmlFree(ret);
6255 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6256 return(NULL);
6257 }
6258 ret->valueNr = 0;
6259 ret->valueMax = 10;
6260 ret->value = NULL;
6261 ret->valueFrame = 0;
6262
6263 ret->context = ctxt;
6264 ret->comp = comp;
6265
6266 return(ret);
6267 }
6268
6269 /**
6270 * xmlXPathFreeParserContext:
6271 * @ctxt: the context to free
6272 *
6273 * Free up an xmlXPathParserContext
6274 */
6275 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6276 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6277 int i;
6278
6279 if (ctxt->valueTab != NULL) {
6280 for (i = 0; i < ctxt->valueNr; i++) {
6281 if (ctxt->context)
6282 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6283 else
6284 xmlXPathFreeObject(ctxt->valueTab[i]);
6285 }
6286 xmlFree(ctxt->valueTab);
6287 }
6288 if (ctxt->comp != NULL) {
6289 #ifdef XPATH_STREAMING
6290 if (ctxt->comp->stream != NULL) {
6291 xmlFreePatternList(ctxt->comp->stream);
6292 ctxt->comp->stream = NULL;
6293 }
6294 #endif
6295 xmlXPathFreeCompExpr(ctxt->comp);
6296 }
6297 xmlFree(ctxt);
6298 }
6299
6300 /************************************************************************
6301 * *
6302 * The implicit core function library *
6303 * *
6304 ************************************************************************/
6305
6306 /**
6307 * xmlXPathNodeValHash:
6308 * @node: a node pointer
6309 *
6310 * Function computing the beginning of the string value of the node,
6311 * used to speed up comparisons
6312 *
6313 * Returns an int usable as a hash
6314 */
6315 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6316 xmlXPathNodeValHash(xmlNodePtr node) {
6317 int len = 2;
6318 const xmlChar * string = NULL;
6319 xmlNodePtr tmp = NULL;
6320 unsigned int ret = 0;
6321
6322 if (node == NULL)
6323 return(0);
6324
6325 if (node->type == XML_DOCUMENT_NODE) {
6326 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6327 if (tmp == NULL)
6328 node = node->children;
6329 else
6330 node = tmp;
6331
6332 if (node == NULL)
6333 return(0);
6334 }
6335
6336 switch (node->type) {
6337 case XML_COMMENT_NODE:
6338 case XML_PI_NODE:
6339 case XML_CDATA_SECTION_NODE:
6340 case XML_TEXT_NODE:
6341 string = node->content;
6342 if (string == NULL)
6343 return(0);
6344 if (string[0] == 0)
6345 return(0);
6346 return(((unsigned int) string[0]) +
6347 (((unsigned int) string[1]) << 8));
6348 case XML_NAMESPACE_DECL:
6349 string = ((xmlNsPtr)node)->href;
6350 if (string == NULL)
6351 return(0);
6352 if (string[0] == 0)
6353 return(0);
6354 return(((unsigned int) string[0]) +
6355 (((unsigned int) string[1]) << 8));
6356 case XML_ATTRIBUTE_NODE:
6357 tmp = ((xmlAttrPtr) node)->children;
6358 break;
6359 case XML_ELEMENT_NODE:
6360 tmp = node->children;
6361 break;
6362 default:
6363 return(0);
6364 }
6365 while (tmp != NULL) {
6366 switch (tmp->type) {
6367 case XML_CDATA_SECTION_NODE:
6368 case XML_TEXT_NODE:
6369 string = tmp->content;
6370 break;
6371 default:
6372 string = NULL;
6373 break;
6374 }
6375 if ((string != NULL) && (string[0] != 0)) {
6376 if (len == 1) {
6377 return(ret + (((unsigned int) string[0]) << 8));
6378 }
6379 if (string[1] == 0) {
6380 len = 1;
6381 ret = (unsigned int) string[0];
6382 } else {
6383 return(((unsigned int) string[0]) +
6384 (((unsigned int) string[1]) << 8));
6385 }
6386 }
6387 /*
6388 * Skip to next node
6389 */
6390 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6391 if (tmp->children->type != XML_ENTITY_DECL) {
6392 tmp = tmp->children;
6393 continue;
6394 }
6395 }
6396 if (tmp == node)
6397 break;
6398
6399 if (tmp->next != NULL) {
6400 tmp = tmp->next;
6401 continue;
6402 }
6403
6404 do {
6405 tmp = tmp->parent;
6406 if (tmp == NULL)
6407 break;
6408 if (tmp == node) {
6409 tmp = NULL;
6410 break;
6411 }
6412 if (tmp->next != NULL) {
6413 tmp = tmp->next;
6414 break;
6415 }
6416 } while (tmp != NULL);
6417 }
6418 return(ret);
6419 }
6420
6421 /**
6422 * xmlXPathStringHash:
6423 * @string: a string
6424 *
6425 * Function computing the beginning of the string value of the node,
6426 * used to speed up comparisons
6427 *
6428 * Returns an int usable as a hash
6429 */
6430 static unsigned int
xmlXPathStringHash(const xmlChar * string)6431 xmlXPathStringHash(const xmlChar * string) {
6432 if (string == NULL)
6433 return((unsigned int) 0);
6434 if (string[0] == 0)
6435 return(0);
6436 return(((unsigned int) string[0]) +
6437 (((unsigned int) string[1]) << 8));
6438 }
6439
6440 /**
6441 * xmlXPathCompareNodeSetFloat:
6442 * @ctxt: the XPath Parser context
6443 * @inf: less than (1) or greater than (0)
6444 * @strict: is the comparison strict
6445 * @arg: the node set
6446 * @f: the value
6447 *
6448 * Implement the compare operation between a nodeset and a number
6449 * @ns < @val (1, 1, ...
6450 * @ns <= @val (1, 0, ...
6451 * @ns > @val (0, 1, ...
6452 * @ns >= @val (0, 0, ...
6453 *
6454 * If one object to be compared is a node-set and the other is a number,
6455 * then the comparison will be true if and only if there is a node in the
6456 * node-set such that the result of performing the comparison on the number
6457 * to be compared and on the result of converting the string-value of that
6458 * node to a number using the number function is true.
6459 *
6460 * Returns 0 or 1 depending on the results of the test.
6461 */
6462 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6463 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6464 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6465 int i, ret = 0;
6466 xmlNodeSetPtr ns;
6467 xmlChar *str2;
6468
6469 if ((f == NULL) || (arg == NULL) ||
6470 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6471 xmlXPathReleaseObject(ctxt->context, arg);
6472 xmlXPathReleaseObject(ctxt->context, f);
6473 return(0);
6474 }
6475 ns = arg->nodesetval;
6476 if (ns != NULL) {
6477 for (i = 0;i < ns->nodeNr;i++) {
6478 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6479 if (str2 != NULL) {
6480 valuePush(ctxt,
6481 xmlXPathCacheNewString(ctxt->context, str2));
6482 xmlFree(str2);
6483 xmlXPathNumberFunction(ctxt, 1);
6484 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6485 ret = xmlXPathCompareValues(ctxt, inf, strict);
6486 if (ret)
6487 break;
6488 }
6489 }
6490 }
6491 xmlXPathReleaseObject(ctxt->context, arg);
6492 xmlXPathReleaseObject(ctxt->context, f);
6493 return(ret);
6494 }
6495
6496 /**
6497 * xmlXPathCompareNodeSetString:
6498 * @ctxt: the XPath Parser context
6499 * @inf: less than (1) or greater than (0)
6500 * @strict: is the comparison strict
6501 * @arg: the node set
6502 * @s: the value
6503 *
6504 * Implement the compare operation between a nodeset and a string
6505 * @ns < @val (1, 1, ...
6506 * @ns <= @val (1, 0, ...
6507 * @ns > @val (0, 1, ...
6508 * @ns >= @val (0, 0, ...
6509 *
6510 * If one object to be compared is a node-set and the other is a string,
6511 * then the comparison will be true if and only if there is a node in
6512 * the node-set such that the result of performing the comparison on the
6513 * string-value of the node and the other string is true.
6514 *
6515 * Returns 0 or 1 depending on the results of the test.
6516 */
6517 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6518 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6519 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6520 int i, ret = 0;
6521 xmlNodeSetPtr ns;
6522 xmlChar *str2;
6523
6524 if ((s == NULL) || (arg == NULL) ||
6525 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6526 xmlXPathReleaseObject(ctxt->context, arg);
6527 xmlXPathReleaseObject(ctxt->context, s);
6528 return(0);
6529 }
6530 ns = arg->nodesetval;
6531 if (ns != NULL) {
6532 for (i = 0;i < ns->nodeNr;i++) {
6533 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6534 if (str2 != NULL) {
6535 valuePush(ctxt,
6536 xmlXPathCacheNewString(ctxt->context, str2));
6537 xmlFree(str2);
6538 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6539 ret = xmlXPathCompareValues(ctxt, inf, strict);
6540 if (ret)
6541 break;
6542 }
6543 }
6544 }
6545 xmlXPathReleaseObject(ctxt->context, arg);
6546 xmlXPathReleaseObject(ctxt->context, s);
6547 return(ret);
6548 }
6549
6550 /**
6551 * xmlXPathCompareNodeSets:
6552 * @inf: less than (1) or greater than (0)
6553 * @strict: is the comparison strict
6554 * @arg1: the first node set object
6555 * @arg2: the second node set object
6556 *
6557 * Implement the compare operation on nodesets:
6558 *
6559 * If both objects to be compared are node-sets, then the comparison
6560 * will be true if and only if there is a node in the first node-set
6561 * and a node in the second node-set such that the result of performing
6562 * the comparison on the string-values of the two nodes is true.
6563 * ....
6564 * When neither object to be compared is a node-set and the operator
6565 * is <=, <, >= or >, then the objects are compared by converting both
6566 * objects to numbers and comparing the numbers according to IEEE 754.
6567 * ....
6568 * The number function converts its argument to a number as follows:
6569 * - a string that consists of optional whitespace followed by an
6570 * optional minus sign followed by a Number followed by whitespace
6571 * is converted to the IEEE 754 number that is nearest (according
6572 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6573 * represented by the string; any other string is converted to NaN
6574 *
6575 * Conclusion all nodes need to be converted first to their string value
6576 * and then the comparison must be done when possible
6577 */
6578 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6579 xmlXPathCompareNodeSets(int inf, int strict,
6580 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6581 int i, j, init = 0;
6582 double val1;
6583 double *values2;
6584 int ret = 0;
6585 xmlNodeSetPtr ns1;
6586 xmlNodeSetPtr ns2;
6587
6588 if ((arg1 == NULL) ||
6589 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6590 xmlXPathFreeObject(arg2);
6591 return(0);
6592 }
6593 if ((arg2 == NULL) ||
6594 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6595 xmlXPathFreeObject(arg1);
6596 xmlXPathFreeObject(arg2);
6597 return(0);
6598 }
6599
6600 ns1 = arg1->nodesetval;
6601 ns2 = arg2->nodesetval;
6602
6603 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6604 xmlXPathFreeObject(arg1);
6605 xmlXPathFreeObject(arg2);
6606 return(0);
6607 }
6608 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6609 xmlXPathFreeObject(arg1);
6610 xmlXPathFreeObject(arg2);
6611 return(0);
6612 }
6613
6614 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6615 if (values2 == NULL) {
6616 /* TODO: Propagate memory error. */
6617 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6618 xmlXPathFreeObject(arg1);
6619 xmlXPathFreeObject(arg2);
6620 return(0);
6621 }
6622 for (i = 0;i < ns1->nodeNr;i++) {
6623 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6624 if (xmlXPathIsNaN(val1))
6625 continue;
6626 for (j = 0;j < ns2->nodeNr;j++) {
6627 if (init == 0) {
6628 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6629 }
6630 if (xmlXPathIsNaN(values2[j]))
6631 continue;
6632 if (inf && strict)
6633 ret = (val1 < values2[j]);
6634 else if (inf && !strict)
6635 ret = (val1 <= values2[j]);
6636 else if (!inf && strict)
6637 ret = (val1 > values2[j]);
6638 else if (!inf && !strict)
6639 ret = (val1 >= values2[j]);
6640 if (ret)
6641 break;
6642 }
6643 if (ret)
6644 break;
6645 init = 1;
6646 }
6647 xmlFree(values2);
6648 xmlXPathFreeObject(arg1);
6649 xmlXPathFreeObject(arg2);
6650 return(ret);
6651 }
6652
6653 /**
6654 * xmlXPathCompareNodeSetValue:
6655 * @ctxt: the XPath Parser context
6656 * @inf: less than (1) or greater than (0)
6657 * @strict: is the comparison strict
6658 * @arg: the node set
6659 * @val: the value
6660 *
6661 * Implement the compare operation between a nodeset and a value
6662 * @ns < @val (1, 1, ...
6663 * @ns <= @val (1, 0, ...
6664 * @ns > @val (0, 1, ...
6665 * @ns >= @val (0, 0, ...
6666 *
6667 * If one object to be compared is a node-set and the other is a boolean,
6668 * then the comparison will be true if and only if the result of performing
6669 * the comparison on the boolean and on the result of converting
6670 * the node-set to a boolean using the boolean function is true.
6671 *
6672 * Returns 0 or 1 depending on the results of the test.
6673 */
6674 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6675 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6676 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6677 if ((val == NULL) || (arg == NULL) ||
6678 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6679 return(0);
6680
6681 switch(val->type) {
6682 case XPATH_NUMBER:
6683 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6684 case XPATH_NODESET:
6685 case XPATH_XSLT_TREE:
6686 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6687 case XPATH_STRING:
6688 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6689 case XPATH_BOOLEAN:
6690 valuePush(ctxt, arg);
6691 xmlXPathBooleanFunction(ctxt, 1);
6692 valuePush(ctxt, val);
6693 return(xmlXPathCompareValues(ctxt, inf, strict));
6694 default:
6695 xmlGenericError(xmlGenericErrorContext,
6696 "xmlXPathCompareNodeSetValue: Can't compare node set "
6697 "and object of type %d\n",
6698 val->type);
6699 xmlXPathReleaseObject(ctxt->context, arg);
6700 xmlXPathReleaseObject(ctxt->context, val);
6701 XP_ERROR0(XPATH_INVALID_TYPE);
6702 }
6703 return(0);
6704 }
6705
6706 /**
6707 * xmlXPathEqualNodeSetString:
6708 * @arg: the nodeset object argument
6709 * @str: the string to compare to.
6710 * @neq: flag to show whether for '=' (0) or '!=' (1)
6711 *
6712 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6713 * If one object to be compared is a node-set and the other is a string,
6714 * then the comparison will be true if and only if there is a node in
6715 * the node-set such that the result of performing the comparison on the
6716 * string-value of the node and the other string is true.
6717 *
6718 * Returns 0 or 1 depending on the results of the test.
6719 */
6720 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6721 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6722 {
6723 int i;
6724 xmlNodeSetPtr ns;
6725 xmlChar *str2;
6726 unsigned int hash;
6727
6728 if ((str == NULL) || (arg == NULL) ||
6729 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6730 return (0);
6731 ns = arg->nodesetval;
6732 /*
6733 * A NULL nodeset compared with a string is always false
6734 * (since there is no node equal, and no node not equal)
6735 */
6736 if ((ns == NULL) || (ns->nodeNr <= 0) )
6737 return (0);
6738 hash = xmlXPathStringHash(str);
6739 for (i = 0; i < ns->nodeNr; i++) {
6740 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6741 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6742 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6743 xmlFree(str2);
6744 if (neq)
6745 continue;
6746 return (1);
6747 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6748 if (neq)
6749 continue;
6750 return (1);
6751 } else if (neq) {
6752 if (str2 != NULL)
6753 xmlFree(str2);
6754 return (1);
6755 }
6756 if (str2 != NULL)
6757 xmlFree(str2);
6758 } else if (neq)
6759 return (1);
6760 }
6761 return (0);
6762 }
6763
6764 /**
6765 * xmlXPathEqualNodeSetFloat:
6766 * @arg: the nodeset object argument
6767 * @f: the float to compare to
6768 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6769 *
6770 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6771 * If one object to be compared is a node-set and the other is a number,
6772 * then the comparison will be true if and only if there is a node in
6773 * the node-set such that the result of performing the comparison on the
6774 * number to be compared and on the result of converting the string-value
6775 * of that node to a number using the number function is true.
6776 *
6777 * Returns 0 or 1 depending on the results of the test.
6778 */
6779 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6780 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6781 xmlXPathObjectPtr arg, double f, int neq) {
6782 int i, ret=0;
6783 xmlNodeSetPtr ns;
6784 xmlChar *str2;
6785 xmlXPathObjectPtr val;
6786 double v;
6787
6788 if ((arg == NULL) ||
6789 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6790 return(0);
6791
6792 ns = arg->nodesetval;
6793 if (ns != NULL) {
6794 for (i=0;i<ns->nodeNr;i++) {
6795 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6796 if (str2 != NULL) {
6797 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6798 xmlFree(str2);
6799 xmlXPathNumberFunction(ctxt, 1);
6800 val = valuePop(ctxt);
6801 v = val->floatval;
6802 xmlXPathReleaseObject(ctxt->context, val);
6803 if (!xmlXPathIsNaN(v)) {
6804 if ((!neq) && (v==f)) {
6805 ret = 1;
6806 break;
6807 } else if ((neq) && (v!=f)) {
6808 ret = 1;
6809 break;
6810 }
6811 } else { /* NaN is unequal to any value */
6812 if (neq)
6813 ret = 1;
6814 }
6815 }
6816 }
6817 }
6818
6819 return(ret);
6820 }
6821
6822
6823 /**
6824 * xmlXPathEqualNodeSets:
6825 * @arg1: first nodeset object argument
6826 * @arg2: second nodeset object argument
6827 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6828 *
6829 * Implement the equal / not equal operation on XPath nodesets:
6830 * @arg1 == @arg2 or @arg1 != @arg2
6831 * If both objects to be compared are node-sets, then the comparison
6832 * will be true if and only if there is a node in the first node-set and
6833 * a node in the second node-set such that the result of performing the
6834 * comparison on the string-values of the two nodes is true.
6835 *
6836 * (needless to say, this is a costly operation)
6837 *
6838 * Returns 0 or 1 depending on the results of the test.
6839 */
6840 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6841 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6842 int i, j;
6843 unsigned int *hashs1;
6844 unsigned int *hashs2;
6845 xmlChar **values1;
6846 xmlChar **values2;
6847 int ret = 0;
6848 xmlNodeSetPtr ns1;
6849 xmlNodeSetPtr ns2;
6850
6851 if ((arg1 == NULL) ||
6852 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6853 return(0);
6854 if ((arg2 == NULL) ||
6855 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6856 return(0);
6857
6858 ns1 = arg1->nodesetval;
6859 ns2 = arg2->nodesetval;
6860
6861 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6862 return(0);
6863 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6864 return(0);
6865
6866 /*
6867 * for equal, check if there is a node pertaining to both sets
6868 */
6869 if (neq == 0)
6870 for (i = 0;i < ns1->nodeNr;i++)
6871 for (j = 0;j < ns2->nodeNr;j++)
6872 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6873 return(1);
6874
6875 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6876 if (values1 == NULL) {
6877 /* TODO: Propagate memory error. */
6878 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6879 return(0);
6880 }
6881 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6882 if (hashs1 == NULL) {
6883 /* TODO: Propagate memory error. */
6884 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6885 xmlFree(values1);
6886 return(0);
6887 }
6888 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6889 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6890 if (values2 == NULL) {
6891 /* TODO: Propagate memory error. */
6892 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6893 xmlFree(hashs1);
6894 xmlFree(values1);
6895 return(0);
6896 }
6897 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6898 if (hashs2 == NULL) {
6899 /* TODO: Propagate memory error. */
6900 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6901 xmlFree(hashs1);
6902 xmlFree(values1);
6903 xmlFree(values2);
6904 return(0);
6905 }
6906 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6907 for (i = 0;i < ns1->nodeNr;i++) {
6908 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6909 for (j = 0;j < ns2->nodeNr;j++) {
6910 if (i == 0)
6911 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6912 if (hashs1[i] != hashs2[j]) {
6913 if (neq) {
6914 ret = 1;
6915 break;
6916 }
6917 }
6918 else {
6919 if (values1[i] == NULL)
6920 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6921 if (values2[j] == NULL)
6922 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6923 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6924 if (ret)
6925 break;
6926 }
6927 }
6928 if (ret)
6929 break;
6930 }
6931 for (i = 0;i < ns1->nodeNr;i++)
6932 if (values1[i] != NULL)
6933 xmlFree(values1[i]);
6934 for (j = 0;j < ns2->nodeNr;j++)
6935 if (values2[j] != NULL)
6936 xmlFree(values2[j]);
6937 xmlFree(values1);
6938 xmlFree(values2);
6939 xmlFree(hashs1);
6940 xmlFree(hashs2);
6941 return(ret);
6942 }
6943
6944 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6945 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6946 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6947 int ret = 0;
6948 /*
6949 *At this point we are assured neither arg1 nor arg2
6950 *is a nodeset, so we can just pick the appropriate routine.
6951 */
6952 switch (arg1->type) {
6953 case XPATH_UNDEFINED:
6954 #ifdef DEBUG_EXPR
6955 xmlGenericError(xmlGenericErrorContext,
6956 "Equal: undefined\n");
6957 #endif
6958 break;
6959 case XPATH_BOOLEAN:
6960 switch (arg2->type) {
6961 case XPATH_UNDEFINED:
6962 #ifdef DEBUG_EXPR
6963 xmlGenericError(xmlGenericErrorContext,
6964 "Equal: undefined\n");
6965 #endif
6966 break;
6967 case XPATH_BOOLEAN:
6968 #ifdef DEBUG_EXPR
6969 xmlGenericError(xmlGenericErrorContext,
6970 "Equal: %d boolean %d \n",
6971 arg1->boolval, arg2->boolval);
6972 #endif
6973 ret = (arg1->boolval == arg2->boolval);
6974 break;
6975 case XPATH_NUMBER:
6976 ret = (arg1->boolval ==
6977 xmlXPathCastNumberToBoolean(arg2->floatval));
6978 break;
6979 case XPATH_STRING:
6980 if ((arg2->stringval == NULL) ||
6981 (arg2->stringval[0] == 0)) ret = 0;
6982 else
6983 ret = 1;
6984 ret = (arg1->boolval == ret);
6985 break;
6986 case XPATH_USERS:
6987 case XPATH_POINT:
6988 case XPATH_RANGE:
6989 case XPATH_LOCATIONSET:
6990 TODO
6991 break;
6992 case XPATH_NODESET:
6993 case XPATH_XSLT_TREE:
6994 break;
6995 }
6996 break;
6997 case XPATH_NUMBER:
6998 switch (arg2->type) {
6999 case XPATH_UNDEFINED:
7000 #ifdef DEBUG_EXPR
7001 xmlGenericError(xmlGenericErrorContext,
7002 "Equal: undefined\n");
7003 #endif
7004 break;
7005 case XPATH_BOOLEAN:
7006 ret = (arg2->boolval==
7007 xmlXPathCastNumberToBoolean(arg1->floatval));
7008 break;
7009 case XPATH_STRING:
7010 valuePush(ctxt, arg2);
7011 xmlXPathNumberFunction(ctxt, 1);
7012 arg2 = valuePop(ctxt);
7013 /* Falls through. */
7014 case XPATH_NUMBER:
7015 /* Hand check NaN and Infinity equalities */
7016 if (xmlXPathIsNaN(arg1->floatval) ||
7017 xmlXPathIsNaN(arg2->floatval)) {
7018 ret = 0;
7019 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7020 if (xmlXPathIsInf(arg2->floatval) == 1)
7021 ret = 1;
7022 else
7023 ret = 0;
7024 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7025 if (xmlXPathIsInf(arg2->floatval) == -1)
7026 ret = 1;
7027 else
7028 ret = 0;
7029 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7030 if (xmlXPathIsInf(arg1->floatval) == 1)
7031 ret = 1;
7032 else
7033 ret = 0;
7034 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7035 if (xmlXPathIsInf(arg1->floatval) == -1)
7036 ret = 1;
7037 else
7038 ret = 0;
7039 } else {
7040 ret = (arg1->floatval == arg2->floatval);
7041 }
7042 break;
7043 case XPATH_USERS:
7044 case XPATH_POINT:
7045 case XPATH_RANGE:
7046 case XPATH_LOCATIONSET:
7047 TODO
7048 break;
7049 case XPATH_NODESET:
7050 case XPATH_XSLT_TREE:
7051 break;
7052 }
7053 break;
7054 case XPATH_STRING:
7055 switch (arg2->type) {
7056 case XPATH_UNDEFINED:
7057 #ifdef DEBUG_EXPR
7058 xmlGenericError(xmlGenericErrorContext,
7059 "Equal: undefined\n");
7060 #endif
7061 break;
7062 case XPATH_BOOLEAN:
7063 if ((arg1->stringval == NULL) ||
7064 (arg1->stringval[0] == 0)) ret = 0;
7065 else
7066 ret = 1;
7067 ret = (arg2->boolval == ret);
7068 break;
7069 case XPATH_STRING:
7070 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7071 break;
7072 case XPATH_NUMBER:
7073 valuePush(ctxt, arg1);
7074 xmlXPathNumberFunction(ctxt, 1);
7075 arg1 = valuePop(ctxt);
7076 /* Hand check NaN and Infinity equalities */
7077 if (xmlXPathIsNaN(arg1->floatval) ||
7078 xmlXPathIsNaN(arg2->floatval)) {
7079 ret = 0;
7080 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7081 if (xmlXPathIsInf(arg2->floatval) == 1)
7082 ret = 1;
7083 else
7084 ret = 0;
7085 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7086 if (xmlXPathIsInf(arg2->floatval) == -1)
7087 ret = 1;
7088 else
7089 ret = 0;
7090 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7091 if (xmlXPathIsInf(arg1->floatval) == 1)
7092 ret = 1;
7093 else
7094 ret = 0;
7095 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7096 if (xmlXPathIsInf(arg1->floatval) == -1)
7097 ret = 1;
7098 else
7099 ret = 0;
7100 } else {
7101 ret = (arg1->floatval == arg2->floatval);
7102 }
7103 break;
7104 case XPATH_USERS:
7105 case XPATH_POINT:
7106 case XPATH_RANGE:
7107 case XPATH_LOCATIONSET:
7108 TODO
7109 break;
7110 case XPATH_NODESET:
7111 case XPATH_XSLT_TREE:
7112 break;
7113 }
7114 break;
7115 case XPATH_USERS:
7116 case XPATH_POINT:
7117 case XPATH_RANGE:
7118 case XPATH_LOCATIONSET:
7119 TODO
7120 break;
7121 case XPATH_NODESET:
7122 case XPATH_XSLT_TREE:
7123 break;
7124 }
7125 xmlXPathReleaseObject(ctxt->context, arg1);
7126 xmlXPathReleaseObject(ctxt->context, arg2);
7127 return(ret);
7128 }
7129
7130 /**
7131 * xmlXPathEqualValues:
7132 * @ctxt: the XPath Parser context
7133 *
7134 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7135 *
7136 * Returns 0 or 1 depending on the results of the test.
7137 */
7138 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7139 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7140 xmlXPathObjectPtr arg1, arg2, argtmp;
7141 int ret = 0;
7142
7143 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7144 arg2 = valuePop(ctxt);
7145 arg1 = valuePop(ctxt);
7146 if ((arg1 == NULL) || (arg2 == NULL)) {
7147 if (arg1 != NULL)
7148 xmlXPathReleaseObject(ctxt->context, arg1);
7149 else
7150 xmlXPathReleaseObject(ctxt->context, arg2);
7151 XP_ERROR0(XPATH_INVALID_OPERAND);
7152 }
7153
7154 if (arg1 == arg2) {
7155 #ifdef DEBUG_EXPR
7156 xmlGenericError(xmlGenericErrorContext,
7157 "Equal: by pointer\n");
7158 #endif
7159 xmlXPathFreeObject(arg1);
7160 return(1);
7161 }
7162
7163 /*
7164 *If either argument is a nodeset, it's a 'special case'
7165 */
7166 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7167 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7168 /*
7169 *Hack it to assure arg1 is the nodeset
7170 */
7171 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7172 argtmp = arg2;
7173 arg2 = arg1;
7174 arg1 = argtmp;
7175 }
7176 switch (arg2->type) {
7177 case XPATH_UNDEFINED:
7178 #ifdef DEBUG_EXPR
7179 xmlGenericError(xmlGenericErrorContext,
7180 "Equal: undefined\n");
7181 #endif
7182 break;
7183 case XPATH_NODESET:
7184 case XPATH_XSLT_TREE:
7185 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7186 break;
7187 case XPATH_BOOLEAN:
7188 if ((arg1->nodesetval == NULL) ||
7189 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7190 else
7191 ret = 1;
7192 ret = (ret == arg2->boolval);
7193 break;
7194 case XPATH_NUMBER:
7195 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7196 break;
7197 case XPATH_STRING:
7198 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7199 break;
7200 case XPATH_USERS:
7201 case XPATH_POINT:
7202 case XPATH_RANGE:
7203 case XPATH_LOCATIONSET:
7204 TODO
7205 break;
7206 }
7207 xmlXPathReleaseObject(ctxt->context, arg1);
7208 xmlXPathReleaseObject(ctxt->context, arg2);
7209 return(ret);
7210 }
7211
7212 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7213 }
7214
7215 /**
7216 * xmlXPathNotEqualValues:
7217 * @ctxt: the XPath Parser context
7218 *
7219 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7220 *
7221 * Returns 0 or 1 depending on the results of the test.
7222 */
7223 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7224 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7225 xmlXPathObjectPtr arg1, arg2, argtmp;
7226 int ret = 0;
7227
7228 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7229 arg2 = valuePop(ctxt);
7230 arg1 = valuePop(ctxt);
7231 if ((arg1 == NULL) || (arg2 == NULL)) {
7232 if (arg1 != NULL)
7233 xmlXPathReleaseObject(ctxt->context, arg1);
7234 else
7235 xmlXPathReleaseObject(ctxt->context, arg2);
7236 XP_ERROR0(XPATH_INVALID_OPERAND);
7237 }
7238
7239 if (arg1 == arg2) {
7240 #ifdef DEBUG_EXPR
7241 xmlGenericError(xmlGenericErrorContext,
7242 "NotEqual: by pointer\n");
7243 #endif
7244 xmlXPathReleaseObject(ctxt->context, arg1);
7245 return(0);
7246 }
7247
7248 /*
7249 *If either argument is a nodeset, it's a 'special case'
7250 */
7251 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7252 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7253 /*
7254 *Hack it to assure arg1 is the nodeset
7255 */
7256 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7257 argtmp = arg2;
7258 arg2 = arg1;
7259 arg1 = argtmp;
7260 }
7261 switch (arg2->type) {
7262 case XPATH_UNDEFINED:
7263 #ifdef DEBUG_EXPR
7264 xmlGenericError(xmlGenericErrorContext,
7265 "NotEqual: undefined\n");
7266 #endif
7267 break;
7268 case XPATH_NODESET:
7269 case XPATH_XSLT_TREE:
7270 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7271 break;
7272 case XPATH_BOOLEAN:
7273 if ((arg1->nodesetval == NULL) ||
7274 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7275 else
7276 ret = 1;
7277 ret = (ret != arg2->boolval);
7278 break;
7279 case XPATH_NUMBER:
7280 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7281 break;
7282 case XPATH_STRING:
7283 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7284 break;
7285 case XPATH_USERS:
7286 case XPATH_POINT:
7287 case XPATH_RANGE:
7288 case XPATH_LOCATIONSET:
7289 TODO
7290 break;
7291 }
7292 xmlXPathReleaseObject(ctxt->context, arg1);
7293 xmlXPathReleaseObject(ctxt->context, arg2);
7294 return(ret);
7295 }
7296
7297 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7298 }
7299
7300 /**
7301 * xmlXPathCompareValues:
7302 * @ctxt: the XPath Parser context
7303 * @inf: less than (1) or greater than (0)
7304 * @strict: is the comparison strict
7305 *
7306 * Implement the compare operation on XPath objects:
7307 * @arg1 < @arg2 (1, 1, ...
7308 * @arg1 <= @arg2 (1, 0, ...
7309 * @arg1 > @arg2 (0, 1, ...
7310 * @arg1 >= @arg2 (0, 0, ...
7311 *
7312 * When neither object to be compared is a node-set and the operator is
7313 * <=, <, >=, >, then the objects are compared by converted both objects
7314 * to numbers and comparing the numbers according to IEEE 754. The <
7315 * comparison will be true if and only if the first number is less than the
7316 * second number. The <= comparison will be true if and only if the first
7317 * number is less than or equal to the second number. The > comparison
7318 * will be true if and only if the first number is greater than the second
7319 * number. The >= comparison will be true if and only if the first number
7320 * is greater than or equal to the second number.
7321 *
7322 * Returns 1 if the comparison succeeded, 0 if it failed
7323 */
7324 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7325 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7326 int ret = 0, arg1i = 0, arg2i = 0;
7327 xmlXPathObjectPtr arg1, arg2;
7328
7329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7330 arg2 = valuePop(ctxt);
7331 arg1 = valuePop(ctxt);
7332 if ((arg1 == NULL) || (arg2 == NULL)) {
7333 if (arg1 != NULL)
7334 xmlXPathReleaseObject(ctxt->context, arg1);
7335 else
7336 xmlXPathReleaseObject(ctxt->context, arg2);
7337 XP_ERROR0(XPATH_INVALID_OPERAND);
7338 }
7339
7340 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7341 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7342 /*
7343 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7344 * are not freed from within this routine; they will be freed from the
7345 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7346 */
7347 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7348 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7349 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7350 } else {
7351 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7352 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7353 arg1, arg2);
7354 } else {
7355 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7356 arg2, arg1);
7357 }
7358 }
7359 return(ret);
7360 }
7361
7362 if (arg1->type != XPATH_NUMBER) {
7363 valuePush(ctxt, arg1);
7364 xmlXPathNumberFunction(ctxt, 1);
7365 arg1 = valuePop(ctxt);
7366 }
7367 if (arg1->type != XPATH_NUMBER) {
7368 xmlXPathFreeObject(arg1);
7369 xmlXPathFreeObject(arg2);
7370 XP_ERROR0(XPATH_INVALID_OPERAND);
7371 }
7372 if (arg2->type != XPATH_NUMBER) {
7373 valuePush(ctxt, arg2);
7374 xmlXPathNumberFunction(ctxt, 1);
7375 arg2 = valuePop(ctxt);
7376 }
7377 if (arg2->type != XPATH_NUMBER) {
7378 xmlXPathReleaseObject(ctxt->context, arg1);
7379 xmlXPathReleaseObject(ctxt->context, arg2);
7380 XP_ERROR0(XPATH_INVALID_OPERAND);
7381 }
7382 /*
7383 * Add tests for infinity and nan
7384 * => feedback on 3.4 for Inf and NaN
7385 */
7386 /* Hand check NaN and Infinity comparisons */
7387 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7388 ret=0;
7389 } else {
7390 arg1i=xmlXPathIsInf(arg1->floatval);
7391 arg2i=xmlXPathIsInf(arg2->floatval);
7392 if (inf && strict) {
7393 if ((arg1i == -1 && arg2i != -1) ||
7394 (arg2i == 1 && arg1i != 1)) {
7395 ret = 1;
7396 } else if (arg1i == 0 && arg2i == 0) {
7397 ret = (arg1->floatval < arg2->floatval);
7398 } else {
7399 ret = 0;
7400 }
7401 }
7402 else if (inf && !strict) {
7403 if (arg1i == -1 || arg2i == 1) {
7404 ret = 1;
7405 } else if (arg1i == 0 && arg2i == 0) {
7406 ret = (arg1->floatval <= arg2->floatval);
7407 } else {
7408 ret = 0;
7409 }
7410 }
7411 else if (!inf && strict) {
7412 if ((arg1i == 1 && arg2i != 1) ||
7413 (arg2i == -1 && arg1i != -1)) {
7414 ret = 1;
7415 } else if (arg1i == 0 && arg2i == 0) {
7416 ret = (arg1->floatval > arg2->floatval);
7417 } else {
7418 ret = 0;
7419 }
7420 }
7421 else if (!inf && !strict) {
7422 if (arg1i == 1 || arg2i == -1) {
7423 ret = 1;
7424 } else if (arg1i == 0 && arg2i == 0) {
7425 ret = (arg1->floatval >= arg2->floatval);
7426 } else {
7427 ret = 0;
7428 }
7429 }
7430 }
7431 xmlXPathReleaseObject(ctxt->context, arg1);
7432 xmlXPathReleaseObject(ctxt->context, arg2);
7433 return(ret);
7434 }
7435
7436 /**
7437 * xmlXPathValueFlipSign:
7438 * @ctxt: the XPath Parser context
7439 *
7440 * Implement the unary - operation on an XPath object
7441 * The numeric operators convert their operands to numbers as if
7442 * by calling the number function.
7443 */
7444 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7445 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7446 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7447 CAST_TO_NUMBER;
7448 CHECK_TYPE(XPATH_NUMBER);
7449 ctxt->value->floatval = -ctxt->value->floatval;
7450 }
7451
7452 /**
7453 * xmlXPathAddValues:
7454 * @ctxt: the XPath Parser context
7455 *
7456 * Implement the add operation on XPath objects:
7457 * The numeric operators convert their operands to numbers as if
7458 * by calling the number function.
7459 */
7460 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7461 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7462 xmlXPathObjectPtr arg;
7463 double val;
7464
7465 arg = valuePop(ctxt);
7466 if (arg == NULL)
7467 XP_ERROR(XPATH_INVALID_OPERAND);
7468 val = xmlXPathCastToNumber(arg);
7469 xmlXPathReleaseObject(ctxt->context, arg);
7470 CAST_TO_NUMBER;
7471 CHECK_TYPE(XPATH_NUMBER);
7472 ctxt->value->floatval += val;
7473 }
7474
7475 /**
7476 * xmlXPathSubValues:
7477 * @ctxt: the XPath Parser context
7478 *
7479 * Implement the subtraction operation on XPath objects:
7480 * The numeric operators convert their operands to numbers as if
7481 * by calling the number function.
7482 */
7483 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7484 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7485 xmlXPathObjectPtr arg;
7486 double val;
7487
7488 arg = valuePop(ctxt);
7489 if (arg == NULL)
7490 XP_ERROR(XPATH_INVALID_OPERAND);
7491 val = xmlXPathCastToNumber(arg);
7492 xmlXPathReleaseObject(ctxt->context, arg);
7493 CAST_TO_NUMBER;
7494 CHECK_TYPE(XPATH_NUMBER);
7495 ctxt->value->floatval -= val;
7496 }
7497
7498 /**
7499 * xmlXPathMultValues:
7500 * @ctxt: the XPath Parser context
7501 *
7502 * Implement the multiply operation on XPath objects:
7503 * The numeric operators convert their operands to numbers as if
7504 * by calling the number function.
7505 */
7506 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7507 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7508 xmlXPathObjectPtr arg;
7509 double val;
7510
7511 arg = valuePop(ctxt);
7512 if (arg == NULL)
7513 XP_ERROR(XPATH_INVALID_OPERAND);
7514 val = xmlXPathCastToNumber(arg);
7515 xmlXPathReleaseObject(ctxt->context, arg);
7516 CAST_TO_NUMBER;
7517 CHECK_TYPE(XPATH_NUMBER);
7518 ctxt->value->floatval *= val;
7519 }
7520
7521 /**
7522 * xmlXPathDivValues:
7523 * @ctxt: the XPath Parser context
7524 *
7525 * Implement the div operation on XPath objects @arg1 / @arg2:
7526 * The numeric operators convert their operands to numbers as if
7527 * by calling the number function.
7528 */
7529 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7530 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7531 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7532 xmlXPathObjectPtr arg;
7533 double val;
7534
7535 arg = valuePop(ctxt);
7536 if (arg == NULL)
7537 XP_ERROR(XPATH_INVALID_OPERAND);
7538 val = xmlXPathCastToNumber(arg);
7539 xmlXPathReleaseObject(ctxt->context, arg);
7540 CAST_TO_NUMBER;
7541 CHECK_TYPE(XPATH_NUMBER);
7542 ctxt->value->floatval /= val;
7543 }
7544
7545 /**
7546 * xmlXPathModValues:
7547 * @ctxt: the XPath Parser context
7548 *
7549 * Implement the mod operation on XPath objects: @arg1 / @arg2
7550 * The numeric operators convert their operands to numbers as if
7551 * by calling the number function.
7552 */
7553 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7554 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7555 xmlXPathObjectPtr arg;
7556 double arg1, arg2;
7557
7558 arg = valuePop(ctxt);
7559 if (arg == NULL)
7560 XP_ERROR(XPATH_INVALID_OPERAND);
7561 arg2 = xmlXPathCastToNumber(arg);
7562 xmlXPathReleaseObject(ctxt->context, arg);
7563 CAST_TO_NUMBER;
7564 CHECK_TYPE(XPATH_NUMBER);
7565 arg1 = ctxt->value->floatval;
7566 if (arg2 == 0)
7567 ctxt->value->floatval = NAN;
7568 else {
7569 ctxt->value->floatval = fmod(arg1, arg2);
7570 }
7571 }
7572
7573 /************************************************************************
7574 * *
7575 * The traversal functions *
7576 * *
7577 ************************************************************************/
7578
7579 /*
7580 * A traversal function enumerates nodes along an axis.
7581 * Initially it must be called with NULL, and it indicates
7582 * termination on the axis by returning NULL.
7583 */
7584 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7585 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7586
7587 /*
7588 * xmlXPathTraversalFunctionExt:
7589 * A traversal function enumerates nodes along an axis.
7590 * Initially it must be called with NULL, and it indicates
7591 * termination on the axis by returning NULL.
7592 * The context node of the traversal is specified via @contextNode.
7593 */
7594 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7595 (xmlNodePtr cur, xmlNodePtr contextNode);
7596
7597 /*
7598 * xmlXPathNodeSetMergeFunction:
7599 * Used for merging node sets in xmlXPathCollectAndTest().
7600 */
7601 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7602 (xmlNodeSetPtr, xmlNodeSetPtr);
7603
7604
7605 /**
7606 * xmlXPathNextSelf:
7607 * @ctxt: the XPath Parser context
7608 * @cur: the current node in the traversal
7609 *
7610 * Traversal function for the "self" direction
7611 * The self axis contains just the context node itself
7612 *
7613 * Returns the next element following that axis
7614 */
7615 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7616 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7617 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7618 if (cur == NULL)
7619 return(ctxt->context->node);
7620 return(NULL);
7621 }
7622
7623 /**
7624 * xmlXPathNextChild:
7625 * @ctxt: the XPath Parser context
7626 * @cur: the current node in the traversal
7627 *
7628 * Traversal function for the "child" direction
7629 * The child axis contains the children of the context node in document order.
7630 *
7631 * Returns the next element following that axis
7632 */
7633 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7634 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7635 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7636 if (cur == NULL) {
7637 if (ctxt->context->node == NULL) return(NULL);
7638 switch (ctxt->context->node->type) {
7639 case XML_ELEMENT_NODE:
7640 case XML_TEXT_NODE:
7641 case XML_CDATA_SECTION_NODE:
7642 case XML_ENTITY_REF_NODE:
7643 case XML_ENTITY_NODE:
7644 case XML_PI_NODE:
7645 case XML_COMMENT_NODE:
7646 case XML_NOTATION_NODE:
7647 case XML_DTD_NODE:
7648 return(ctxt->context->node->children);
7649 case XML_DOCUMENT_NODE:
7650 case XML_DOCUMENT_TYPE_NODE:
7651 case XML_DOCUMENT_FRAG_NODE:
7652 case XML_HTML_DOCUMENT_NODE:
7653 #ifdef LIBXML_DOCB_ENABLED
7654 case XML_DOCB_DOCUMENT_NODE:
7655 #endif
7656 return(((xmlDocPtr) ctxt->context->node)->children);
7657 case XML_ELEMENT_DECL:
7658 case XML_ATTRIBUTE_DECL:
7659 case XML_ENTITY_DECL:
7660 case XML_ATTRIBUTE_NODE:
7661 case XML_NAMESPACE_DECL:
7662 case XML_XINCLUDE_START:
7663 case XML_XINCLUDE_END:
7664 return(NULL);
7665 }
7666 return(NULL);
7667 }
7668 if ((cur->type == XML_DOCUMENT_NODE) ||
7669 (cur->type == XML_HTML_DOCUMENT_NODE))
7670 return(NULL);
7671 return(cur->next);
7672 }
7673
7674 /**
7675 * xmlXPathNextChildElement:
7676 * @ctxt: the XPath Parser context
7677 * @cur: the current node in the traversal
7678 *
7679 * Traversal function for the "child" direction and nodes of type element.
7680 * The child axis contains the children of the context node in document order.
7681 *
7682 * Returns the next element following that axis
7683 */
7684 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7685 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7686 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7687 if (cur == NULL) {
7688 cur = ctxt->context->node;
7689 if (cur == NULL) return(NULL);
7690 /*
7691 * Get the first element child.
7692 */
7693 switch (cur->type) {
7694 case XML_ELEMENT_NODE:
7695 case XML_DOCUMENT_FRAG_NODE:
7696 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7697 case XML_ENTITY_NODE:
7698 cur = cur->children;
7699 if (cur != NULL) {
7700 if (cur->type == XML_ELEMENT_NODE)
7701 return(cur);
7702 do {
7703 cur = cur->next;
7704 } while ((cur != NULL) &&
7705 (cur->type != XML_ELEMENT_NODE));
7706 return(cur);
7707 }
7708 return(NULL);
7709 case XML_DOCUMENT_NODE:
7710 case XML_HTML_DOCUMENT_NODE:
7711 #ifdef LIBXML_DOCB_ENABLED
7712 case XML_DOCB_DOCUMENT_NODE:
7713 #endif
7714 return(xmlDocGetRootElement((xmlDocPtr) cur));
7715 default:
7716 return(NULL);
7717 }
7718 return(NULL);
7719 }
7720 /*
7721 * Get the next sibling element node.
7722 */
7723 switch (cur->type) {
7724 case XML_ELEMENT_NODE:
7725 case XML_TEXT_NODE:
7726 case XML_ENTITY_REF_NODE:
7727 case XML_ENTITY_NODE:
7728 case XML_CDATA_SECTION_NODE:
7729 case XML_PI_NODE:
7730 case XML_COMMENT_NODE:
7731 case XML_XINCLUDE_END:
7732 break;
7733 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7734 default:
7735 return(NULL);
7736 }
7737 if (cur->next != NULL) {
7738 if (cur->next->type == XML_ELEMENT_NODE)
7739 return(cur->next);
7740 cur = cur->next;
7741 do {
7742 cur = cur->next;
7743 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7744 return(cur);
7745 }
7746 return(NULL);
7747 }
7748
7749 #if 0
7750 /**
7751 * xmlXPathNextDescendantOrSelfElemParent:
7752 * @ctxt: the XPath Parser context
7753 * @cur: the current node in the traversal
7754 *
7755 * Traversal function for the "descendant-or-self" axis.
7756 * Additionally it returns only nodes which can be parents of
7757 * element nodes.
7758 *
7759 *
7760 * Returns the next element following that axis
7761 */
7762 static xmlNodePtr
7763 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7764 xmlNodePtr contextNode)
7765 {
7766 if (cur == NULL) {
7767 if (contextNode == NULL)
7768 return(NULL);
7769 switch (contextNode->type) {
7770 case XML_ELEMENT_NODE:
7771 case XML_XINCLUDE_START:
7772 case XML_DOCUMENT_FRAG_NODE:
7773 case XML_DOCUMENT_NODE:
7774 #ifdef LIBXML_DOCB_ENABLED
7775 case XML_DOCB_DOCUMENT_NODE:
7776 #endif
7777 case XML_HTML_DOCUMENT_NODE:
7778 return(contextNode);
7779 default:
7780 return(NULL);
7781 }
7782 return(NULL);
7783 } else {
7784 xmlNodePtr start = cur;
7785
7786 while (cur != NULL) {
7787 switch (cur->type) {
7788 case XML_ELEMENT_NODE:
7789 /* TODO: OK to have XInclude here? */
7790 case XML_XINCLUDE_START:
7791 case XML_DOCUMENT_FRAG_NODE:
7792 if (cur != start)
7793 return(cur);
7794 if (cur->children != NULL) {
7795 cur = cur->children;
7796 continue;
7797 }
7798 break;
7799 /* Not sure if we need those here. */
7800 case XML_DOCUMENT_NODE:
7801 #ifdef LIBXML_DOCB_ENABLED
7802 case XML_DOCB_DOCUMENT_NODE:
7803 #endif
7804 case XML_HTML_DOCUMENT_NODE:
7805 if (cur != start)
7806 return(cur);
7807 return(xmlDocGetRootElement((xmlDocPtr) cur));
7808 default:
7809 break;
7810 }
7811
7812 next_sibling:
7813 if ((cur == NULL) || (cur == contextNode))
7814 return(NULL);
7815 if (cur->next != NULL) {
7816 cur = cur->next;
7817 } else {
7818 cur = cur->parent;
7819 goto next_sibling;
7820 }
7821 }
7822 }
7823 return(NULL);
7824 }
7825 #endif
7826
7827 /**
7828 * xmlXPathNextDescendant:
7829 * @ctxt: the XPath Parser context
7830 * @cur: the current node in the traversal
7831 *
7832 * Traversal function for the "descendant" direction
7833 * the descendant axis contains the descendants of the context node in document
7834 * order; a descendant is a child or a child of a child and so on.
7835 *
7836 * Returns the next element following that axis
7837 */
7838 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7839 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7840 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7841 if (cur == NULL) {
7842 if (ctxt->context->node == NULL)
7843 return(NULL);
7844 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7845 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7846 return(NULL);
7847
7848 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7849 return(ctxt->context->doc->children);
7850 return(ctxt->context->node->children);
7851 }
7852
7853 if (cur->type == XML_NAMESPACE_DECL)
7854 return(NULL);
7855 if (cur->children != NULL) {
7856 /*
7857 * Do not descend on entities declarations
7858 */
7859 if (cur->children->type != XML_ENTITY_DECL) {
7860 cur = cur->children;
7861 /*
7862 * Skip DTDs
7863 */
7864 if (cur->type != XML_DTD_NODE)
7865 return(cur);
7866 }
7867 }
7868
7869 if (cur == ctxt->context->node) return(NULL);
7870
7871 while (cur->next != NULL) {
7872 cur = cur->next;
7873 if ((cur->type != XML_ENTITY_DECL) &&
7874 (cur->type != XML_DTD_NODE))
7875 return(cur);
7876 }
7877
7878 do {
7879 cur = cur->parent;
7880 if (cur == NULL) break;
7881 if (cur == ctxt->context->node) return(NULL);
7882 if (cur->next != NULL) {
7883 cur = cur->next;
7884 return(cur);
7885 }
7886 } while (cur != NULL);
7887 return(cur);
7888 }
7889
7890 /**
7891 * xmlXPathNextDescendantOrSelf:
7892 * @ctxt: the XPath Parser context
7893 * @cur: the current node in the traversal
7894 *
7895 * Traversal function for the "descendant-or-self" direction
7896 * the descendant-or-self axis contains the context node and the descendants
7897 * of the context node in document order; thus the context node is the first
7898 * node on the axis, and the first child of the context node is the second node
7899 * on the axis
7900 *
7901 * Returns the next element following that axis
7902 */
7903 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7904 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7905 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7906 if (cur == NULL)
7907 return(ctxt->context->node);
7908
7909 if (ctxt->context->node == NULL)
7910 return(NULL);
7911 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7912 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7913 return(NULL);
7914
7915 return(xmlXPathNextDescendant(ctxt, cur));
7916 }
7917
7918 /**
7919 * xmlXPathNextParent:
7920 * @ctxt: the XPath Parser context
7921 * @cur: the current node in the traversal
7922 *
7923 * Traversal function for the "parent" direction
7924 * The parent axis contains the parent of the context node, if there is one.
7925 *
7926 * Returns the next element following that axis
7927 */
7928 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7929 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931 /*
7932 * the parent of an attribute or namespace node is the element
7933 * to which the attribute or namespace node is attached
7934 * Namespace handling !!!
7935 */
7936 if (cur == NULL) {
7937 if (ctxt->context->node == NULL) return(NULL);
7938 switch (ctxt->context->node->type) {
7939 case XML_ELEMENT_NODE:
7940 case XML_TEXT_NODE:
7941 case XML_CDATA_SECTION_NODE:
7942 case XML_ENTITY_REF_NODE:
7943 case XML_ENTITY_NODE:
7944 case XML_PI_NODE:
7945 case XML_COMMENT_NODE:
7946 case XML_NOTATION_NODE:
7947 case XML_DTD_NODE:
7948 case XML_ELEMENT_DECL:
7949 case XML_ATTRIBUTE_DECL:
7950 case XML_XINCLUDE_START:
7951 case XML_XINCLUDE_END:
7952 case XML_ENTITY_DECL:
7953 if (ctxt->context->node->parent == NULL)
7954 return((xmlNodePtr) ctxt->context->doc);
7955 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7956 ((ctxt->context->node->parent->name[0] == ' ') ||
7957 (xmlStrEqual(ctxt->context->node->parent->name,
7958 BAD_CAST "fake node libxslt"))))
7959 return(NULL);
7960 return(ctxt->context->node->parent);
7961 case XML_ATTRIBUTE_NODE: {
7962 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7963
7964 return(att->parent);
7965 }
7966 case XML_DOCUMENT_NODE:
7967 case XML_DOCUMENT_TYPE_NODE:
7968 case XML_DOCUMENT_FRAG_NODE:
7969 case XML_HTML_DOCUMENT_NODE:
7970 #ifdef LIBXML_DOCB_ENABLED
7971 case XML_DOCB_DOCUMENT_NODE:
7972 #endif
7973 return(NULL);
7974 case XML_NAMESPACE_DECL: {
7975 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7976
7977 if ((ns->next != NULL) &&
7978 (ns->next->type != XML_NAMESPACE_DECL))
7979 return((xmlNodePtr) ns->next);
7980 return(NULL);
7981 }
7982 }
7983 }
7984 return(NULL);
7985 }
7986
7987 /**
7988 * xmlXPathNextAncestor:
7989 * @ctxt: the XPath Parser context
7990 * @cur: the current node in the traversal
7991 *
7992 * Traversal function for the "ancestor" direction
7993 * the ancestor axis contains the ancestors of the context node; the ancestors
7994 * of the context node consist of the parent of context node and the parent's
7995 * parent and so on; the nodes are ordered in reverse document order; thus the
7996 * parent is the first node on the axis, and the parent's parent is the second
7997 * node on the axis
7998 *
7999 * Returns the next element following that axis
8000 */
8001 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8002 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8003 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8004 /*
8005 * the parent of an attribute or namespace node is the element
8006 * to which the attribute or namespace node is attached
8007 * !!!!!!!!!!!!!
8008 */
8009 if (cur == NULL) {
8010 if (ctxt->context->node == NULL) return(NULL);
8011 switch (ctxt->context->node->type) {
8012 case XML_ELEMENT_NODE:
8013 case XML_TEXT_NODE:
8014 case XML_CDATA_SECTION_NODE:
8015 case XML_ENTITY_REF_NODE:
8016 case XML_ENTITY_NODE:
8017 case XML_PI_NODE:
8018 case XML_COMMENT_NODE:
8019 case XML_DTD_NODE:
8020 case XML_ELEMENT_DECL:
8021 case XML_ATTRIBUTE_DECL:
8022 case XML_ENTITY_DECL:
8023 case XML_NOTATION_NODE:
8024 case XML_XINCLUDE_START:
8025 case XML_XINCLUDE_END:
8026 if (ctxt->context->node->parent == NULL)
8027 return((xmlNodePtr) ctxt->context->doc);
8028 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8029 ((ctxt->context->node->parent->name[0] == ' ') ||
8030 (xmlStrEqual(ctxt->context->node->parent->name,
8031 BAD_CAST "fake node libxslt"))))
8032 return(NULL);
8033 return(ctxt->context->node->parent);
8034 case XML_ATTRIBUTE_NODE: {
8035 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8036
8037 return(tmp->parent);
8038 }
8039 case XML_DOCUMENT_NODE:
8040 case XML_DOCUMENT_TYPE_NODE:
8041 case XML_DOCUMENT_FRAG_NODE:
8042 case XML_HTML_DOCUMENT_NODE:
8043 #ifdef LIBXML_DOCB_ENABLED
8044 case XML_DOCB_DOCUMENT_NODE:
8045 #endif
8046 return(NULL);
8047 case XML_NAMESPACE_DECL: {
8048 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8049
8050 if ((ns->next != NULL) &&
8051 (ns->next->type != XML_NAMESPACE_DECL))
8052 return((xmlNodePtr) ns->next);
8053 /* Bad, how did that namespace end up here ? */
8054 return(NULL);
8055 }
8056 }
8057 return(NULL);
8058 }
8059 if (cur == ctxt->context->doc->children)
8060 return((xmlNodePtr) ctxt->context->doc);
8061 if (cur == (xmlNodePtr) ctxt->context->doc)
8062 return(NULL);
8063 switch (cur->type) {
8064 case XML_ELEMENT_NODE:
8065 case XML_TEXT_NODE:
8066 case XML_CDATA_SECTION_NODE:
8067 case XML_ENTITY_REF_NODE:
8068 case XML_ENTITY_NODE:
8069 case XML_PI_NODE:
8070 case XML_COMMENT_NODE:
8071 case XML_NOTATION_NODE:
8072 case XML_DTD_NODE:
8073 case XML_ELEMENT_DECL:
8074 case XML_ATTRIBUTE_DECL:
8075 case XML_ENTITY_DECL:
8076 case XML_XINCLUDE_START:
8077 case XML_XINCLUDE_END:
8078 if (cur->parent == NULL)
8079 return(NULL);
8080 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8081 ((cur->parent->name[0] == ' ') ||
8082 (xmlStrEqual(cur->parent->name,
8083 BAD_CAST "fake node libxslt"))))
8084 return(NULL);
8085 return(cur->parent);
8086 case XML_ATTRIBUTE_NODE: {
8087 xmlAttrPtr att = (xmlAttrPtr) cur;
8088
8089 return(att->parent);
8090 }
8091 case XML_NAMESPACE_DECL: {
8092 xmlNsPtr ns = (xmlNsPtr) cur;
8093
8094 if ((ns->next != NULL) &&
8095 (ns->next->type != XML_NAMESPACE_DECL))
8096 return((xmlNodePtr) ns->next);
8097 /* Bad, how did that namespace end up here ? */
8098 return(NULL);
8099 }
8100 case XML_DOCUMENT_NODE:
8101 case XML_DOCUMENT_TYPE_NODE:
8102 case XML_DOCUMENT_FRAG_NODE:
8103 case XML_HTML_DOCUMENT_NODE:
8104 #ifdef LIBXML_DOCB_ENABLED
8105 case XML_DOCB_DOCUMENT_NODE:
8106 #endif
8107 return(NULL);
8108 }
8109 return(NULL);
8110 }
8111
8112 /**
8113 * xmlXPathNextAncestorOrSelf:
8114 * @ctxt: the XPath Parser context
8115 * @cur: the current node in the traversal
8116 *
8117 * Traversal function for the "ancestor-or-self" direction
8118 * he ancestor-or-self axis contains the context node and ancestors of
8119 * the context node in reverse document order; thus the context node is
8120 * the first node on the axis, and the context node's parent the second;
8121 * parent here is defined the same as with the parent axis.
8122 *
8123 * Returns the next element following that axis
8124 */
8125 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8126 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8127 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8128 if (cur == NULL)
8129 return(ctxt->context->node);
8130 return(xmlXPathNextAncestor(ctxt, cur));
8131 }
8132
8133 /**
8134 * xmlXPathNextFollowingSibling:
8135 * @ctxt: the XPath Parser context
8136 * @cur: the current node in the traversal
8137 *
8138 * Traversal function for the "following-sibling" direction
8139 * The following-sibling axis contains the following siblings of the context
8140 * node in document order.
8141 *
8142 * Returns the next element following that axis
8143 */
8144 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8145 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8146 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8147 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8148 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8149 return(NULL);
8150 if (cur == (xmlNodePtr) ctxt->context->doc)
8151 return(NULL);
8152 if (cur == NULL)
8153 return(ctxt->context->node->next);
8154 return(cur->next);
8155 }
8156
8157 /**
8158 * xmlXPathNextPrecedingSibling:
8159 * @ctxt: the XPath Parser context
8160 * @cur: the current node in the traversal
8161 *
8162 * Traversal function for the "preceding-sibling" direction
8163 * The preceding-sibling axis contains the preceding siblings of the context
8164 * node in reverse document order; the first preceding sibling is first on the
8165 * axis; the sibling preceding that node is the second on the axis and so on.
8166 *
8167 * Returns the next element following that axis
8168 */
8169 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8170 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8171 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8172 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8173 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8174 return(NULL);
8175 if (cur == (xmlNodePtr) ctxt->context->doc)
8176 return(NULL);
8177 if (cur == NULL)
8178 return(ctxt->context->node->prev);
8179 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8180 cur = cur->prev;
8181 if (cur == NULL)
8182 return(ctxt->context->node->prev);
8183 }
8184 return(cur->prev);
8185 }
8186
8187 /**
8188 * xmlXPathNextFollowing:
8189 * @ctxt: the XPath Parser context
8190 * @cur: the current node in the traversal
8191 *
8192 * Traversal function for the "following" direction
8193 * The following axis contains all nodes in the same document as the context
8194 * node that are after the context node in document order, excluding any
8195 * descendants and excluding attribute nodes and namespace nodes; the nodes
8196 * are ordered in document order
8197 *
8198 * Returns the next element following that axis
8199 */
8200 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8201 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8202 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8203 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8204 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8205 return(cur->children);
8206
8207 if (cur == NULL) {
8208 cur = ctxt->context->node;
8209 if (cur->type == XML_ATTRIBUTE_NODE) {
8210 cur = cur->parent;
8211 } else if (cur->type == XML_NAMESPACE_DECL) {
8212 xmlNsPtr ns = (xmlNsPtr) cur;
8213
8214 if ((ns->next == NULL) ||
8215 (ns->next->type == XML_NAMESPACE_DECL))
8216 return (NULL);
8217 cur = (xmlNodePtr) ns->next;
8218 }
8219 }
8220 if (cur == NULL) return(NULL) ; /* ERROR */
8221 if (cur->next != NULL) return(cur->next) ;
8222 do {
8223 cur = cur->parent;
8224 if (cur == NULL) break;
8225 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8226 if (cur->next != NULL) return(cur->next);
8227 } while (cur != NULL);
8228 return(cur);
8229 }
8230
8231 /*
8232 * xmlXPathIsAncestor:
8233 * @ancestor: the ancestor node
8234 * @node: the current node
8235 *
8236 * Check that @ancestor is a @node's ancestor
8237 *
8238 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8239 */
8240 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8241 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8242 if ((ancestor == NULL) || (node == NULL)) return(0);
8243 if (node->type == XML_NAMESPACE_DECL)
8244 return(0);
8245 if (ancestor->type == XML_NAMESPACE_DECL)
8246 return(0);
8247 /* nodes need to be in the same document */
8248 if (ancestor->doc != node->doc) return(0);
8249 /* avoid searching if ancestor or node is the root node */
8250 if (ancestor == (xmlNodePtr) node->doc) return(1);
8251 if (node == (xmlNodePtr) ancestor->doc) return(0);
8252 while (node->parent != NULL) {
8253 if (node->parent == ancestor)
8254 return(1);
8255 node = node->parent;
8256 }
8257 return(0);
8258 }
8259
8260 /**
8261 * xmlXPathNextPreceding:
8262 * @ctxt: the XPath Parser context
8263 * @cur: the current node in the traversal
8264 *
8265 * Traversal function for the "preceding" direction
8266 * the preceding axis contains all nodes in the same document as the context
8267 * node that are before the context node in document order, excluding any
8268 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8269 * ordered in reverse document order
8270 *
8271 * Returns the next element following that axis
8272 */
8273 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8274 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8275 {
8276 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8277 if (cur == NULL) {
8278 cur = ctxt->context->node;
8279 if (cur->type == XML_ATTRIBUTE_NODE) {
8280 cur = cur->parent;
8281 } else if (cur->type == XML_NAMESPACE_DECL) {
8282 xmlNsPtr ns = (xmlNsPtr) cur;
8283
8284 if ((ns->next == NULL) ||
8285 (ns->next->type == XML_NAMESPACE_DECL))
8286 return (NULL);
8287 cur = (xmlNodePtr) ns->next;
8288 }
8289 }
8290 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8291 return (NULL);
8292 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8293 cur = cur->prev;
8294 do {
8295 if (cur->prev != NULL) {
8296 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8297 return (cur);
8298 }
8299
8300 cur = cur->parent;
8301 if (cur == NULL)
8302 return (NULL);
8303 if (cur == ctxt->context->doc->children)
8304 return (NULL);
8305 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8306 return (cur);
8307 }
8308
8309 /**
8310 * xmlXPathNextPrecedingInternal:
8311 * @ctxt: the XPath Parser context
8312 * @cur: the current node in the traversal
8313 *
8314 * Traversal function for the "preceding" direction
8315 * the preceding axis contains all nodes in the same document as the context
8316 * node that are before the context node in document order, excluding any
8317 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8318 * ordered in reverse document order
8319 * This is a faster implementation but internal only since it requires a
8320 * state kept in the parser context: ctxt->ancestor.
8321 *
8322 * Returns the next element following that axis
8323 */
8324 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8325 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8326 xmlNodePtr cur)
8327 {
8328 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8329 if (cur == NULL) {
8330 cur = ctxt->context->node;
8331 if (cur == NULL)
8332 return (NULL);
8333 if (cur->type == XML_ATTRIBUTE_NODE) {
8334 cur = cur->parent;
8335 } else if (cur->type == XML_NAMESPACE_DECL) {
8336 xmlNsPtr ns = (xmlNsPtr) cur;
8337
8338 if ((ns->next == NULL) ||
8339 (ns->next->type == XML_NAMESPACE_DECL))
8340 return (NULL);
8341 cur = (xmlNodePtr) ns->next;
8342 }
8343 ctxt->ancestor = cur->parent;
8344 }
8345 if (cur->type == XML_NAMESPACE_DECL)
8346 return(NULL);
8347 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8348 cur = cur->prev;
8349 while (cur->prev == NULL) {
8350 cur = cur->parent;
8351 if (cur == NULL)
8352 return (NULL);
8353 if (cur == ctxt->context->doc->children)
8354 return (NULL);
8355 if (cur != ctxt->ancestor)
8356 return (cur);
8357 ctxt->ancestor = cur->parent;
8358 }
8359 cur = cur->prev;
8360 while (cur->last != NULL)
8361 cur = cur->last;
8362 return (cur);
8363 }
8364
8365 /**
8366 * xmlXPathNextNamespace:
8367 * @ctxt: the XPath Parser context
8368 * @cur: the current attribute in the traversal
8369 *
8370 * Traversal function for the "namespace" direction
8371 * the namespace axis contains the namespace nodes of the context node;
8372 * the order of nodes on this axis is implementation-defined; the axis will
8373 * be empty unless the context node is an element
8374 *
8375 * We keep the XML namespace node at the end of the list.
8376 *
8377 * Returns the next element following that axis
8378 */
8379 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8380 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8381 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8382 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8383 if (cur == NULL) {
8384 if (ctxt->context->tmpNsList != NULL)
8385 xmlFree(ctxt->context->tmpNsList);
8386 ctxt->context->tmpNsList =
8387 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8388 ctxt->context->tmpNsNr = 0;
8389 if (ctxt->context->tmpNsList != NULL) {
8390 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8391 ctxt->context->tmpNsNr++;
8392 }
8393 }
8394 return((xmlNodePtr) xmlXPathXMLNamespace);
8395 }
8396 if (ctxt->context->tmpNsNr > 0) {
8397 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8398 } else {
8399 if (ctxt->context->tmpNsList != NULL)
8400 xmlFree(ctxt->context->tmpNsList);
8401 ctxt->context->tmpNsList = NULL;
8402 return(NULL);
8403 }
8404 }
8405
8406 /**
8407 * xmlXPathNextAttribute:
8408 * @ctxt: the XPath Parser context
8409 * @cur: the current attribute in the traversal
8410 *
8411 * Traversal function for the "attribute" direction
8412 * TODO: support DTD inherited default attributes
8413 *
8414 * Returns the next element following that axis
8415 */
8416 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8417 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8418 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8419 if (ctxt->context->node == NULL)
8420 return(NULL);
8421 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8422 return(NULL);
8423 if (cur == NULL) {
8424 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8425 return(NULL);
8426 return((xmlNodePtr)ctxt->context->node->properties);
8427 }
8428 return((xmlNodePtr)cur->next);
8429 }
8430
8431 /************************************************************************
8432 * *
8433 * NodeTest Functions *
8434 * *
8435 ************************************************************************/
8436
8437 #define IS_FUNCTION 200
8438
8439
8440 /************************************************************************
8441 * *
8442 * Implicit tree core function library *
8443 * *
8444 ************************************************************************/
8445
8446 /**
8447 * xmlXPathRoot:
8448 * @ctxt: the XPath Parser context
8449 *
8450 * Initialize the context to the root of the document
8451 */
8452 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8453 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8454 if ((ctxt == NULL) || (ctxt->context == NULL))
8455 return;
8456 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8457 (xmlNodePtr) ctxt->context->doc));
8458 }
8459
8460 /************************************************************************
8461 * *
8462 * The explicit core function library *
8463 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8464 * *
8465 ************************************************************************/
8466
8467
8468 /**
8469 * xmlXPathLastFunction:
8470 * @ctxt: the XPath Parser context
8471 * @nargs: the number of arguments
8472 *
8473 * Implement the last() XPath function
8474 * number last()
8475 * The last function returns the number of nodes in the context node list.
8476 */
8477 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8478 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8479 CHECK_ARITY(0);
8480 if (ctxt->context->contextSize >= 0) {
8481 valuePush(ctxt,
8482 xmlXPathCacheNewFloat(ctxt->context,
8483 (double) ctxt->context->contextSize));
8484 #ifdef DEBUG_EXPR
8485 xmlGenericError(xmlGenericErrorContext,
8486 "last() : %d\n", ctxt->context->contextSize);
8487 #endif
8488 } else {
8489 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8490 }
8491 }
8492
8493 /**
8494 * xmlXPathPositionFunction:
8495 * @ctxt: the XPath Parser context
8496 * @nargs: the number of arguments
8497 *
8498 * Implement the position() XPath function
8499 * number position()
8500 * The position function returns the position of the context node in the
8501 * context node list. The first position is 1, and so the last position
8502 * will be equal to last().
8503 */
8504 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8505 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8506 CHECK_ARITY(0);
8507 if (ctxt->context->proximityPosition >= 0) {
8508 valuePush(ctxt,
8509 xmlXPathCacheNewFloat(ctxt->context,
8510 (double) ctxt->context->proximityPosition));
8511 #ifdef DEBUG_EXPR
8512 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8513 ctxt->context->proximityPosition);
8514 #endif
8515 } else {
8516 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8517 }
8518 }
8519
8520 /**
8521 * xmlXPathCountFunction:
8522 * @ctxt: the XPath Parser context
8523 * @nargs: the number of arguments
8524 *
8525 * Implement the count() XPath function
8526 * number count(node-set)
8527 */
8528 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8529 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8530 xmlXPathObjectPtr cur;
8531
8532 CHECK_ARITY(1);
8533 if ((ctxt->value == NULL) ||
8534 ((ctxt->value->type != XPATH_NODESET) &&
8535 (ctxt->value->type != XPATH_XSLT_TREE)))
8536 XP_ERROR(XPATH_INVALID_TYPE);
8537 cur = valuePop(ctxt);
8538
8539 if ((cur == NULL) || (cur->nodesetval == NULL))
8540 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8541 else
8542 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8543 (double) cur->nodesetval->nodeNr));
8544 xmlXPathReleaseObject(ctxt->context, cur);
8545 }
8546
8547 /**
8548 * xmlXPathGetElementsByIds:
8549 * @doc: the document
8550 * @ids: a whitespace separated list of IDs
8551 *
8552 * Selects elements by their unique ID.
8553 *
8554 * Returns a node-set of selected elements.
8555 */
8556 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8557 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8558 xmlNodeSetPtr ret;
8559 const xmlChar *cur = ids;
8560 xmlChar *ID;
8561 xmlAttrPtr attr;
8562 xmlNodePtr elem = NULL;
8563
8564 if (ids == NULL) return(NULL);
8565
8566 ret = xmlXPathNodeSetCreate(NULL);
8567 if (ret == NULL)
8568 return(ret);
8569
8570 while (IS_BLANK_CH(*cur)) cur++;
8571 while (*cur != 0) {
8572 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8573 cur++;
8574
8575 ID = xmlStrndup(ids, cur - ids);
8576 if (ID != NULL) {
8577 /*
8578 * We used to check the fact that the value passed
8579 * was an NCName, but this generated much troubles for
8580 * me and Aleksey Sanin, people blatantly violated that
8581 * constraint, like Visa3D spec.
8582 * if (xmlValidateNCName(ID, 1) == 0)
8583 */
8584 attr = xmlGetID(doc, ID);
8585 if (attr != NULL) {
8586 if (attr->type == XML_ATTRIBUTE_NODE)
8587 elem = attr->parent;
8588 else if (attr->type == XML_ELEMENT_NODE)
8589 elem = (xmlNodePtr) attr;
8590 else
8591 elem = NULL;
8592 /* TODO: Check memory error. */
8593 if (elem != NULL)
8594 xmlXPathNodeSetAdd(ret, elem);
8595 }
8596 xmlFree(ID);
8597 }
8598
8599 while (IS_BLANK_CH(*cur)) cur++;
8600 ids = cur;
8601 }
8602 return(ret);
8603 }
8604
8605 /**
8606 * xmlXPathIdFunction:
8607 * @ctxt: the XPath Parser context
8608 * @nargs: the number of arguments
8609 *
8610 * Implement the id() XPath function
8611 * node-set id(object)
8612 * The id function selects elements by their unique ID
8613 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8614 * then the result is the union of the result of applying id to the
8615 * string value of each of the nodes in the argument node-set. When the
8616 * argument to id is of any other type, the argument is converted to a
8617 * string as if by a call to the string function; the string is split
8618 * into a whitespace-separated list of tokens (whitespace is any sequence
8619 * of characters matching the production S); the result is a node-set
8620 * containing the elements in the same document as the context node that
8621 * have a unique ID equal to any of the tokens in the list.
8622 */
8623 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8624 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8625 xmlChar *tokens;
8626 xmlNodeSetPtr ret;
8627 xmlXPathObjectPtr obj;
8628
8629 CHECK_ARITY(1);
8630 obj = valuePop(ctxt);
8631 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8632 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8633 xmlNodeSetPtr ns;
8634 int i;
8635
8636 /* TODO: Check memory error. */
8637 ret = xmlXPathNodeSetCreate(NULL);
8638
8639 if (obj->nodesetval != NULL) {
8640 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8641 tokens =
8642 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8643 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8644 /* TODO: Check memory error. */
8645 ret = xmlXPathNodeSetMerge(ret, ns);
8646 xmlXPathFreeNodeSet(ns);
8647 if (tokens != NULL)
8648 xmlFree(tokens);
8649 }
8650 }
8651 xmlXPathReleaseObject(ctxt->context, obj);
8652 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8653 return;
8654 }
8655 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8656 if (obj == NULL) return;
8657 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8658 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8659 xmlXPathReleaseObject(ctxt->context, obj);
8660 return;
8661 }
8662
8663 /**
8664 * xmlXPathLocalNameFunction:
8665 * @ctxt: the XPath Parser context
8666 * @nargs: the number of arguments
8667 *
8668 * Implement the local-name() XPath function
8669 * string local-name(node-set?)
8670 * The local-name function returns a string containing the local part
8671 * of the name of the node in the argument node-set that is first in
8672 * document order. If the node-set is empty or the first node has no
8673 * name, an empty string is returned. If the argument is omitted it
8674 * defaults to the context node.
8675 */
8676 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8677 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8678 xmlXPathObjectPtr cur;
8679
8680 if (ctxt == NULL) return;
8681
8682 if (nargs == 0) {
8683 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8684 ctxt->context->node));
8685 nargs = 1;
8686 }
8687
8688 CHECK_ARITY(1);
8689 if ((ctxt->value == NULL) ||
8690 ((ctxt->value->type != XPATH_NODESET) &&
8691 (ctxt->value->type != XPATH_XSLT_TREE)))
8692 XP_ERROR(XPATH_INVALID_TYPE);
8693 cur = valuePop(ctxt);
8694
8695 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8696 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8697 } else {
8698 int i = 0; /* Should be first in document order !!!!! */
8699 switch (cur->nodesetval->nodeTab[i]->type) {
8700 case XML_ELEMENT_NODE:
8701 case XML_ATTRIBUTE_NODE:
8702 case XML_PI_NODE:
8703 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8704 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8705 else
8706 valuePush(ctxt,
8707 xmlXPathCacheNewString(ctxt->context,
8708 cur->nodesetval->nodeTab[i]->name));
8709 break;
8710 case XML_NAMESPACE_DECL:
8711 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8712 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8713 break;
8714 default:
8715 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8716 }
8717 }
8718 xmlXPathReleaseObject(ctxt->context, cur);
8719 }
8720
8721 /**
8722 * xmlXPathNamespaceURIFunction:
8723 * @ctxt: the XPath Parser context
8724 * @nargs: the number of arguments
8725 *
8726 * Implement the namespace-uri() XPath function
8727 * string namespace-uri(node-set?)
8728 * The namespace-uri function returns a string containing the
8729 * namespace URI of the expanded name of the node in the argument
8730 * node-set that is first in document order. If the node-set is empty,
8731 * the first node has no name, or the expanded name has no namespace
8732 * URI, an empty string is returned. If the argument is omitted it
8733 * defaults to the context node.
8734 */
8735 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8736 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8737 xmlXPathObjectPtr cur;
8738
8739 if (ctxt == NULL) return;
8740
8741 if (nargs == 0) {
8742 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8743 ctxt->context->node));
8744 nargs = 1;
8745 }
8746 CHECK_ARITY(1);
8747 if ((ctxt->value == NULL) ||
8748 ((ctxt->value->type != XPATH_NODESET) &&
8749 (ctxt->value->type != XPATH_XSLT_TREE)))
8750 XP_ERROR(XPATH_INVALID_TYPE);
8751 cur = valuePop(ctxt);
8752
8753 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8754 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8755 } else {
8756 int i = 0; /* Should be first in document order !!!!! */
8757 switch (cur->nodesetval->nodeTab[i]->type) {
8758 case XML_ELEMENT_NODE:
8759 case XML_ATTRIBUTE_NODE:
8760 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8761 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8762 else
8763 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8764 cur->nodesetval->nodeTab[i]->ns->href));
8765 break;
8766 default:
8767 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8768 }
8769 }
8770 xmlXPathReleaseObject(ctxt->context, cur);
8771 }
8772
8773 /**
8774 * xmlXPathNameFunction:
8775 * @ctxt: the XPath Parser context
8776 * @nargs: the number of arguments
8777 *
8778 * Implement the name() XPath function
8779 * string name(node-set?)
8780 * The name function returns a string containing a QName representing
8781 * the name of the node in the argument node-set that is first in document
8782 * order. The QName must represent the name with respect to the namespace
8783 * declarations in effect on the node whose name is being represented.
8784 * Typically, this will be the form in which the name occurred in the XML
8785 * source. This need not be the case if there are namespace declarations
8786 * in effect on the node that associate multiple prefixes with the same
8787 * namespace. However, an implementation may include information about
8788 * the original prefix in its representation of nodes; in this case, an
8789 * implementation can ensure that the returned string is always the same
8790 * as the QName used in the XML source. If the argument it omitted it
8791 * defaults to the context node.
8792 * Libxml keep the original prefix so the "real qualified name" used is
8793 * returned.
8794 */
8795 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8796 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8797 {
8798 xmlXPathObjectPtr cur;
8799
8800 if (nargs == 0) {
8801 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8802 ctxt->context->node));
8803 nargs = 1;
8804 }
8805
8806 CHECK_ARITY(1);
8807 if ((ctxt->value == NULL) ||
8808 ((ctxt->value->type != XPATH_NODESET) &&
8809 (ctxt->value->type != XPATH_XSLT_TREE)))
8810 XP_ERROR(XPATH_INVALID_TYPE);
8811 cur = valuePop(ctxt);
8812
8813 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8814 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8815 } else {
8816 int i = 0; /* Should be first in document order !!!!! */
8817
8818 switch (cur->nodesetval->nodeTab[i]->type) {
8819 case XML_ELEMENT_NODE:
8820 case XML_ATTRIBUTE_NODE:
8821 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8822 valuePush(ctxt,
8823 xmlXPathCacheNewCString(ctxt->context, ""));
8824 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8825 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8826 valuePush(ctxt,
8827 xmlXPathCacheNewString(ctxt->context,
8828 cur->nodesetval->nodeTab[i]->name));
8829 } else {
8830 xmlChar *fullname;
8831
8832 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8833 cur->nodesetval->nodeTab[i]->ns->prefix,
8834 NULL, 0);
8835 if (fullname == cur->nodesetval->nodeTab[i]->name)
8836 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8837 if (fullname == NULL) {
8838 XP_ERROR(XPATH_MEMORY_ERROR);
8839 }
8840 valuePush(ctxt, xmlXPathCacheWrapString(
8841 ctxt->context, fullname));
8842 }
8843 break;
8844 default:
8845 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8846 cur->nodesetval->nodeTab[i]));
8847 xmlXPathLocalNameFunction(ctxt, 1);
8848 }
8849 }
8850 xmlXPathReleaseObject(ctxt->context, cur);
8851 }
8852
8853
8854 /**
8855 * xmlXPathStringFunction:
8856 * @ctxt: the XPath Parser context
8857 * @nargs: the number of arguments
8858 *
8859 * Implement the string() XPath function
8860 * string string(object?)
8861 * The string function converts an object to a string as follows:
8862 * - A node-set is converted to a string by returning the value of
8863 * the node in the node-set that is first in document order.
8864 * If the node-set is empty, an empty string is returned.
8865 * - A number is converted to a string as follows
8866 * + NaN is converted to the string NaN
8867 * + positive zero is converted to the string 0
8868 * + negative zero is converted to the string 0
8869 * + positive infinity is converted to the string Infinity
8870 * + negative infinity is converted to the string -Infinity
8871 * + if the number is an integer, the number is represented in
8872 * decimal form as a Number with no decimal point and no leading
8873 * zeros, preceded by a minus sign (-) if the number is negative
8874 * + otherwise, the number is represented in decimal form as a
8875 * Number including a decimal point with at least one digit
8876 * before the decimal point and at least one digit after the
8877 * decimal point, preceded by a minus sign (-) if the number
8878 * is negative; there must be no leading zeros before the decimal
8879 * point apart possibly from the one required digit immediately
8880 * before the decimal point; beyond the one required digit
8881 * after the decimal point there must be as many, but only as
8882 * many, more digits as are needed to uniquely distinguish the
8883 * number from all other IEEE 754 numeric values.
8884 * - The boolean false value is converted to the string false.
8885 * The boolean true value is converted to the string true.
8886 *
8887 * If the argument is omitted, it defaults to a node-set with the
8888 * context node as its only member.
8889 */
8890 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8891 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8892 xmlXPathObjectPtr cur;
8893
8894 if (ctxt == NULL) return;
8895 if (nargs == 0) {
8896 valuePush(ctxt,
8897 xmlXPathCacheWrapString(ctxt->context,
8898 xmlXPathCastNodeToString(ctxt->context->node)));
8899 return;
8900 }
8901
8902 CHECK_ARITY(1);
8903 cur = valuePop(ctxt);
8904 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8905 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8906 }
8907
8908 /**
8909 * xmlXPathStringLengthFunction:
8910 * @ctxt: the XPath Parser context
8911 * @nargs: the number of arguments
8912 *
8913 * Implement the string-length() XPath function
8914 * number string-length(string?)
8915 * The string-length returns the number of characters in the string
8916 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8917 * the context node converted to a string, in other words the value
8918 * of the context node.
8919 */
8920 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8921 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8922 xmlXPathObjectPtr cur;
8923
8924 if (nargs == 0) {
8925 if ((ctxt == NULL) || (ctxt->context == NULL))
8926 return;
8927 if (ctxt->context->node == NULL) {
8928 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8929 } else {
8930 xmlChar *content;
8931
8932 content = xmlXPathCastNodeToString(ctxt->context->node);
8933 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8934 xmlUTF8Strlen(content)));
8935 xmlFree(content);
8936 }
8937 return;
8938 }
8939 CHECK_ARITY(1);
8940 CAST_TO_STRING;
8941 CHECK_TYPE(XPATH_STRING);
8942 cur = valuePop(ctxt);
8943 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8944 xmlUTF8Strlen(cur->stringval)));
8945 xmlXPathReleaseObject(ctxt->context, cur);
8946 }
8947
8948 /**
8949 * xmlXPathConcatFunction:
8950 * @ctxt: the XPath Parser context
8951 * @nargs: the number of arguments
8952 *
8953 * Implement the concat() XPath function
8954 * string concat(string, string, string*)
8955 * The concat function returns the concatenation of its arguments.
8956 */
8957 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8958 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8959 xmlXPathObjectPtr cur, newobj;
8960 xmlChar *tmp;
8961
8962 if (ctxt == NULL) return;
8963 if (nargs < 2) {
8964 CHECK_ARITY(2);
8965 }
8966
8967 CAST_TO_STRING;
8968 cur = valuePop(ctxt);
8969 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8970 xmlXPathReleaseObject(ctxt->context, cur);
8971 return;
8972 }
8973 nargs--;
8974
8975 while (nargs > 0) {
8976 CAST_TO_STRING;
8977 newobj = valuePop(ctxt);
8978 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8979 xmlXPathReleaseObject(ctxt->context, newobj);
8980 xmlXPathReleaseObject(ctxt->context, cur);
8981 XP_ERROR(XPATH_INVALID_TYPE);
8982 }
8983 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8984 newobj->stringval = cur->stringval;
8985 cur->stringval = tmp;
8986 xmlXPathReleaseObject(ctxt->context, newobj);
8987 nargs--;
8988 }
8989 valuePush(ctxt, cur);
8990 }
8991
8992 /**
8993 * xmlXPathContainsFunction:
8994 * @ctxt: the XPath Parser context
8995 * @nargs: the number of arguments
8996 *
8997 * Implement the contains() XPath function
8998 * boolean contains(string, string)
8999 * The contains function returns true if the first argument string
9000 * contains the second argument string, and otherwise returns false.
9001 */
9002 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9003 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9004 xmlXPathObjectPtr hay, needle;
9005
9006 CHECK_ARITY(2);
9007 CAST_TO_STRING;
9008 CHECK_TYPE(XPATH_STRING);
9009 needle = valuePop(ctxt);
9010 CAST_TO_STRING;
9011 hay = valuePop(ctxt);
9012
9013 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9014 xmlXPathReleaseObject(ctxt->context, hay);
9015 xmlXPathReleaseObject(ctxt->context, needle);
9016 XP_ERROR(XPATH_INVALID_TYPE);
9017 }
9018 if (xmlStrstr(hay->stringval, needle->stringval))
9019 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9020 else
9021 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9022 xmlXPathReleaseObject(ctxt->context, hay);
9023 xmlXPathReleaseObject(ctxt->context, needle);
9024 }
9025
9026 /**
9027 * xmlXPathStartsWithFunction:
9028 * @ctxt: the XPath Parser context
9029 * @nargs: the number of arguments
9030 *
9031 * Implement the starts-with() XPath function
9032 * boolean starts-with(string, string)
9033 * The starts-with function returns true if the first argument string
9034 * starts with the second argument string, and otherwise returns false.
9035 */
9036 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9037 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038 xmlXPathObjectPtr hay, needle;
9039 int n;
9040
9041 CHECK_ARITY(2);
9042 CAST_TO_STRING;
9043 CHECK_TYPE(XPATH_STRING);
9044 needle = valuePop(ctxt);
9045 CAST_TO_STRING;
9046 hay = valuePop(ctxt);
9047
9048 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9049 xmlXPathReleaseObject(ctxt->context, hay);
9050 xmlXPathReleaseObject(ctxt->context, needle);
9051 XP_ERROR(XPATH_INVALID_TYPE);
9052 }
9053 n = xmlStrlen(needle->stringval);
9054 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9055 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9056 else
9057 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9058 xmlXPathReleaseObject(ctxt->context, hay);
9059 xmlXPathReleaseObject(ctxt->context, needle);
9060 }
9061
9062 /**
9063 * xmlXPathSubstringFunction:
9064 * @ctxt: the XPath Parser context
9065 * @nargs: the number of arguments
9066 *
9067 * Implement the substring() XPath function
9068 * string substring(string, number, number?)
9069 * The substring function returns the substring of the first argument
9070 * starting at the position specified in the second argument with
9071 * length specified in the third argument. For example,
9072 * substring("12345",2,3) returns "234". If the third argument is not
9073 * specified, it returns the substring starting at the position specified
9074 * in the second argument and continuing to the end of the string. For
9075 * example, substring("12345",2) returns "2345". More precisely, each
9076 * character in the string (see [3.6 Strings]) is considered to have a
9077 * numeric position: the position of the first character is 1, the position
9078 * of the second character is 2 and so on. The returned substring contains
9079 * those characters for which the position of the character is greater than
9080 * or equal to the second argument and, if the third argument is specified,
9081 * less than the sum of the second and third arguments; the comparisons
9082 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9083 * - substring("12345", 1.5, 2.6) returns "234"
9084 * - substring("12345", 0, 3) returns "12"
9085 * - substring("12345", 0 div 0, 3) returns ""
9086 * - substring("12345", 1, 0 div 0) returns ""
9087 * - substring("12345", -42, 1 div 0) returns "12345"
9088 * - substring("12345", -1 div 0, 1 div 0) returns ""
9089 */
9090 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9091 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9092 xmlXPathObjectPtr str, start, len;
9093 double le=0, in;
9094 int i = 1, j = INT_MAX;
9095
9096 if (nargs < 2) {
9097 CHECK_ARITY(2);
9098 }
9099 if (nargs > 3) {
9100 CHECK_ARITY(3);
9101 }
9102 /*
9103 * take care of possible last (position) argument
9104 */
9105 if (nargs == 3) {
9106 CAST_TO_NUMBER;
9107 CHECK_TYPE(XPATH_NUMBER);
9108 len = valuePop(ctxt);
9109 le = len->floatval;
9110 xmlXPathReleaseObject(ctxt->context, len);
9111 }
9112
9113 CAST_TO_NUMBER;
9114 CHECK_TYPE(XPATH_NUMBER);
9115 start = valuePop(ctxt);
9116 in = start->floatval;
9117 xmlXPathReleaseObject(ctxt->context, start);
9118 CAST_TO_STRING;
9119 CHECK_TYPE(XPATH_STRING);
9120 str = valuePop(ctxt);
9121
9122 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9123 i = INT_MAX;
9124 } else if (in >= 1.0) {
9125 i = (int)in;
9126 if (in - floor(in) >= 0.5)
9127 i += 1;
9128 }
9129
9130 if (nargs == 3) {
9131 double rin, rle, end;
9132
9133 rin = floor(in);
9134 if (in - rin >= 0.5)
9135 rin += 1.0;
9136
9137 rle = floor(le);
9138 if (le - rle >= 0.5)
9139 rle += 1.0;
9140
9141 end = rin + rle;
9142 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9143 j = 1;
9144 } else if (end < INT_MAX) {
9145 j = (int)end;
9146 }
9147 }
9148
9149 if (i < j) {
9150 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9151 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9152 xmlFree(ret);
9153 } else {
9154 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9155 }
9156
9157 xmlXPathReleaseObject(ctxt->context, str);
9158 }
9159
9160 /**
9161 * xmlXPathSubstringBeforeFunction:
9162 * @ctxt: the XPath Parser context
9163 * @nargs: the number of arguments
9164 *
9165 * Implement the substring-before() XPath function
9166 * string substring-before(string, string)
9167 * The substring-before function returns the substring of the first
9168 * argument string that precedes the first occurrence of the second
9169 * argument string in the first argument string, or the empty string
9170 * if the first argument string does not contain the second argument
9171 * string. For example, substring-before("1999/04/01","/") returns 1999.
9172 */
9173 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9174 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9175 xmlXPathObjectPtr str;
9176 xmlXPathObjectPtr find;
9177 xmlBufPtr target;
9178 const xmlChar *point;
9179 int offset;
9180
9181 CHECK_ARITY(2);
9182 CAST_TO_STRING;
9183 find = valuePop(ctxt);
9184 CAST_TO_STRING;
9185 str = valuePop(ctxt);
9186
9187 target = xmlBufCreate();
9188 if (target) {
9189 point = xmlStrstr(str->stringval, find->stringval);
9190 if (point) {
9191 offset = (int)(point - str->stringval);
9192 xmlBufAdd(target, str->stringval, offset);
9193 }
9194 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9195 xmlBufContent(target)));
9196 xmlBufFree(target);
9197 }
9198 xmlXPathReleaseObject(ctxt->context, str);
9199 xmlXPathReleaseObject(ctxt->context, find);
9200 }
9201
9202 /**
9203 * xmlXPathSubstringAfterFunction:
9204 * @ctxt: the XPath Parser context
9205 * @nargs: the number of arguments
9206 *
9207 * Implement the substring-after() XPath function
9208 * string substring-after(string, string)
9209 * The substring-after function returns the substring of the first
9210 * argument string that follows the first occurrence of the second
9211 * argument string in the first argument string, or the empty stringi
9212 * if the first argument string does not contain the second argument
9213 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9214 * and substring-after("1999/04/01","19") returns 99/04/01.
9215 */
9216 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9217 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9218 xmlXPathObjectPtr str;
9219 xmlXPathObjectPtr find;
9220 xmlBufPtr target;
9221 const xmlChar *point;
9222 int offset;
9223
9224 CHECK_ARITY(2);
9225 CAST_TO_STRING;
9226 find = valuePop(ctxt);
9227 CAST_TO_STRING;
9228 str = valuePop(ctxt);
9229
9230 target = xmlBufCreate();
9231 if (target) {
9232 point = xmlStrstr(str->stringval, find->stringval);
9233 if (point) {
9234 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9235 xmlBufAdd(target, &str->stringval[offset],
9236 xmlStrlen(str->stringval) - offset);
9237 }
9238 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9239 xmlBufContent(target)));
9240 xmlBufFree(target);
9241 }
9242 xmlXPathReleaseObject(ctxt->context, str);
9243 xmlXPathReleaseObject(ctxt->context, find);
9244 }
9245
9246 /**
9247 * xmlXPathNormalizeFunction:
9248 * @ctxt: the XPath Parser context
9249 * @nargs: the number of arguments
9250 *
9251 * Implement the normalize-space() XPath function
9252 * string normalize-space(string?)
9253 * The normalize-space function returns the argument string with white
9254 * space normalized by stripping leading and trailing whitespace
9255 * and replacing sequences of whitespace characters by a single
9256 * space. Whitespace characters are the same allowed by the S production
9257 * in XML. If the argument is omitted, it defaults to the context
9258 * node converted to a string, in other words the value of the context node.
9259 */
9260 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9261 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9262 xmlXPathObjectPtr obj = NULL;
9263 xmlChar *source = NULL;
9264 xmlBufPtr target;
9265 xmlChar blank;
9266
9267 if (ctxt == NULL) return;
9268 if (nargs == 0) {
9269 /* Use current context node */
9270 valuePush(ctxt,
9271 xmlXPathCacheWrapString(ctxt->context,
9272 xmlXPathCastNodeToString(ctxt->context->node)));
9273 nargs = 1;
9274 }
9275
9276 CHECK_ARITY(1);
9277 CAST_TO_STRING;
9278 CHECK_TYPE(XPATH_STRING);
9279 obj = valuePop(ctxt);
9280 source = obj->stringval;
9281
9282 target = xmlBufCreate();
9283 if (target && source) {
9284
9285 /* Skip leading whitespaces */
9286 while (IS_BLANK_CH(*source))
9287 source++;
9288
9289 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9290 blank = 0;
9291 while (*source) {
9292 if (IS_BLANK_CH(*source)) {
9293 blank = 0x20;
9294 } else {
9295 if (blank) {
9296 xmlBufAdd(target, &blank, 1);
9297 blank = 0;
9298 }
9299 xmlBufAdd(target, source, 1);
9300 }
9301 source++;
9302 }
9303 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9304 xmlBufContent(target)));
9305 xmlBufFree(target);
9306 }
9307 xmlXPathReleaseObject(ctxt->context, obj);
9308 }
9309
9310 /**
9311 * xmlXPathTranslateFunction:
9312 * @ctxt: the XPath Parser context
9313 * @nargs: the number of arguments
9314 *
9315 * Implement the translate() XPath function
9316 * string translate(string, string, string)
9317 * The translate function returns the first argument string with
9318 * occurrences of characters in the second argument string replaced
9319 * by the character at the corresponding position in the third argument
9320 * string. For example, translate("bar","abc","ABC") returns the string
9321 * BAr. If there is a character in the second argument string with no
9322 * character at a corresponding position in the third argument string
9323 * (because the second argument string is longer than the third argument
9324 * string), then occurrences of that character in the first argument
9325 * string are removed. For example, translate("--aaa--","abc-","ABC")
9326 * returns "AAA". If a character occurs more than once in second
9327 * argument string, then the first occurrence determines the replacement
9328 * character. If the third argument string is longer than the second
9329 * argument string, then excess characters are ignored.
9330 */
9331 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9332 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9333 xmlXPathObjectPtr str;
9334 xmlXPathObjectPtr from;
9335 xmlXPathObjectPtr to;
9336 xmlBufPtr target;
9337 int offset, max;
9338 xmlChar ch;
9339 const xmlChar *point;
9340 xmlChar *cptr;
9341
9342 CHECK_ARITY(3);
9343
9344 CAST_TO_STRING;
9345 to = valuePop(ctxt);
9346 CAST_TO_STRING;
9347 from = valuePop(ctxt);
9348 CAST_TO_STRING;
9349 str = valuePop(ctxt);
9350
9351 target = xmlBufCreate();
9352 if (target) {
9353 max = xmlUTF8Strlen(to->stringval);
9354 for (cptr = str->stringval; (ch=*cptr); ) {
9355 offset = xmlUTF8Strloc(from->stringval, cptr);
9356 if (offset >= 0) {
9357 if (offset < max) {
9358 point = xmlUTF8Strpos(to->stringval, offset);
9359 if (point)
9360 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9361 }
9362 } else
9363 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9364
9365 /* Step to next character in input */
9366 cptr++;
9367 if ( ch & 0x80 ) {
9368 /* if not simple ascii, verify proper format */
9369 if ( (ch & 0xc0) != 0xc0 ) {
9370 xmlGenericError(xmlGenericErrorContext,
9371 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9372 /* not asserting an XPath error is probably better */
9373 break;
9374 }
9375 /* then skip over remaining bytes for this char */
9376 while ( (ch <<= 1) & 0x80 )
9377 if ( (*cptr++ & 0xc0) != 0x80 ) {
9378 xmlGenericError(xmlGenericErrorContext,
9379 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9380 /* not asserting an XPath error is probably better */
9381 break;
9382 }
9383 if (ch & 0x80) /* must have had error encountered */
9384 break;
9385 }
9386 }
9387 }
9388 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9389 xmlBufContent(target)));
9390 xmlBufFree(target);
9391 xmlXPathReleaseObject(ctxt->context, str);
9392 xmlXPathReleaseObject(ctxt->context, from);
9393 xmlXPathReleaseObject(ctxt->context, to);
9394 }
9395
9396 /**
9397 * xmlXPathBooleanFunction:
9398 * @ctxt: the XPath Parser context
9399 * @nargs: the number of arguments
9400 *
9401 * Implement the boolean() XPath function
9402 * boolean boolean(object)
9403 * The boolean function converts its argument to a boolean as follows:
9404 * - a number is true if and only if it is neither positive or
9405 * negative zero nor NaN
9406 * - a node-set is true if and only if it is non-empty
9407 * - a string is true if and only if its length is non-zero
9408 */
9409 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9410 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9411 xmlXPathObjectPtr cur;
9412
9413 CHECK_ARITY(1);
9414 cur = valuePop(ctxt);
9415 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9416 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9417 valuePush(ctxt, cur);
9418 }
9419
9420 /**
9421 * xmlXPathNotFunction:
9422 * @ctxt: the XPath Parser context
9423 * @nargs: the number of arguments
9424 *
9425 * Implement the not() XPath function
9426 * boolean not(boolean)
9427 * The not function returns true if its argument is false,
9428 * and false otherwise.
9429 */
9430 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9431 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9432 CHECK_ARITY(1);
9433 CAST_TO_BOOLEAN;
9434 CHECK_TYPE(XPATH_BOOLEAN);
9435 ctxt->value->boolval = ! ctxt->value->boolval;
9436 }
9437
9438 /**
9439 * xmlXPathTrueFunction:
9440 * @ctxt: the XPath Parser context
9441 * @nargs: the number of arguments
9442 *
9443 * Implement the true() XPath function
9444 * boolean true()
9445 */
9446 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9447 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9448 CHECK_ARITY(0);
9449 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9450 }
9451
9452 /**
9453 * xmlXPathFalseFunction:
9454 * @ctxt: the XPath Parser context
9455 * @nargs: the number of arguments
9456 *
9457 * Implement the false() XPath function
9458 * boolean false()
9459 */
9460 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9461 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9462 CHECK_ARITY(0);
9463 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9464 }
9465
9466 /**
9467 * xmlXPathLangFunction:
9468 * @ctxt: the XPath Parser context
9469 * @nargs: the number of arguments
9470 *
9471 * Implement the lang() XPath function
9472 * boolean lang(string)
9473 * The lang function returns true or false depending on whether the
9474 * language of the context node as specified by xml:lang attributes
9475 * is the same as or is a sublanguage of the language specified by
9476 * the argument string. The language of the context node is determined
9477 * by the value of the xml:lang attribute on the context node, or, if
9478 * the context node has no xml:lang attribute, by the value of the
9479 * xml:lang attribute on the nearest ancestor of the context node that
9480 * has an xml:lang attribute. If there is no such attribute, then lang
9481 * returns false. If there is such an attribute, then lang returns
9482 * true if the attribute value is equal to the argument ignoring case,
9483 * or if there is some suffix starting with - such that the attribute
9484 * value is equal to the argument ignoring that suffix of the attribute
9485 * value and ignoring case.
9486 */
9487 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9488 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9489 xmlXPathObjectPtr val = NULL;
9490 const xmlChar *theLang = NULL;
9491 const xmlChar *lang;
9492 int ret = 0;
9493 int i;
9494
9495 CHECK_ARITY(1);
9496 CAST_TO_STRING;
9497 CHECK_TYPE(XPATH_STRING);
9498 val = valuePop(ctxt);
9499 lang = val->stringval;
9500 theLang = xmlNodeGetLang(ctxt->context->node);
9501 if ((theLang != NULL) && (lang != NULL)) {
9502 for (i = 0;lang[i] != 0;i++)
9503 if (toupper(lang[i]) != toupper(theLang[i]))
9504 goto not_equal;
9505 if ((theLang[i] == 0) || (theLang[i] == '-'))
9506 ret = 1;
9507 }
9508 not_equal:
9509 if (theLang != NULL)
9510 xmlFree((void *)theLang);
9511
9512 xmlXPathReleaseObject(ctxt->context, val);
9513 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9514 }
9515
9516 /**
9517 * xmlXPathNumberFunction:
9518 * @ctxt: the XPath Parser context
9519 * @nargs: the number of arguments
9520 *
9521 * Implement the number() XPath function
9522 * number number(object?)
9523 */
9524 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9525 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9526 xmlXPathObjectPtr cur;
9527 double res;
9528
9529 if (ctxt == NULL) return;
9530 if (nargs == 0) {
9531 if (ctxt->context->node == NULL) {
9532 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9533 } else {
9534 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9535
9536 res = xmlXPathStringEvalNumber(content);
9537 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9538 xmlFree(content);
9539 }
9540 return;
9541 }
9542
9543 CHECK_ARITY(1);
9544 cur = valuePop(ctxt);
9545 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9546 }
9547
9548 /**
9549 * xmlXPathSumFunction:
9550 * @ctxt: the XPath Parser context
9551 * @nargs: the number of arguments
9552 *
9553 * Implement the sum() XPath function
9554 * number sum(node-set)
9555 * The sum function returns the sum of the values of the nodes in
9556 * the argument node-set.
9557 */
9558 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9559 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9560 xmlXPathObjectPtr cur;
9561 int i;
9562 double res = 0.0;
9563
9564 CHECK_ARITY(1);
9565 if ((ctxt->value == NULL) ||
9566 ((ctxt->value->type != XPATH_NODESET) &&
9567 (ctxt->value->type != XPATH_XSLT_TREE)))
9568 XP_ERROR(XPATH_INVALID_TYPE);
9569 cur = valuePop(ctxt);
9570
9571 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9572 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9573 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9574 }
9575 }
9576 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9577 xmlXPathReleaseObject(ctxt->context, cur);
9578 }
9579
9580 /**
9581 * xmlXPathFloorFunction:
9582 * @ctxt: the XPath Parser context
9583 * @nargs: the number of arguments
9584 *
9585 * Implement the floor() XPath function
9586 * number floor(number)
9587 * The floor function returns the largest (closest to positive infinity)
9588 * number that is not greater than the argument and that is an integer.
9589 */
9590 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9591 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9592 CHECK_ARITY(1);
9593 CAST_TO_NUMBER;
9594 CHECK_TYPE(XPATH_NUMBER);
9595
9596 ctxt->value->floatval = floor(ctxt->value->floatval);
9597 }
9598
9599 /**
9600 * xmlXPathCeilingFunction:
9601 * @ctxt: the XPath Parser context
9602 * @nargs: the number of arguments
9603 *
9604 * Implement the ceiling() XPath function
9605 * number ceiling(number)
9606 * The ceiling function returns the smallest (closest to negative infinity)
9607 * number that is not less than the argument and that is an integer.
9608 */
9609 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9610 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9611 CHECK_ARITY(1);
9612 CAST_TO_NUMBER;
9613 CHECK_TYPE(XPATH_NUMBER);
9614
9615 #ifdef _AIX
9616 /* Work around buggy ceil() function on AIX */
9617 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9618 #else
9619 ctxt->value->floatval = ceil(ctxt->value->floatval);
9620 #endif
9621 }
9622
9623 /**
9624 * xmlXPathRoundFunction:
9625 * @ctxt: the XPath Parser context
9626 * @nargs: the number of arguments
9627 *
9628 * Implement the round() XPath function
9629 * number round(number)
9630 * The round function returns the number that is closest to the
9631 * argument and that is an integer. If there are two such numbers,
9632 * then the one that is closest to positive infinity is returned.
9633 */
9634 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9635 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9636 double f;
9637
9638 CHECK_ARITY(1);
9639 CAST_TO_NUMBER;
9640 CHECK_TYPE(XPATH_NUMBER);
9641
9642 f = ctxt->value->floatval;
9643
9644 if ((f >= -0.5) && (f < 0.5)) {
9645 /* Handles negative zero. */
9646 ctxt->value->floatval *= 0.0;
9647 }
9648 else {
9649 double rounded = floor(f);
9650 if (f - rounded >= 0.5)
9651 rounded += 1.0;
9652 ctxt->value->floatval = rounded;
9653 }
9654 }
9655
9656 /************************************************************************
9657 * *
9658 * The Parser *
9659 * *
9660 ************************************************************************/
9661
9662 /*
9663 * a few forward declarations since we use a recursive call based
9664 * implementation.
9665 */
9666 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9667 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9668 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9669 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9670 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9671 int qualified);
9672
9673 /**
9674 * xmlXPathCurrentChar:
9675 * @ctxt: the XPath parser context
9676 * @cur: pointer to the beginning of the char
9677 * @len: pointer to the length of the char read
9678 *
9679 * The current char value, if using UTF-8 this may actually span multiple
9680 * bytes in the input buffer.
9681 *
9682 * Returns the current char value and its length
9683 */
9684
9685 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9686 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9687 unsigned char c;
9688 unsigned int val;
9689 const xmlChar *cur;
9690
9691 if (ctxt == NULL)
9692 return(0);
9693 cur = ctxt->cur;
9694
9695 /*
9696 * We are supposed to handle UTF8, check it's valid
9697 * From rfc2044: encoding of the Unicode values on UTF-8:
9698 *
9699 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9700 * 0000 0000-0000 007F 0xxxxxxx
9701 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9702 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9703 *
9704 * Check for the 0x110000 limit too
9705 */
9706 c = *cur;
9707 if (c & 0x80) {
9708 if ((cur[1] & 0xc0) != 0x80)
9709 goto encoding_error;
9710 if ((c & 0xe0) == 0xe0) {
9711
9712 if ((cur[2] & 0xc0) != 0x80)
9713 goto encoding_error;
9714 if ((c & 0xf0) == 0xf0) {
9715 if (((c & 0xf8) != 0xf0) ||
9716 ((cur[3] & 0xc0) != 0x80))
9717 goto encoding_error;
9718 /* 4-byte code */
9719 *len = 4;
9720 val = (cur[0] & 0x7) << 18;
9721 val |= (cur[1] & 0x3f) << 12;
9722 val |= (cur[2] & 0x3f) << 6;
9723 val |= cur[3] & 0x3f;
9724 } else {
9725 /* 3-byte code */
9726 *len = 3;
9727 val = (cur[0] & 0xf) << 12;
9728 val |= (cur[1] & 0x3f) << 6;
9729 val |= cur[2] & 0x3f;
9730 }
9731 } else {
9732 /* 2-byte code */
9733 *len = 2;
9734 val = (cur[0] & 0x1f) << 6;
9735 val |= cur[1] & 0x3f;
9736 }
9737 if (!IS_CHAR(val)) {
9738 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9739 }
9740 return(val);
9741 } else {
9742 /* 1-byte code */
9743 *len = 1;
9744 return((int) *cur);
9745 }
9746 encoding_error:
9747 /*
9748 * If we detect an UTF8 error that probably means that the
9749 * input encoding didn't get properly advertised in the
9750 * declaration header. Report the error and switch the encoding
9751 * to ISO-Latin-1 (if you don't like this policy, just declare the
9752 * encoding !)
9753 */
9754 *len = 0;
9755 XP_ERROR0(XPATH_ENCODING_ERROR);
9756 }
9757
9758 /**
9759 * xmlXPathParseNCName:
9760 * @ctxt: the XPath Parser context
9761 *
9762 * parse an XML namespace non qualified name.
9763 *
9764 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9765 *
9766 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9767 * CombiningChar | Extender
9768 *
9769 * Returns the namespace name or NULL
9770 */
9771
9772 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9773 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9774 const xmlChar *in;
9775 xmlChar *ret;
9776 int count = 0;
9777
9778 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9779 /*
9780 * Accelerator for simple ASCII names
9781 */
9782 in = ctxt->cur;
9783 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9784 ((*in >= 0x41) && (*in <= 0x5A)) ||
9785 (*in == '_')) {
9786 in++;
9787 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9788 ((*in >= 0x41) && (*in <= 0x5A)) ||
9789 ((*in >= 0x30) && (*in <= 0x39)) ||
9790 (*in == '_') || (*in == '.') ||
9791 (*in == '-'))
9792 in++;
9793 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9794 (*in == '[') || (*in == ']') || (*in == ':') ||
9795 (*in == '@') || (*in == '*')) {
9796 count = in - ctxt->cur;
9797 if (count == 0)
9798 return(NULL);
9799 ret = xmlStrndup(ctxt->cur, count);
9800 ctxt->cur = in;
9801 return(ret);
9802 }
9803 }
9804 return(xmlXPathParseNameComplex(ctxt, 0));
9805 }
9806
9807
9808 /**
9809 * xmlXPathParseQName:
9810 * @ctxt: the XPath Parser context
9811 * @prefix: a xmlChar **
9812 *
9813 * parse an XML qualified name
9814 *
9815 * [NS 5] QName ::= (Prefix ':')? LocalPart
9816 *
9817 * [NS 6] Prefix ::= NCName
9818 *
9819 * [NS 7] LocalPart ::= NCName
9820 *
9821 * Returns the function returns the local part, and prefix is updated
9822 * to get the Prefix if any.
9823 */
9824
9825 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9826 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9827 xmlChar *ret = NULL;
9828
9829 *prefix = NULL;
9830 ret = xmlXPathParseNCName(ctxt);
9831 if (ret && CUR == ':') {
9832 *prefix = ret;
9833 NEXT;
9834 ret = xmlXPathParseNCName(ctxt);
9835 }
9836 return(ret);
9837 }
9838
9839 /**
9840 * xmlXPathParseName:
9841 * @ctxt: the XPath Parser context
9842 *
9843 * parse an XML name
9844 *
9845 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9846 * CombiningChar | Extender
9847 *
9848 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9849 *
9850 * Returns the namespace name or NULL
9851 */
9852
9853 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9854 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9855 const xmlChar *in;
9856 xmlChar *ret;
9857 size_t count = 0;
9858
9859 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9860 /*
9861 * Accelerator for simple ASCII names
9862 */
9863 in = ctxt->cur;
9864 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9865 ((*in >= 0x41) && (*in <= 0x5A)) ||
9866 (*in == '_') || (*in == ':')) {
9867 in++;
9868 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9869 ((*in >= 0x41) && (*in <= 0x5A)) ||
9870 ((*in >= 0x30) && (*in <= 0x39)) ||
9871 (*in == '_') || (*in == '-') ||
9872 (*in == ':') || (*in == '.'))
9873 in++;
9874 if ((*in > 0) && (*in < 0x80)) {
9875 count = in - ctxt->cur;
9876 if (count > XML_MAX_NAME_LENGTH) {
9877 ctxt->cur = in;
9878 XP_ERRORNULL(XPATH_EXPR_ERROR);
9879 }
9880 ret = xmlStrndup(ctxt->cur, count);
9881 ctxt->cur = in;
9882 return(ret);
9883 }
9884 }
9885 return(xmlXPathParseNameComplex(ctxt, 1));
9886 }
9887
9888 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9889 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9890 xmlChar buf[XML_MAX_NAMELEN + 5];
9891 int len = 0, l;
9892 int c;
9893
9894 /*
9895 * Handler for more complex cases
9896 */
9897 c = CUR_CHAR(l);
9898 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9899 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9900 (c == '*') || /* accelerators */
9901 (!IS_LETTER(c) && (c != '_') &&
9902 ((!qualified) || (c != ':')))) {
9903 return(NULL);
9904 }
9905
9906 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9907 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9908 (c == '.') || (c == '-') ||
9909 (c == '_') || ((qualified) && (c == ':')) ||
9910 (IS_COMBINING(c)) ||
9911 (IS_EXTENDER(c)))) {
9912 COPY_BUF(l,buf,len,c);
9913 NEXTL(l);
9914 c = CUR_CHAR(l);
9915 if (len >= XML_MAX_NAMELEN) {
9916 /*
9917 * Okay someone managed to make a huge name, so he's ready to pay
9918 * for the processing speed.
9919 */
9920 xmlChar *buffer;
9921 int max = len * 2;
9922
9923 if (len > XML_MAX_NAME_LENGTH) {
9924 XP_ERRORNULL(XPATH_EXPR_ERROR);
9925 }
9926 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9927 if (buffer == NULL) {
9928 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9929 }
9930 memcpy(buffer, buf, len);
9931 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9932 (c == '.') || (c == '-') ||
9933 (c == '_') || ((qualified) && (c == ':')) ||
9934 (IS_COMBINING(c)) ||
9935 (IS_EXTENDER(c))) {
9936 if (len + 10 > max) {
9937 xmlChar *tmp;
9938 if (max > XML_MAX_NAME_LENGTH) {
9939 xmlFree(buffer);
9940 XP_ERRORNULL(XPATH_EXPR_ERROR);
9941 }
9942 max *= 2;
9943 tmp = (xmlChar *) xmlRealloc(buffer,
9944 max * sizeof(xmlChar));
9945 if (tmp == NULL) {
9946 xmlFree(buffer);
9947 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9948 }
9949 buffer = tmp;
9950 }
9951 COPY_BUF(l,buffer,len,c);
9952 NEXTL(l);
9953 c = CUR_CHAR(l);
9954 }
9955 buffer[len] = 0;
9956 return(buffer);
9957 }
9958 }
9959 if (len == 0)
9960 return(NULL);
9961 return(xmlStrndup(buf, len));
9962 }
9963
9964 #define MAX_FRAC 20
9965
9966 /**
9967 * xmlXPathStringEvalNumber:
9968 * @str: A string to scan
9969 *
9970 * [30a] Float ::= Number ('e' Digits?)?
9971 *
9972 * [30] Number ::= Digits ('.' Digits?)?
9973 * | '.' Digits
9974 * [31] Digits ::= [0-9]+
9975 *
9976 * Compile a Number in the string
9977 * In complement of the Number expression, this function also handles
9978 * negative values : '-' Number.
9979 *
9980 * Returns the double value.
9981 */
9982 double
xmlXPathStringEvalNumber(const xmlChar * str)9983 xmlXPathStringEvalNumber(const xmlChar *str) {
9984 const xmlChar *cur = str;
9985 double ret;
9986 int ok = 0;
9987 int isneg = 0;
9988 int exponent = 0;
9989 int is_exponent_negative = 0;
9990 #ifdef __GNUC__
9991 unsigned long tmp = 0;
9992 double temp;
9993 #endif
9994 if (cur == NULL) return(0);
9995 while (IS_BLANK_CH(*cur)) cur++;
9996 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9997 return(NAN);
9998 }
9999 if (*cur == '-') {
10000 isneg = 1;
10001 cur++;
10002 }
10003
10004 #ifdef __GNUC__
10005 /*
10006 * tmp/temp is a workaround against a gcc compiler bug
10007 * http://veillard.com/gcc.bug
10008 */
10009 ret = 0;
10010 while ((*cur >= '0') && (*cur <= '9')) {
10011 ret = ret * 10;
10012 tmp = (*cur - '0');
10013 ok = 1;
10014 cur++;
10015 temp = (double) tmp;
10016 ret = ret + temp;
10017 }
10018 #else
10019 ret = 0;
10020 while ((*cur >= '0') && (*cur <= '9')) {
10021 ret = ret * 10 + (*cur - '0');
10022 ok = 1;
10023 cur++;
10024 }
10025 #endif
10026
10027 if (*cur == '.') {
10028 int v, frac = 0, max;
10029 double fraction = 0;
10030
10031 cur++;
10032 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10033 return(NAN);
10034 }
10035 while (*cur == '0') {
10036 frac = frac + 1;
10037 cur++;
10038 }
10039 max = frac + MAX_FRAC;
10040 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10041 v = (*cur - '0');
10042 fraction = fraction * 10 + v;
10043 frac = frac + 1;
10044 cur++;
10045 }
10046 fraction /= pow(10.0, frac);
10047 ret = ret + fraction;
10048 while ((*cur >= '0') && (*cur <= '9'))
10049 cur++;
10050 }
10051 if ((*cur == 'e') || (*cur == 'E')) {
10052 cur++;
10053 if (*cur == '-') {
10054 is_exponent_negative = 1;
10055 cur++;
10056 } else if (*cur == '+') {
10057 cur++;
10058 }
10059 while ((*cur >= '0') && (*cur <= '9')) {
10060 if (exponent < 1000000)
10061 exponent = exponent * 10 + (*cur - '0');
10062 cur++;
10063 }
10064 }
10065 while (IS_BLANK_CH(*cur)) cur++;
10066 if (*cur != 0) return(NAN);
10067 if (isneg) ret = -ret;
10068 if (is_exponent_negative) exponent = -exponent;
10069 ret *= pow(10.0, (double)exponent);
10070 return(ret);
10071 }
10072
10073 /**
10074 * xmlXPathCompNumber:
10075 * @ctxt: the XPath Parser context
10076 *
10077 * [30] Number ::= Digits ('.' Digits?)?
10078 * | '.' Digits
10079 * [31] Digits ::= [0-9]+
10080 *
10081 * Compile a Number, then push it on the stack
10082 *
10083 */
10084 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10085 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10086 {
10087 double ret = 0.0;
10088 int ok = 0;
10089 int exponent = 0;
10090 int is_exponent_negative = 0;
10091 #ifdef __GNUC__
10092 unsigned long tmp = 0;
10093 double temp;
10094 #endif
10095
10096 CHECK_ERROR;
10097 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10098 XP_ERROR(XPATH_NUMBER_ERROR);
10099 }
10100 #ifdef __GNUC__
10101 /*
10102 * tmp/temp is a workaround against a gcc compiler bug
10103 * http://veillard.com/gcc.bug
10104 */
10105 ret = 0;
10106 while ((CUR >= '0') && (CUR <= '9')) {
10107 ret = ret * 10;
10108 tmp = (CUR - '0');
10109 ok = 1;
10110 NEXT;
10111 temp = (double) tmp;
10112 ret = ret + temp;
10113 }
10114 #else
10115 ret = 0;
10116 while ((CUR >= '0') && (CUR <= '9')) {
10117 ret = ret * 10 + (CUR - '0');
10118 ok = 1;
10119 NEXT;
10120 }
10121 #endif
10122 if (CUR == '.') {
10123 int v, frac = 0, max;
10124 double fraction = 0;
10125
10126 NEXT;
10127 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10128 XP_ERROR(XPATH_NUMBER_ERROR);
10129 }
10130 while (CUR == '0') {
10131 frac = frac + 1;
10132 NEXT;
10133 }
10134 max = frac + MAX_FRAC;
10135 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10136 v = (CUR - '0');
10137 fraction = fraction * 10 + v;
10138 frac = frac + 1;
10139 NEXT;
10140 }
10141 fraction /= pow(10.0, frac);
10142 ret = ret + fraction;
10143 while ((CUR >= '0') && (CUR <= '9'))
10144 NEXT;
10145 }
10146 if ((CUR == 'e') || (CUR == 'E')) {
10147 NEXT;
10148 if (CUR == '-') {
10149 is_exponent_negative = 1;
10150 NEXT;
10151 } else if (CUR == '+') {
10152 NEXT;
10153 }
10154 while ((CUR >= '0') && (CUR <= '9')) {
10155 if (exponent < 1000000)
10156 exponent = exponent * 10 + (CUR - '0');
10157 NEXT;
10158 }
10159 if (is_exponent_negative)
10160 exponent = -exponent;
10161 ret *= pow(10.0, (double) exponent);
10162 }
10163 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10164 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10165 }
10166
10167 /**
10168 * xmlXPathParseLiteral:
10169 * @ctxt: the XPath Parser context
10170 *
10171 * Parse a Literal
10172 *
10173 * [29] Literal ::= '"' [^"]* '"'
10174 * | "'" [^']* "'"
10175 *
10176 * Returns the value found or NULL in case of error
10177 */
10178 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10179 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10180 const xmlChar *q;
10181 xmlChar *ret = NULL;
10182
10183 if (CUR == '"') {
10184 NEXT;
10185 q = CUR_PTR;
10186 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10187 NEXT;
10188 if (!IS_CHAR_CH(CUR)) {
10189 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10190 } else {
10191 ret = xmlStrndup(q, CUR_PTR - q);
10192 NEXT;
10193 }
10194 } else if (CUR == '\'') {
10195 NEXT;
10196 q = CUR_PTR;
10197 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10198 NEXT;
10199 if (!IS_CHAR_CH(CUR)) {
10200 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10201 } else {
10202 ret = xmlStrndup(q, CUR_PTR - q);
10203 NEXT;
10204 }
10205 } else {
10206 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10207 }
10208 return(ret);
10209 }
10210
10211 /**
10212 * xmlXPathCompLiteral:
10213 * @ctxt: the XPath Parser context
10214 *
10215 * Parse a Literal and push it on the stack.
10216 *
10217 * [29] Literal ::= '"' [^"]* '"'
10218 * | "'" [^']* "'"
10219 *
10220 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10221 */
10222 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10223 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10224 const xmlChar *q;
10225 xmlChar *ret = NULL;
10226
10227 if (CUR == '"') {
10228 NEXT;
10229 q = CUR_PTR;
10230 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10231 NEXT;
10232 if (!IS_CHAR_CH(CUR)) {
10233 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10234 } else {
10235 ret = xmlStrndup(q, CUR_PTR - q);
10236 NEXT;
10237 }
10238 } else if (CUR == '\'') {
10239 NEXT;
10240 q = CUR_PTR;
10241 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10242 NEXT;
10243 if (!IS_CHAR_CH(CUR)) {
10244 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10245 } else {
10246 ret = xmlStrndup(q, CUR_PTR - q);
10247 NEXT;
10248 }
10249 } else {
10250 XP_ERROR(XPATH_START_LITERAL_ERROR);
10251 }
10252 if (ret == NULL) return;
10253 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10254 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10255 xmlFree(ret);
10256 }
10257
10258 /**
10259 * xmlXPathCompVariableReference:
10260 * @ctxt: the XPath Parser context
10261 *
10262 * Parse a VariableReference, evaluate it and push it on the stack.
10263 *
10264 * The variable bindings consist of a mapping from variable names
10265 * to variable values. The value of a variable is an object, which can be
10266 * of any of the types that are possible for the value of an expression,
10267 * and may also be of additional types not specified here.
10268 *
10269 * Early evaluation is possible since:
10270 * The variable bindings [...] used to evaluate a subexpression are
10271 * always the same as those used to evaluate the containing expression.
10272 *
10273 * [36] VariableReference ::= '$' QName
10274 */
10275 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10276 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10277 xmlChar *name;
10278 xmlChar *prefix;
10279
10280 SKIP_BLANKS;
10281 if (CUR != '$') {
10282 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10283 }
10284 NEXT;
10285 name = xmlXPathParseQName(ctxt, &prefix);
10286 if (name == NULL) {
10287 xmlFree(prefix);
10288 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10289 }
10290 ctxt->comp->last = -1;
10291 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10292 name, prefix);
10293 SKIP_BLANKS;
10294 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10295 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10296 }
10297 }
10298
10299 /**
10300 * xmlXPathIsNodeType:
10301 * @name: a name string
10302 *
10303 * Is the name given a NodeType one.
10304 *
10305 * [38] NodeType ::= 'comment'
10306 * | 'text'
10307 * | 'processing-instruction'
10308 * | 'node'
10309 *
10310 * Returns 1 if true 0 otherwise
10311 */
10312 int
xmlXPathIsNodeType(const xmlChar * name)10313 xmlXPathIsNodeType(const xmlChar *name) {
10314 if (name == NULL)
10315 return(0);
10316
10317 if (xmlStrEqual(name, BAD_CAST "node"))
10318 return(1);
10319 if (xmlStrEqual(name, BAD_CAST "text"))
10320 return(1);
10321 if (xmlStrEqual(name, BAD_CAST "comment"))
10322 return(1);
10323 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10324 return(1);
10325 return(0);
10326 }
10327
10328 /**
10329 * xmlXPathCompFunctionCall:
10330 * @ctxt: the XPath Parser context
10331 *
10332 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10333 * [17] Argument ::= Expr
10334 *
10335 * Compile a function call, the evaluation of all arguments are
10336 * pushed on the stack
10337 */
10338 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10339 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10340 xmlChar *name;
10341 xmlChar *prefix;
10342 int nbargs = 0;
10343 int sort = 1;
10344
10345 name = xmlXPathParseQName(ctxt, &prefix);
10346 if (name == NULL) {
10347 xmlFree(prefix);
10348 XP_ERROR(XPATH_EXPR_ERROR);
10349 }
10350 SKIP_BLANKS;
10351 #ifdef DEBUG_EXPR
10352 if (prefix == NULL)
10353 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10354 name);
10355 else
10356 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10357 prefix, name);
10358 #endif
10359
10360 if (CUR != '(') {
10361 xmlFree(name);
10362 xmlFree(prefix);
10363 XP_ERROR(XPATH_EXPR_ERROR);
10364 }
10365 NEXT;
10366 SKIP_BLANKS;
10367
10368 /*
10369 * Optimization for count(): we don't need the node-set to be sorted.
10370 */
10371 if ((prefix == NULL) && (name[0] == 'c') &&
10372 xmlStrEqual(name, BAD_CAST "count"))
10373 {
10374 sort = 0;
10375 }
10376 ctxt->comp->last = -1;
10377 if (CUR != ')') {
10378 while (CUR != 0) {
10379 int op1 = ctxt->comp->last;
10380 ctxt->comp->last = -1;
10381 xmlXPathCompileExpr(ctxt, sort);
10382 if (ctxt->error != XPATH_EXPRESSION_OK) {
10383 xmlFree(name);
10384 xmlFree(prefix);
10385 return;
10386 }
10387 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10388 nbargs++;
10389 if (CUR == ')') break;
10390 if (CUR != ',') {
10391 xmlFree(name);
10392 xmlFree(prefix);
10393 XP_ERROR(XPATH_EXPR_ERROR);
10394 }
10395 NEXT;
10396 SKIP_BLANKS;
10397 }
10398 }
10399 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10400 name, prefix);
10401 NEXT;
10402 SKIP_BLANKS;
10403 }
10404
10405 /**
10406 * xmlXPathCompPrimaryExpr:
10407 * @ctxt: the XPath Parser context
10408 *
10409 * [15] PrimaryExpr ::= VariableReference
10410 * | '(' Expr ')'
10411 * | Literal
10412 * | Number
10413 * | FunctionCall
10414 *
10415 * Compile a primary expression.
10416 */
10417 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10418 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10419 SKIP_BLANKS;
10420 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10421 else if (CUR == '(') {
10422 NEXT;
10423 SKIP_BLANKS;
10424 xmlXPathCompileExpr(ctxt, 1);
10425 CHECK_ERROR;
10426 if (CUR != ')') {
10427 XP_ERROR(XPATH_EXPR_ERROR);
10428 }
10429 NEXT;
10430 SKIP_BLANKS;
10431 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10432 xmlXPathCompNumber(ctxt);
10433 } else if ((CUR == '\'') || (CUR == '"')) {
10434 xmlXPathCompLiteral(ctxt);
10435 } else {
10436 xmlXPathCompFunctionCall(ctxt);
10437 }
10438 SKIP_BLANKS;
10439 }
10440
10441 /**
10442 * xmlXPathCompFilterExpr:
10443 * @ctxt: the XPath Parser context
10444 *
10445 * [20] FilterExpr ::= PrimaryExpr
10446 * | FilterExpr Predicate
10447 *
10448 * Compile a filter expression.
10449 * Square brackets are used to filter expressions in the same way that
10450 * they are used in location paths. It is an error if the expression to
10451 * be filtered does not evaluate to a node-set. The context node list
10452 * used for evaluating the expression in square brackets is the node-set
10453 * to be filtered listed in document order.
10454 */
10455
10456 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10457 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10458 xmlXPathCompPrimaryExpr(ctxt);
10459 CHECK_ERROR;
10460 SKIP_BLANKS;
10461
10462 while (CUR == '[') {
10463 xmlXPathCompPredicate(ctxt, 1);
10464 SKIP_BLANKS;
10465 }
10466
10467
10468 }
10469
10470 /**
10471 * xmlXPathScanName:
10472 * @ctxt: the XPath Parser context
10473 *
10474 * Trickery: parse an XML name but without consuming the input flow
10475 * Needed to avoid insanity in the parser state.
10476 *
10477 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10478 * CombiningChar | Extender
10479 *
10480 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10481 *
10482 * [6] Names ::= Name (S Name)*
10483 *
10484 * Returns the Name parsed or NULL
10485 */
10486
10487 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10488 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10489 int len = 0, l;
10490 int c;
10491 const xmlChar *cur;
10492 xmlChar *ret;
10493
10494 cur = ctxt->cur;
10495
10496 c = CUR_CHAR(l);
10497 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10498 (!IS_LETTER(c) && (c != '_') &&
10499 (c != ':'))) {
10500 return(NULL);
10501 }
10502
10503 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10504 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10505 (c == '.') || (c == '-') ||
10506 (c == '_') || (c == ':') ||
10507 (IS_COMBINING(c)) ||
10508 (IS_EXTENDER(c)))) {
10509 len += l;
10510 NEXTL(l);
10511 c = CUR_CHAR(l);
10512 }
10513 ret = xmlStrndup(cur, ctxt->cur - cur);
10514 ctxt->cur = cur;
10515 return(ret);
10516 }
10517
10518 /**
10519 * xmlXPathCompPathExpr:
10520 * @ctxt: the XPath Parser context
10521 *
10522 * [19] PathExpr ::= LocationPath
10523 * | FilterExpr
10524 * | FilterExpr '/' RelativeLocationPath
10525 * | FilterExpr '//' RelativeLocationPath
10526 *
10527 * Compile a path expression.
10528 * The / operator and // operators combine an arbitrary expression
10529 * and a relative location path. It is an error if the expression
10530 * does not evaluate to a node-set.
10531 * The / operator does composition in the same way as when / is
10532 * used in a location path. As in location paths, // is short for
10533 * /descendant-or-self::node()/.
10534 */
10535
10536 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10537 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10538 int lc = 1; /* Should we branch to LocationPath ? */
10539 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10540
10541 SKIP_BLANKS;
10542 if ((CUR == '$') || (CUR == '(') ||
10543 (IS_ASCII_DIGIT(CUR)) ||
10544 (CUR == '\'') || (CUR == '"') ||
10545 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10546 lc = 0;
10547 } else if (CUR == '*') {
10548 /* relative or absolute location path */
10549 lc = 1;
10550 } else if (CUR == '/') {
10551 /* relative or absolute location path */
10552 lc = 1;
10553 } else if (CUR == '@') {
10554 /* relative abbreviated attribute location path */
10555 lc = 1;
10556 } else if (CUR == '.') {
10557 /* relative abbreviated attribute location path */
10558 lc = 1;
10559 } else {
10560 /*
10561 * Problem is finding if we have a name here whether it's:
10562 * - a nodetype
10563 * - a function call in which case it's followed by '('
10564 * - an axis in which case it's followed by ':'
10565 * - a element name
10566 * We do an a priori analysis here rather than having to
10567 * maintain parsed token content through the recursive function
10568 * calls. This looks uglier but makes the code easier to
10569 * read/write/debug.
10570 */
10571 SKIP_BLANKS;
10572 name = xmlXPathScanName(ctxt);
10573 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10574 #ifdef DEBUG_STEP
10575 xmlGenericError(xmlGenericErrorContext,
10576 "PathExpr: Axis\n");
10577 #endif
10578 lc = 1;
10579 xmlFree(name);
10580 } else if (name != NULL) {
10581 int len =xmlStrlen(name);
10582
10583
10584 while (NXT(len) != 0) {
10585 if (NXT(len) == '/') {
10586 /* element name */
10587 #ifdef DEBUG_STEP
10588 xmlGenericError(xmlGenericErrorContext,
10589 "PathExpr: AbbrRelLocation\n");
10590 #endif
10591 lc = 1;
10592 break;
10593 } else if (IS_BLANK_CH(NXT(len))) {
10594 /* ignore blanks */
10595 ;
10596 } else if (NXT(len) == ':') {
10597 #ifdef DEBUG_STEP
10598 xmlGenericError(xmlGenericErrorContext,
10599 "PathExpr: AbbrRelLocation\n");
10600 #endif
10601 lc = 1;
10602 break;
10603 } else if ((NXT(len) == '(')) {
10604 /* Node Type or Function */
10605 if (xmlXPathIsNodeType(name)) {
10606 #ifdef DEBUG_STEP
10607 xmlGenericError(xmlGenericErrorContext,
10608 "PathExpr: Type search\n");
10609 #endif
10610 lc = 1;
10611 #ifdef LIBXML_XPTR_ENABLED
10612 } else if (ctxt->xptr &&
10613 xmlStrEqual(name, BAD_CAST "range-to")) {
10614 lc = 1;
10615 #endif
10616 } else {
10617 #ifdef DEBUG_STEP
10618 xmlGenericError(xmlGenericErrorContext,
10619 "PathExpr: function call\n");
10620 #endif
10621 lc = 0;
10622 }
10623 break;
10624 } else if ((NXT(len) == '[')) {
10625 /* element name */
10626 #ifdef DEBUG_STEP
10627 xmlGenericError(xmlGenericErrorContext,
10628 "PathExpr: AbbrRelLocation\n");
10629 #endif
10630 lc = 1;
10631 break;
10632 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10633 (NXT(len) == '=')) {
10634 lc = 1;
10635 break;
10636 } else {
10637 lc = 1;
10638 break;
10639 }
10640 len++;
10641 }
10642 if (NXT(len) == 0) {
10643 #ifdef DEBUG_STEP
10644 xmlGenericError(xmlGenericErrorContext,
10645 "PathExpr: AbbrRelLocation\n");
10646 #endif
10647 /* element name */
10648 lc = 1;
10649 }
10650 xmlFree(name);
10651 } else {
10652 /* make sure all cases are covered explicitly */
10653 XP_ERROR(XPATH_EXPR_ERROR);
10654 }
10655 }
10656
10657 if (lc) {
10658 if (CUR == '/') {
10659 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10660 } else {
10661 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10662 }
10663 xmlXPathCompLocationPath(ctxt);
10664 } else {
10665 xmlXPathCompFilterExpr(ctxt);
10666 CHECK_ERROR;
10667 if ((CUR == '/') && (NXT(1) == '/')) {
10668 SKIP(2);
10669 SKIP_BLANKS;
10670
10671 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10672 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10673
10674 xmlXPathCompRelativeLocationPath(ctxt);
10675 } else if (CUR == '/') {
10676 xmlXPathCompRelativeLocationPath(ctxt);
10677 }
10678 }
10679 SKIP_BLANKS;
10680 }
10681
10682 /**
10683 * xmlXPathCompUnionExpr:
10684 * @ctxt: the XPath Parser context
10685 *
10686 * [18] UnionExpr ::= PathExpr
10687 * | UnionExpr '|' PathExpr
10688 *
10689 * Compile an union expression.
10690 */
10691
10692 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10693 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10694 xmlXPathCompPathExpr(ctxt);
10695 CHECK_ERROR;
10696 SKIP_BLANKS;
10697 while (CUR == '|') {
10698 int op1 = ctxt->comp->last;
10699 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10700
10701 NEXT;
10702 SKIP_BLANKS;
10703 xmlXPathCompPathExpr(ctxt);
10704
10705 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10706
10707 SKIP_BLANKS;
10708 }
10709 }
10710
10711 /**
10712 * xmlXPathCompUnaryExpr:
10713 * @ctxt: the XPath Parser context
10714 *
10715 * [27] UnaryExpr ::= UnionExpr
10716 * | '-' UnaryExpr
10717 *
10718 * Compile an unary expression.
10719 */
10720
10721 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10722 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10723 int minus = 0;
10724 int found = 0;
10725
10726 SKIP_BLANKS;
10727 while (CUR == '-') {
10728 minus = 1 - minus;
10729 found = 1;
10730 NEXT;
10731 SKIP_BLANKS;
10732 }
10733
10734 xmlXPathCompUnionExpr(ctxt);
10735 CHECK_ERROR;
10736 if (found) {
10737 if (minus)
10738 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10739 else
10740 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10741 }
10742 }
10743
10744 /**
10745 * xmlXPathCompMultiplicativeExpr:
10746 * @ctxt: the XPath Parser context
10747 *
10748 * [26] MultiplicativeExpr ::= UnaryExpr
10749 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10750 * | MultiplicativeExpr 'div' UnaryExpr
10751 * | MultiplicativeExpr 'mod' UnaryExpr
10752 * [34] MultiplyOperator ::= '*'
10753 *
10754 * Compile an Additive expression.
10755 */
10756
10757 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10758 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10759 xmlXPathCompUnaryExpr(ctxt);
10760 CHECK_ERROR;
10761 SKIP_BLANKS;
10762 while ((CUR == '*') ||
10763 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10764 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10765 int op = -1;
10766 int op1 = ctxt->comp->last;
10767
10768 if (CUR == '*') {
10769 op = 0;
10770 NEXT;
10771 } else if (CUR == 'd') {
10772 op = 1;
10773 SKIP(3);
10774 } else if (CUR == 'm') {
10775 op = 2;
10776 SKIP(3);
10777 }
10778 SKIP_BLANKS;
10779 xmlXPathCompUnaryExpr(ctxt);
10780 CHECK_ERROR;
10781 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10782 SKIP_BLANKS;
10783 }
10784 }
10785
10786 /**
10787 * xmlXPathCompAdditiveExpr:
10788 * @ctxt: the XPath Parser context
10789 *
10790 * [25] AdditiveExpr ::= MultiplicativeExpr
10791 * | AdditiveExpr '+' MultiplicativeExpr
10792 * | AdditiveExpr '-' MultiplicativeExpr
10793 *
10794 * Compile an Additive expression.
10795 */
10796
10797 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10798 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10799
10800 xmlXPathCompMultiplicativeExpr(ctxt);
10801 CHECK_ERROR;
10802 SKIP_BLANKS;
10803 while ((CUR == '+') || (CUR == '-')) {
10804 int plus;
10805 int op1 = ctxt->comp->last;
10806
10807 if (CUR == '+') plus = 1;
10808 else plus = 0;
10809 NEXT;
10810 SKIP_BLANKS;
10811 xmlXPathCompMultiplicativeExpr(ctxt);
10812 CHECK_ERROR;
10813 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10814 SKIP_BLANKS;
10815 }
10816 }
10817
10818 /**
10819 * xmlXPathCompRelationalExpr:
10820 * @ctxt: the XPath Parser context
10821 *
10822 * [24] RelationalExpr ::= AdditiveExpr
10823 * | RelationalExpr '<' AdditiveExpr
10824 * | RelationalExpr '>' AdditiveExpr
10825 * | RelationalExpr '<=' AdditiveExpr
10826 * | RelationalExpr '>=' AdditiveExpr
10827 *
10828 * A <= B > C is allowed ? Answer from James, yes with
10829 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10830 * which is basically what got implemented.
10831 *
10832 * Compile a Relational expression, then push the result
10833 * on the stack
10834 */
10835
10836 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10837 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10838 xmlXPathCompAdditiveExpr(ctxt);
10839 CHECK_ERROR;
10840 SKIP_BLANKS;
10841 while ((CUR == '<') || (CUR == '>')) {
10842 int inf, strict;
10843 int op1 = ctxt->comp->last;
10844
10845 if (CUR == '<') inf = 1;
10846 else inf = 0;
10847 if (NXT(1) == '=') strict = 0;
10848 else strict = 1;
10849 NEXT;
10850 if (!strict) NEXT;
10851 SKIP_BLANKS;
10852 xmlXPathCompAdditiveExpr(ctxt);
10853 CHECK_ERROR;
10854 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10855 SKIP_BLANKS;
10856 }
10857 }
10858
10859 /**
10860 * xmlXPathCompEqualityExpr:
10861 * @ctxt: the XPath Parser context
10862 *
10863 * [23] EqualityExpr ::= RelationalExpr
10864 * | EqualityExpr '=' RelationalExpr
10865 * | EqualityExpr '!=' RelationalExpr
10866 *
10867 * A != B != C is allowed ? Answer from James, yes with
10868 * (RelationalExpr = RelationalExpr) = RelationalExpr
10869 * (RelationalExpr != RelationalExpr) != RelationalExpr
10870 * which is basically what got implemented.
10871 *
10872 * Compile an Equality expression.
10873 *
10874 */
10875 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10876 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10877 xmlXPathCompRelationalExpr(ctxt);
10878 CHECK_ERROR;
10879 SKIP_BLANKS;
10880 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10881 int eq;
10882 int op1 = ctxt->comp->last;
10883
10884 if (CUR == '=') eq = 1;
10885 else eq = 0;
10886 NEXT;
10887 if (!eq) NEXT;
10888 SKIP_BLANKS;
10889 xmlXPathCompRelationalExpr(ctxt);
10890 CHECK_ERROR;
10891 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10892 SKIP_BLANKS;
10893 }
10894 }
10895
10896 /**
10897 * xmlXPathCompAndExpr:
10898 * @ctxt: the XPath Parser context
10899 *
10900 * [22] AndExpr ::= EqualityExpr
10901 * | AndExpr 'and' EqualityExpr
10902 *
10903 * Compile an AND expression.
10904 *
10905 */
10906 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10907 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10908 xmlXPathCompEqualityExpr(ctxt);
10909 CHECK_ERROR;
10910 SKIP_BLANKS;
10911 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10912 int op1 = ctxt->comp->last;
10913 SKIP(3);
10914 SKIP_BLANKS;
10915 xmlXPathCompEqualityExpr(ctxt);
10916 CHECK_ERROR;
10917 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10918 SKIP_BLANKS;
10919 }
10920 }
10921
10922 /**
10923 * xmlXPathCompileExpr:
10924 * @ctxt: the XPath Parser context
10925 *
10926 * [14] Expr ::= OrExpr
10927 * [21] OrExpr ::= AndExpr
10928 * | OrExpr 'or' AndExpr
10929 *
10930 * Parse and compile an expression
10931 */
10932 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10933 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10934 xmlXPathContextPtr xpctxt = ctxt->context;
10935
10936 if (xpctxt != NULL) {
10937 if (xpctxt->depth >= xpctxt->maxParserDepth)
10938 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10939 xpctxt->depth += 1;
10940 }
10941
10942 xmlXPathCompAndExpr(ctxt);
10943 CHECK_ERROR;
10944 SKIP_BLANKS;
10945 while ((CUR == 'o') && (NXT(1) == 'r')) {
10946 int op1 = ctxt->comp->last;
10947 SKIP(2);
10948 SKIP_BLANKS;
10949 xmlXPathCompAndExpr(ctxt);
10950 CHECK_ERROR;
10951 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10952 SKIP_BLANKS;
10953 }
10954 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10955 /* more ops could be optimized too */
10956 /*
10957 * This is the main place to eliminate sorting for
10958 * operations which don't require a sorted node-set.
10959 * E.g. count().
10960 */
10961 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10962 }
10963
10964 if (xpctxt != NULL)
10965 xpctxt->depth -= 1;
10966 }
10967
10968 /**
10969 * xmlXPathCompPredicate:
10970 * @ctxt: the XPath Parser context
10971 * @filter: act as a filter
10972 *
10973 * [8] Predicate ::= '[' PredicateExpr ']'
10974 * [9] PredicateExpr ::= Expr
10975 *
10976 * Compile a predicate expression
10977 */
10978 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)10979 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10980 int op1 = ctxt->comp->last;
10981
10982 SKIP_BLANKS;
10983 if (CUR != '[') {
10984 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10985 }
10986 NEXT;
10987 SKIP_BLANKS;
10988
10989 ctxt->comp->last = -1;
10990 /*
10991 * This call to xmlXPathCompileExpr() will deactivate sorting
10992 * of the predicate result.
10993 * TODO: Sorting is still activated for filters, since I'm not
10994 * sure if needed. Normally sorting should not be needed, since
10995 * a filter can only diminish the number of items in a sequence,
10996 * but won't change its order; so if the initial sequence is sorted,
10997 * subsequent sorting is not needed.
10998 */
10999 if (! filter)
11000 xmlXPathCompileExpr(ctxt, 0);
11001 else
11002 xmlXPathCompileExpr(ctxt, 1);
11003 CHECK_ERROR;
11004
11005 if (CUR != ']') {
11006 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11007 }
11008
11009 if (filter)
11010 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11011 else
11012 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11013
11014 NEXT;
11015 SKIP_BLANKS;
11016 }
11017
11018 /**
11019 * xmlXPathCompNodeTest:
11020 * @ctxt: the XPath Parser context
11021 * @test: pointer to a xmlXPathTestVal
11022 * @type: pointer to a xmlXPathTypeVal
11023 * @prefix: placeholder for a possible name prefix
11024 *
11025 * [7] NodeTest ::= NameTest
11026 * | NodeType '(' ')'
11027 * | 'processing-instruction' '(' Literal ')'
11028 *
11029 * [37] NameTest ::= '*'
11030 * | NCName ':' '*'
11031 * | QName
11032 * [38] NodeType ::= 'comment'
11033 * | 'text'
11034 * | 'processing-instruction'
11035 * | 'node'
11036 *
11037 * Returns the name found and updates @test, @type and @prefix appropriately
11038 */
11039 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)11040 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11041 xmlXPathTypeVal *type, const xmlChar **prefix,
11042 xmlChar *name) {
11043 int blanks;
11044
11045 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11046 STRANGE;
11047 return(NULL);
11048 }
11049 *type = (xmlXPathTypeVal) 0;
11050 *test = (xmlXPathTestVal) 0;
11051 *prefix = NULL;
11052 SKIP_BLANKS;
11053
11054 if ((name == NULL) && (CUR == '*')) {
11055 /*
11056 * All elements
11057 */
11058 NEXT;
11059 *test = NODE_TEST_ALL;
11060 return(NULL);
11061 }
11062
11063 if (name == NULL)
11064 name = xmlXPathParseNCName(ctxt);
11065 if (name == NULL) {
11066 XP_ERRORNULL(XPATH_EXPR_ERROR);
11067 }
11068
11069 blanks = IS_BLANK_CH(CUR);
11070 SKIP_BLANKS;
11071 if (CUR == '(') {
11072 NEXT;
11073 /*
11074 * NodeType or PI search
11075 */
11076 if (xmlStrEqual(name, BAD_CAST "comment"))
11077 *type = NODE_TYPE_COMMENT;
11078 else if (xmlStrEqual(name, BAD_CAST "node"))
11079 *type = NODE_TYPE_NODE;
11080 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11081 *type = NODE_TYPE_PI;
11082 else if (xmlStrEqual(name, BAD_CAST "text"))
11083 *type = NODE_TYPE_TEXT;
11084 else {
11085 if (name != NULL)
11086 xmlFree(name);
11087 XP_ERRORNULL(XPATH_EXPR_ERROR);
11088 }
11089
11090 *test = NODE_TEST_TYPE;
11091
11092 SKIP_BLANKS;
11093 if (*type == NODE_TYPE_PI) {
11094 /*
11095 * Specific case: search a PI by name.
11096 */
11097 if (name != NULL)
11098 xmlFree(name);
11099 name = NULL;
11100 if (CUR != ')') {
11101 name = xmlXPathParseLiteral(ctxt);
11102 CHECK_ERROR NULL;
11103 *test = NODE_TEST_PI;
11104 SKIP_BLANKS;
11105 }
11106 }
11107 if (CUR != ')') {
11108 if (name != NULL)
11109 xmlFree(name);
11110 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11111 }
11112 NEXT;
11113 return(name);
11114 }
11115 *test = NODE_TEST_NAME;
11116 if ((!blanks) && (CUR == ':')) {
11117 NEXT;
11118
11119 /*
11120 * Since currently the parser context don't have a
11121 * namespace list associated:
11122 * The namespace name for this prefix can be computed
11123 * only at evaluation time. The compilation is done
11124 * outside of any context.
11125 */
11126 #if 0
11127 *prefix = xmlXPathNsLookup(ctxt->context, name);
11128 if (name != NULL)
11129 xmlFree(name);
11130 if (*prefix == NULL) {
11131 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11132 }
11133 #else
11134 *prefix = name;
11135 #endif
11136
11137 if (CUR == '*') {
11138 /*
11139 * All elements
11140 */
11141 NEXT;
11142 *test = NODE_TEST_ALL;
11143 return(NULL);
11144 }
11145
11146 name = xmlXPathParseNCName(ctxt);
11147 if (name == NULL) {
11148 XP_ERRORNULL(XPATH_EXPR_ERROR);
11149 }
11150 }
11151 return(name);
11152 }
11153
11154 /**
11155 * xmlXPathIsAxisName:
11156 * @name: a preparsed name token
11157 *
11158 * [6] AxisName ::= 'ancestor'
11159 * | 'ancestor-or-self'
11160 * | 'attribute'
11161 * | 'child'
11162 * | 'descendant'
11163 * | 'descendant-or-self'
11164 * | 'following'
11165 * | 'following-sibling'
11166 * | 'namespace'
11167 * | 'parent'
11168 * | 'preceding'
11169 * | 'preceding-sibling'
11170 * | 'self'
11171 *
11172 * Returns the axis or 0
11173 */
11174 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11175 xmlXPathIsAxisName(const xmlChar *name) {
11176 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11177 switch (name[0]) {
11178 case 'a':
11179 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11180 ret = AXIS_ANCESTOR;
11181 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11182 ret = AXIS_ANCESTOR_OR_SELF;
11183 if (xmlStrEqual(name, BAD_CAST "attribute"))
11184 ret = AXIS_ATTRIBUTE;
11185 break;
11186 case 'c':
11187 if (xmlStrEqual(name, BAD_CAST "child"))
11188 ret = AXIS_CHILD;
11189 break;
11190 case 'd':
11191 if (xmlStrEqual(name, BAD_CAST "descendant"))
11192 ret = AXIS_DESCENDANT;
11193 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11194 ret = AXIS_DESCENDANT_OR_SELF;
11195 break;
11196 case 'f':
11197 if (xmlStrEqual(name, BAD_CAST "following"))
11198 ret = AXIS_FOLLOWING;
11199 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11200 ret = AXIS_FOLLOWING_SIBLING;
11201 break;
11202 case 'n':
11203 if (xmlStrEqual(name, BAD_CAST "namespace"))
11204 ret = AXIS_NAMESPACE;
11205 break;
11206 case 'p':
11207 if (xmlStrEqual(name, BAD_CAST "parent"))
11208 ret = AXIS_PARENT;
11209 if (xmlStrEqual(name, BAD_CAST "preceding"))
11210 ret = AXIS_PRECEDING;
11211 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11212 ret = AXIS_PRECEDING_SIBLING;
11213 break;
11214 case 's':
11215 if (xmlStrEqual(name, BAD_CAST "self"))
11216 ret = AXIS_SELF;
11217 break;
11218 }
11219 return(ret);
11220 }
11221
11222 /**
11223 * xmlXPathCompStep:
11224 * @ctxt: the XPath Parser context
11225 *
11226 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11227 * | AbbreviatedStep
11228 *
11229 * [12] AbbreviatedStep ::= '.' | '..'
11230 *
11231 * [5] AxisSpecifier ::= AxisName '::'
11232 * | AbbreviatedAxisSpecifier
11233 *
11234 * [13] AbbreviatedAxisSpecifier ::= '@'?
11235 *
11236 * Modified for XPtr range support as:
11237 *
11238 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11239 * | AbbreviatedStep
11240 * | 'range-to' '(' Expr ')' Predicate*
11241 *
11242 * Compile one step in a Location Path
11243 * A location step of . is short for self::node(). This is
11244 * particularly useful in conjunction with //. For example, the
11245 * location path .//para is short for
11246 * self::node()/descendant-or-self::node()/child::para
11247 * and so will select all para descendant elements of the context
11248 * node.
11249 * Similarly, a location step of .. is short for parent::node().
11250 * For example, ../title is short for parent::node()/child::title
11251 * and so will select the title children of the parent of the context
11252 * node.
11253 */
11254 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11255 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11256 #ifdef LIBXML_XPTR_ENABLED
11257 int rangeto = 0;
11258 int op2 = -1;
11259 #endif
11260
11261 SKIP_BLANKS;
11262 if ((CUR == '.') && (NXT(1) == '.')) {
11263 SKIP(2);
11264 SKIP_BLANKS;
11265 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11266 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11267 } else if (CUR == '.') {
11268 NEXT;
11269 SKIP_BLANKS;
11270 } else {
11271 xmlChar *name = NULL;
11272 const xmlChar *prefix = NULL;
11273 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11274 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11275 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11276 int op1;
11277
11278 /*
11279 * The modification needed for XPointer change to the production
11280 */
11281 #ifdef LIBXML_XPTR_ENABLED
11282 if (ctxt->xptr) {
11283 name = xmlXPathParseNCName(ctxt);
11284 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11285 op2 = ctxt->comp->last;
11286 xmlFree(name);
11287 SKIP_BLANKS;
11288 if (CUR != '(') {
11289 XP_ERROR(XPATH_EXPR_ERROR);
11290 }
11291 NEXT;
11292 SKIP_BLANKS;
11293
11294 xmlXPathCompileExpr(ctxt, 1);
11295 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11296 CHECK_ERROR;
11297
11298 SKIP_BLANKS;
11299 if (CUR != ')') {
11300 XP_ERROR(XPATH_EXPR_ERROR);
11301 }
11302 NEXT;
11303 rangeto = 1;
11304 goto eval_predicates;
11305 }
11306 }
11307 #endif
11308 if (CUR == '*') {
11309 axis = AXIS_CHILD;
11310 } else {
11311 if (name == NULL)
11312 name = xmlXPathParseNCName(ctxt);
11313 if (name != NULL) {
11314 axis = xmlXPathIsAxisName(name);
11315 if (axis != 0) {
11316 SKIP_BLANKS;
11317 if ((CUR == ':') && (NXT(1) == ':')) {
11318 SKIP(2);
11319 xmlFree(name);
11320 name = NULL;
11321 } else {
11322 /* an element name can conflict with an axis one :-\ */
11323 axis = AXIS_CHILD;
11324 }
11325 } else {
11326 axis = AXIS_CHILD;
11327 }
11328 } else if (CUR == '@') {
11329 NEXT;
11330 axis = AXIS_ATTRIBUTE;
11331 } else {
11332 axis = AXIS_CHILD;
11333 }
11334 }
11335
11336 if (ctxt->error != XPATH_EXPRESSION_OK) {
11337 xmlFree(name);
11338 return;
11339 }
11340
11341 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11342 if (test == 0)
11343 return;
11344
11345 if ((prefix != NULL) && (ctxt->context != NULL) &&
11346 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11347 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11348 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11349 }
11350 }
11351 #ifdef DEBUG_STEP
11352 xmlGenericError(xmlGenericErrorContext,
11353 "Basis : computing new set\n");
11354 #endif
11355
11356 #ifdef DEBUG_STEP
11357 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11358 if (ctxt->value == NULL)
11359 xmlGenericError(xmlGenericErrorContext, "no value\n");
11360 else if (ctxt->value->nodesetval == NULL)
11361 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11362 else
11363 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11364 #endif
11365
11366 #ifdef LIBXML_XPTR_ENABLED
11367 eval_predicates:
11368 #endif
11369 op1 = ctxt->comp->last;
11370 ctxt->comp->last = -1;
11371
11372 SKIP_BLANKS;
11373 while (CUR == '[') {
11374 xmlXPathCompPredicate(ctxt, 0);
11375 }
11376
11377 #ifdef LIBXML_XPTR_ENABLED
11378 if (rangeto) {
11379 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11380 } else
11381 #endif
11382 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11383 test, type, (void *)prefix, (void *)name);
11384
11385 }
11386 #ifdef DEBUG_STEP
11387 xmlGenericError(xmlGenericErrorContext, "Step : ");
11388 if (ctxt->value == NULL)
11389 xmlGenericError(xmlGenericErrorContext, "no value\n");
11390 else if (ctxt->value->nodesetval == NULL)
11391 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11392 else
11393 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11394 ctxt->value->nodesetval);
11395 #endif
11396 }
11397
11398 /**
11399 * xmlXPathCompRelativeLocationPath:
11400 * @ctxt: the XPath Parser context
11401 *
11402 * [3] RelativeLocationPath ::= Step
11403 * | RelativeLocationPath '/' Step
11404 * | AbbreviatedRelativeLocationPath
11405 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11406 *
11407 * Compile a relative location path.
11408 */
11409 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11410 xmlXPathCompRelativeLocationPath
11411 (xmlXPathParserContextPtr ctxt) {
11412 SKIP_BLANKS;
11413 if ((CUR == '/') && (NXT(1) == '/')) {
11414 SKIP(2);
11415 SKIP_BLANKS;
11416 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11417 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11418 } else if (CUR == '/') {
11419 NEXT;
11420 SKIP_BLANKS;
11421 }
11422 xmlXPathCompStep(ctxt);
11423 CHECK_ERROR;
11424 SKIP_BLANKS;
11425 while (CUR == '/') {
11426 if ((CUR == '/') && (NXT(1) == '/')) {
11427 SKIP(2);
11428 SKIP_BLANKS;
11429 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11430 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11431 xmlXPathCompStep(ctxt);
11432 } else if (CUR == '/') {
11433 NEXT;
11434 SKIP_BLANKS;
11435 xmlXPathCompStep(ctxt);
11436 }
11437 SKIP_BLANKS;
11438 }
11439 }
11440
11441 /**
11442 * xmlXPathCompLocationPath:
11443 * @ctxt: the XPath Parser context
11444 *
11445 * [1] LocationPath ::= RelativeLocationPath
11446 * | AbsoluteLocationPath
11447 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11448 * | AbbreviatedAbsoluteLocationPath
11449 * [10] AbbreviatedAbsoluteLocationPath ::=
11450 * '//' RelativeLocationPath
11451 *
11452 * Compile a location path
11453 *
11454 * // is short for /descendant-or-self::node()/. For example,
11455 * //para is short for /descendant-or-self::node()/child::para and
11456 * so will select any para element in the document (even a para element
11457 * that is a document element will be selected by //para since the
11458 * document element node is a child of the root node); div//para is
11459 * short for div/descendant-or-self::node()/child::para and so will
11460 * select all para descendants of div children.
11461 */
11462 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11463 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11464 SKIP_BLANKS;
11465 if (CUR != '/') {
11466 xmlXPathCompRelativeLocationPath(ctxt);
11467 } else {
11468 while (CUR == '/') {
11469 if ((CUR == '/') && (NXT(1) == '/')) {
11470 SKIP(2);
11471 SKIP_BLANKS;
11472 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11473 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11474 xmlXPathCompRelativeLocationPath(ctxt);
11475 } else if (CUR == '/') {
11476 NEXT;
11477 SKIP_BLANKS;
11478 if ((CUR != 0 ) &&
11479 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11480 (CUR == '@') || (CUR == '*')))
11481 xmlXPathCompRelativeLocationPath(ctxt);
11482 }
11483 CHECK_ERROR;
11484 }
11485 }
11486 }
11487
11488 /************************************************************************
11489 * *
11490 * XPath precompiled expression evaluation *
11491 * *
11492 ************************************************************************/
11493
11494 static int
11495 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11496
11497 #ifdef DEBUG_STEP
11498 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11499 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11500 int nbNodes)
11501 {
11502 xmlGenericError(xmlGenericErrorContext, "new step : ");
11503 switch (op->value) {
11504 case AXIS_ANCESTOR:
11505 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11506 break;
11507 case AXIS_ANCESTOR_OR_SELF:
11508 xmlGenericError(xmlGenericErrorContext,
11509 "axis 'ancestors-or-self' ");
11510 break;
11511 case AXIS_ATTRIBUTE:
11512 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11513 break;
11514 case AXIS_CHILD:
11515 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11516 break;
11517 case AXIS_DESCENDANT:
11518 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11519 break;
11520 case AXIS_DESCENDANT_OR_SELF:
11521 xmlGenericError(xmlGenericErrorContext,
11522 "axis 'descendant-or-self' ");
11523 break;
11524 case AXIS_FOLLOWING:
11525 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11526 break;
11527 case AXIS_FOLLOWING_SIBLING:
11528 xmlGenericError(xmlGenericErrorContext,
11529 "axis 'following-siblings' ");
11530 break;
11531 case AXIS_NAMESPACE:
11532 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11533 break;
11534 case AXIS_PARENT:
11535 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11536 break;
11537 case AXIS_PRECEDING:
11538 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11539 break;
11540 case AXIS_PRECEDING_SIBLING:
11541 xmlGenericError(xmlGenericErrorContext,
11542 "axis 'preceding-sibling' ");
11543 break;
11544 case AXIS_SELF:
11545 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11546 break;
11547 }
11548 xmlGenericError(xmlGenericErrorContext,
11549 " context contains %d nodes\n", nbNodes);
11550 switch (op->value2) {
11551 case NODE_TEST_NONE:
11552 xmlGenericError(xmlGenericErrorContext,
11553 " searching for none !!!\n");
11554 break;
11555 case NODE_TEST_TYPE:
11556 xmlGenericError(xmlGenericErrorContext,
11557 " searching for type %d\n", op->value3);
11558 break;
11559 case NODE_TEST_PI:
11560 xmlGenericError(xmlGenericErrorContext,
11561 " searching for PI !!!\n");
11562 break;
11563 case NODE_TEST_ALL:
11564 xmlGenericError(xmlGenericErrorContext,
11565 " searching for *\n");
11566 break;
11567 case NODE_TEST_NS:
11568 xmlGenericError(xmlGenericErrorContext,
11569 " searching for namespace %s\n",
11570 op->value5);
11571 break;
11572 case NODE_TEST_NAME:
11573 xmlGenericError(xmlGenericErrorContext,
11574 " searching for name %s\n", op->value5);
11575 if (op->value4)
11576 xmlGenericError(xmlGenericErrorContext,
11577 " with namespace %s\n", op->value4);
11578 break;
11579 }
11580 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11581 }
11582 #endif /* DEBUG_STEP */
11583
11584 /**
11585 * xmlXPathNodeSetFilter:
11586 * @ctxt: the XPath Parser context
11587 * @set: the node set to filter
11588 * @filterOpIndex: the index of the predicate/filter op
11589 * @minPos: minimum position in the filtered set (1-based)
11590 * @maxPos: maximum position in the filtered set (1-based)
11591 * @hasNsNodes: true if the node set may contain namespace nodes
11592 *
11593 * Filter a node set, keeping only nodes for which the predicate expression
11594 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11595 * filtered result.
11596 */
11597 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)11598 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11599 xmlNodeSetPtr set,
11600 int filterOpIndex,
11601 int minPos, int maxPos,
11602 int hasNsNodes)
11603 {
11604 xmlXPathContextPtr xpctxt;
11605 xmlNodePtr oldnode;
11606 xmlDocPtr olddoc;
11607 xmlXPathStepOpPtr filterOp;
11608 int oldcs, oldpp;
11609 int i, j, pos;
11610
11611 if ((set == NULL) || (set->nodeNr == 0))
11612 return;
11613
11614 /*
11615 * Check if the node set contains a sufficient number of nodes for
11616 * the requested range.
11617 */
11618 if (set->nodeNr < minPos) {
11619 xmlXPathNodeSetClear(set, hasNsNodes);
11620 return;
11621 }
11622
11623 xpctxt = ctxt->context;
11624 oldnode = xpctxt->node;
11625 olddoc = xpctxt->doc;
11626 oldcs = xpctxt->contextSize;
11627 oldpp = xpctxt->proximityPosition;
11628 filterOp = &ctxt->comp->steps[filterOpIndex];
11629
11630 xpctxt->contextSize = set->nodeNr;
11631
11632 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11633 xmlNodePtr node = set->nodeTab[i];
11634 int res;
11635
11636 xpctxt->node = node;
11637 xpctxt->proximityPosition = i + 1;
11638
11639 /*
11640 * Also set the xpath document in case things like
11641 * key() are evaluated in the predicate.
11642 *
11643 * TODO: Get real doc for namespace nodes.
11644 */
11645 if ((node->type != XML_NAMESPACE_DECL) &&
11646 (node->doc != NULL))
11647 xpctxt->doc = node->doc;
11648
11649 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11650
11651 if (ctxt->error != XPATH_EXPRESSION_OK)
11652 goto exit;
11653 if (res < 0) {
11654 /* Shouldn't happen */
11655 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11656 goto exit;
11657 }
11658
11659 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11660 if (i != j) {
11661 set->nodeTab[j] = node;
11662 set->nodeTab[i] = NULL;
11663 }
11664
11665 j += 1;
11666 } else {
11667 /* Remove the entry from the initial node set. */
11668 set->nodeTab[i] = NULL;
11669 if (node->type == XML_NAMESPACE_DECL)
11670 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11671 }
11672
11673 if (res != 0) {
11674 if (pos == maxPos) {
11675 /* Clear remaining nodes and exit loop. */
11676 if (hasNsNodes) {
11677 for (i++; i < set->nodeNr; i++) {
11678 node = set->nodeTab[i];
11679 if ((node != NULL) &&
11680 (node->type == XML_NAMESPACE_DECL))
11681 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11682 }
11683 }
11684 break;
11685 }
11686
11687 pos += 1;
11688 }
11689 }
11690
11691 set->nodeNr = j;
11692
11693 /* If too many elements were removed, shrink table to preserve memory. */
11694 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11695 (set->nodeNr < set->nodeMax / 2)) {
11696 xmlNodePtr *tmp;
11697 int nodeMax = set->nodeNr;
11698
11699 if (nodeMax < XML_NODESET_DEFAULT)
11700 nodeMax = XML_NODESET_DEFAULT;
11701 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11702 nodeMax * sizeof(xmlNodePtr));
11703 if (tmp == NULL) {
11704 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11705 } else {
11706 set->nodeTab = tmp;
11707 set->nodeMax = nodeMax;
11708 }
11709 }
11710
11711 exit:
11712 xpctxt->node = oldnode;
11713 xpctxt->doc = olddoc;
11714 xpctxt->contextSize = oldcs;
11715 xpctxt->proximityPosition = oldpp;
11716 }
11717
11718 #ifdef LIBXML_XPTR_ENABLED
11719 /**
11720 * xmlXPathLocationSetFilter:
11721 * @ctxt: the XPath Parser context
11722 * @locset: the location set to filter
11723 * @filterOpIndex: the index of the predicate/filter op
11724 * @minPos: minimum position in the filtered set (1-based)
11725 * @maxPos: maximum position in the filtered set (1-based)
11726 *
11727 * Filter a location set, keeping only nodes for which the predicate
11728 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11729 * in the filtered result.
11730 */
11731 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)11732 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11733 xmlLocationSetPtr locset,
11734 int filterOpIndex,
11735 int minPos, int maxPos)
11736 {
11737 xmlXPathContextPtr xpctxt;
11738 xmlNodePtr oldnode;
11739 xmlDocPtr olddoc;
11740 xmlXPathStepOpPtr filterOp;
11741 int oldcs, oldpp;
11742 int i, j, pos;
11743
11744 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11745 return;
11746
11747 xpctxt = ctxt->context;
11748 oldnode = xpctxt->node;
11749 olddoc = xpctxt->doc;
11750 oldcs = xpctxt->contextSize;
11751 oldpp = xpctxt->proximityPosition;
11752 filterOp = &ctxt->comp->steps[filterOpIndex];
11753
11754 xpctxt->contextSize = locset->locNr;
11755
11756 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11757 xmlNodePtr contextNode = locset->locTab[i]->user;
11758 int res;
11759
11760 xpctxt->node = contextNode;
11761 xpctxt->proximityPosition = i + 1;
11762
11763 /*
11764 * Also set the xpath document in case things like
11765 * key() are evaluated in the predicate.
11766 *
11767 * TODO: Get real doc for namespace nodes.
11768 */
11769 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11770 (contextNode->doc != NULL))
11771 xpctxt->doc = contextNode->doc;
11772
11773 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11774
11775 if (ctxt->error != XPATH_EXPRESSION_OK)
11776 goto exit;
11777 if (res < 0) {
11778 /* Shouldn't happen */
11779 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11780 goto exit;
11781 }
11782
11783 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11784 if (i != j) {
11785 locset->locTab[j] = locset->locTab[i];
11786 locset->locTab[i] = NULL;
11787 }
11788
11789 j += 1;
11790 } else {
11791 /* Remove the entry from the initial location set. */
11792 xmlXPathFreeObject(locset->locTab[i]);
11793 locset->locTab[i] = NULL;
11794 }
11795
11796 if (res != 0) {
11797 if (pos == maxPos) {
11798 /* Clear remaining nodes and exit loop. */
11799 for (i++; i < locset->locNr; i++) {
11800 xmlXPathFreeObject(locset->locTab[i]);
11801 }
11802 break;
11803 }
11804
11805 pos += 1;
11806 }
11807 }
11808
11809 locset->locNr = j;
11810
11811 /* If too many elements were removed, shrink table to preserve memory. */
11812 if ((locset->locMax > XML_NODESET_DEFAULT) &&
11813 (locset->locNr < locset->locMax / 2)) {
11814 xmlXPathObjectPtr *tmp;
11815 int locMax = locset->locNr;
11816
11817 if (locMax < XML_NODESET_DEFAULT)
11818 locMax = XML_NODESET_DEFAULT;
11819 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11820 locMax * sizeof(xmlXPathObjectPtr));
11821 if (tmp == NULL) {
11822 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11823 } else {
11824 locset->locTab = tmp;
11825 locset->locMax = locMax;
11826 }
11827 }
11828
11829 exit:
11830 xpctxt->node = oldnode;
11831 xpctxt->doc = olddoc;
11832 xpctxt->contextSize = oldcs;
11833 xpctxt->proximityPosition = oldpp;
11834 }
11835 #endif /* LIBXML_XPTR_ENABLED */
11836
11837 /**
11838 * xmlXPathCompOpEvalPredicate:
11839 * @ctxt: the XPath Parser context
11840 * @op: the predicate op
11841 * @set: the node set to filter
11842 * @minPos: minimum position in the filtered set (1-based)
11843 * @maxPos: maximum position in the filtered set (1-based)
11844 * @hasNsNodes: true if the node set may contain namespace nodes
11845 *
11846 * Filter a node set, keeping only nodes for which the sequence of predicate
11847 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11848 * in the filtered result.
11849 */
11850 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)11851 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11852 xmlXPathStepOpPtr op,
11853 xmlNodeSetPtr set,
11854 int minPos, int maxPos,
11855 int hasNsNodes)
11856 {
11857 if (op->ch1 != -1) {
11858 xmlXPathCompExprPtr comp = ctxt->comp;
11859 /*
11860 * Process inner predicates first.
11861 */
11862 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11863 xmlGenericError(xmlGenericErrorContext,
11864 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11865 XP_ERROR(XPATH_INVALID_OPERAND);
11866 }
11867 if (ctxt->context->depth >= ctxt->context->maxDepth)
11868 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11869 ctxt->context->depth += 1;
11870 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11871 1, set->nodeNr, hasNsNodes);
11872 ctxt->context->depth -= 1;
11873 CHECK_ERROR;
11874 }
11875
11876 if (op->ch2 != -1)
11877 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11878 }
11879
11880 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11881 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11882 xmlXPathStepOpPtr op,
11883 int *maxPos)
11884 {
11885
11886 xmlXPathStepOpPtr exprOp;
11887
11888 /*
11889 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11890 */
11891
11892 /*
11893 * If not -1, then ch1 will point to:
11894 * 1) For predicates (XPATH_OP_PREDICATE):
11895 * - an inner predicate operator
11896 * 2) For filters (XPATH_OP_FILTER):
11897 * - an inner filter operator OR
11898 * - an expression selecting the node set.
11899 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11900 */
11901 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11902 return(0);
11903
11904 if (op->ch2 != -1) {
11905 exprOp = &ctxt->comp->steps[op->ch2];
11906 } else
11907 return(0);
11908
11909 if ((exprOp != NULL) &&
11910 (exprOp->op == XPATH_OP_VALUE) &&
11911 (exprOp->value4 != NULL) &&
11912 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11913 {
11914 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11915
11916 /*
11917 * We have a "[n]" predicate here.
11918 * TODO: Unfortunately this simplistic test here is not
11919 * able to detect a position() predicate in compound
11920 * expressions like "[@attr = 'a" and position() = 1],
11921 * and even not the usage of position() in
11922 * "[position() = 1]"; thus - obviously - a position-range,
11923 * like it "[position() < 5]", is also not detected.
11924 * Maybe we could rewrite the AST to ease the optimization.
11925 */
11926
11927 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11928 *maxPos = (int) floatval;
11929 if (floatval == (double) *maxPos)
11930 return(1);
11931 }
11932 }
11933 return(0);
11934 }
11935
11936 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11937 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11938 xmlXPathStepOpPtr op,
11939 xmlNodePtr * first, xmlNodePtr * last,
11940 int toBool)
11941 {
11942
11943 #define XP_TEST_HIT \
11944 if (hasAxisRange != 0) { \
11945 if (++pos == maxPos) { \
11946 if (addNode(seq, cur) < 0) \
11947 ctxt->error = XPATH_MEMORY_ERROR; \
11948 goto axis_range_end; } \
11949 } else { \
11950 if (addNode(seq, cur) < 0) \
11951 ctxt->error = XPATH_MEMORY_ERROR; \
11952 if (breakOnFirstHit) goto first_hit; }
11953
11954 #define XP_TEST_HIT_NS \
11955 if (hasAxisRange != 0) { \
11956 if (++pos == maxPos) { \
11957 hasNsNodes = 1; \
11958 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11959 ctxt->error = XPATH_MEMORY_ERROR; \
11960 goto axis_range_end; } \
11961 } else { \
11962 hasNsNodes = 1; \
11963 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11964 ctxt->error = XPATH_MEMORY_ERROR; \
11965 if (breakOnFirstHit) goto first_hit; }
11966
11967 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11968 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11969 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11970 const xmlChar *prefix = op->value4;
11971 const xmlChar *name = op->value5;
11972 const xmlChar *URI = NULL;
11973
11974 #ifdef DEBUG_STEP
11975 int nbMatches = 0, prevMatches = 0;
11976 #endif
11977 int total = 0, hasNsNodes = 0;
11978 /* The popped object holding the context nodes */
11979 xmlXPathObjectPtr obj;
11980 /* The set of context nodes for the node tests */
11981 xmlNodeSetPtr contextSeq;
11982 int contextIdx;
11983 xmlNodePtr contextNode;
11984 /* The final resulting node set wrt to all context nodes */
11985 xmlNodeSetPtr outSeq;
11986 /*
11987 * The temporary resulting node set wrt 1 context node.
11988 * Used to feed predicate evaluation.
11989 */
11990 xmlNodeSetPtr seq;
11991 xmlNodePtr cur;
11992 /* First predicate operator */
11993 xmlXPathStepOpPtr predOp;
11994 int maxPos; /* The requested position() (when a "[n]" predicate) */
11995 int hasPredicateRange, hasAxisRange, pos;
11996 int breakOnFirstHit;
11997
11998 xmlXPathTraversalFunction next = NULL;
11999 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12000 xmlXPathNodeSetMergeFunction mergeAndClear;
12001 xmlNodePtr oldContextNode;
12002 xmlXPathContextPtr xpctxt = ctxt->context;
12003
12004
12005 CHECK_TYPE0(XPATH_NODESET);
12006 obj = valuePop(ctxt);
12007 /*
12008 * Setup namespaces.
12009 */
12010 if (prefix != NULL) {
12011 URI = xmlXPathNsLookup(xpctxt, prefix);
12012 if (URI == NULL) {
12013 xmlXPathReleaseObject(xpctxt, obj);
12014 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12015 }
12016 }
12017 /*
12018 * Setup axis.
12019 *
12020 * MAYBE FUTURE TODO: merging optimizations:
12021 * - If the nodes to be traversed wrt to the initial nodes and
12022 * the current axis cannot overlap, then we could avoid searching
12023 * for duplicates during the merge.
12024 * But the question is how/when to evaluate if they cannot overlap.
12025 * Example: if we know that for two initial nodes, the one is
12026 * not in the ancestor-or-self axis of the other, then we could safely
12027 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12028 * the descendant-or-self axis.
12029 */
12030 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12031 switch (axis) {
12032 case AXIS_ANCESTOR:
12033 first = NULL;
12034 next = xmlXPathNextAncestor;
12035 break;
12036 case AXIS_ANCESTOR_OR_SELF:
12037 first = NULL;
12038 next = xmlXPathNextAncestorOrSelf;
12039 break;
12040 case AXIS_ATTRIBUTE:
12041 first = NULL;
12042 last = NULL;
12043 next = xmlXPathNextAttribute;
12044 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12045 break;
12046 case AXIS_CHILD:
12047 last = NULL;
12048 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12049 (type == NODE_TYPE_NODE))
12050 {
12051 /*
12052 * Optimization if an element node type is 'element'.
12053 */
12054 next = xmlXPathNextChildElement;
12055 } else
12056 next = xmlXPathNextChild;
12057 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058 break;
12059 case AXIS_DESCENDANT:
12060 last = NULL;
12061 next = xmlXPathNextDescendant;
12062 break;
12063 case AXIS_DESCENDANT_OR_SELF:
12064 last = NULL;
12065 next = xmlXPathNextDescendantOrSelf;
12066 break;
12067 case AXIS_FOLLOWING:
12068 last = NULL;
12069 next = xmlXPathNextFollowing;
12070 break;
12071 case AXIS_FOLLOWING_SIBLING:
12072 last = NULL;
12073 next = xmlXPathNextFollowingSibling;
12074 break;
12075 case AXIS_NAMESPACE:
12076 first = NULL;
12077 last = NULL;
12078 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12079 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080 break;
12081 case AXIS_PARENT:
12082 first = NULL;
12083 next = xmlXPathNextParent;
12084 break;
12085 case AXIS_PRECEDING:
12086 first = NULL;
12087 next = xmlXPathNextPrecedingInternal;
12088 break;
12089 case AXIS_PRECEDING_SIBLING:
12090 first = NULL;
12091 next = xmlXPathNextPrecedingSibling;
12092 break;
12093 case AXIS_SELF:
12094 first = NULL;
12095 last = NULL;
12096 next = xmlXPathNextSelf;
12097 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12098 break;
12099 }
12100
12101 #ifdef DEBUG_STEP
12102 xmlXPathDebugDumpStepAxis(op,
12103 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12104 #endif
12105
12106 if (next == NULL) {
12107 xmlXPathReleaseObject(xpctxt, obj);
12108 return(0);
12109 }
12110 contextSeq = obj->nodesetval;
12111 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12112 xmlXPathReleaseObject(xpctxt, obj);
12113 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12114 return(0);
12115 }
12116 /*
12117 * Predicate optimization ---------------------------------------------
12118 * If this step has a last predicate, which contains a position(),
12119 * then we'll optimize (although not exactly "position()", but only
12120 * the short-hand form, i.e., "[n]".
12121 *
12122 * Example - expression "/foo[parent::bar][1]":
12123 *
12124 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12125 * ROOT -- op->ch1
12126 * PREDICATE -- op->ch2 (predOp)
12127 * PREDICATE -- predOp->ch1 = [parent::bar]
12128 * SORT
12129 * COLLECT 'parent' 'name' 'node' bar
12130 * NODE
12131 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12132 *
12133 */
12134 maxPos = 0;
12135 predOp = NULL;
12136 hasPredicateRange = 0;
12137 hasAxisRange = 0;
12138 if (op->ch2 != -1) {
12139 /*
12140 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12141 */
12142 predOp = &ctxt->comp->steps[op->ch2];
12143 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12144 if (predOp->ch1 != -1) {
12145 /*
12146 * Use the next inner predicate operator.
12147 */
12148 predOp = &ctxt->comp->steps[predOp->ch1];
12149 hasPredicateRange = 1;
12150 } else {
12151 /*
12152 * There's no other predicate than the [n] predicate.
12153 */
12154 predOp = NULL;
12155 hasAxisRange = 1;
12156 }
12157 }
12158 }
12159 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12160 /*
12161 * Axis traversal -----------------------------------------------------
12162 */
12163 /*
12164 * 2.3 Node Tests
12165 * - For the attribute axis, the principal node type is attribute.
12166 * - For the namespace axis, the principal node type is namespace.
12167 * - For other axes, the principal node type is element.
12168 *
12169 * A node test * is true for any node of the
12170 * principal node type. For example, child::* will
12171 * select all element children of the context node
12172 */
12173 oldContextNode = xpctxt->node;
12174 addNode = xmlXPathNodeSetAddUnique;
12175 outSeq = NULL;
12176 seq = NULL;
12177 contextNode = NULL;
12178 contextIdx = 0;
12179
12180
12181 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12182 (ctxt->error == XPATH_EXPRESSION_OK)) {
12183 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12184
12185 if (seq == NULL) {
12186 seq = xmlXPathNodeSetCreate(NULL);
12187 if (seq == NULL) {
12188 /* TODO: Propagate memory error. */
12189 total = 0;
12190 goto error;
12191 }
12192 }
12193 /*
12194 * Traverse the axis and test the nodes.
12195 */
12196 pos = 0;
12197 cur = NULL;
12198 hasNsNodes = 0;
12199 do {
12200 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12201 goto error;
12202
12203 cur = next(ctxt, cur);
12204 if (cur == NULL)
12205 break;
12206
12207 /*
12208 * QUESTION TODO: What does the "first" and "last" stuff do?
12209 */
12210 if ((first != NULL) && (*first != NULL)) {
12211 if (*first == cur)
12212 break;
12213 if (((total % 256) == 0) &&
12214 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12215 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12216 #else
12217 (xmlXPathCmpNodes(*first, cur) >= 0))
12218 #endif
12219 {
12220 break;
12221 }
12222 }
12223 if ((last != NULL) && (*last != NULL)) {
12224 if (*last == cur)
12225 break;
12226 if (((total % 256) == 0) &&
12227 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12228 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12229 #else
12230 (xmlXPathCmpNodes(cur, *last) >= 0))
12231 #endif
12232 {
12233 break;
12234 }
12235 }
12236
12237 total++;
12238
12239 #ifdef DEBUG_STEP
12240 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12241 #endif
12242
12243 switch (test) {
12244 case NODE_TEST_NONE:
12245 total = 0;
12246 STRANGE
12247 goto error;
12248 case NODE_TEST_TYPE:
12249 if (type == NODE_TYPE_NODE) {
12250 switch (cur->type) {
12251 case XML_DOCUMENT_NODE:
12252 case XML_HTML_DOCUMENT_NODE:
12253 #ifdef LIBXML_DOCB_ENABLED
12254 case XML_DOCB_DOCUMENT_NODE:
12255 #endif
12256 case XML_ELEMENT_NODE:
12257 case XML_ATTRIBUTE_NODE:
12258 case XML_PI_NODE:
12259 case XML_COMMENT_NODE:
12260 case XML_CDATA_SECTION_NODE:
12261 case XML_TEXT_NODE:
12262 XP_TEST_HIT
12263 break;
12264 case XML_NAMESPACE_DECL: {
12265 if (axis == AXIS_NAMESPACE) {
12266 XP_TEST_HIT_NS
12267 } else {
12268 hasNsNodes = 1;
12269 XP_TEST_HIT
12270 }
12271 break;
12272 }
12273 default:
12274 break;
12275 }
12276 } else if (cur->type == (xmlElementType) type) {
12277 if (cur->type == XML_NAMESPACE_DECL)
12278 XP_TEST_HIT_NS
12279 else
12280 XP_TEST_HIT
12281 } else if ((type == NODE_TYPE_TEXT) &&
12282 (cur->type == XML_CDATA_SECTION_NODE))
12283 {
12284 XP_TEST_HIT
12285 }
12286 break;
12287 case NODE_TEST_PI:
12288 if ((cur->type == XML_PI_NODE) &&
12289 ((name == NULL) || xmlStrEqual(name, cur->name)))
12290 {
12291 XP_TEST_HIT
12292 }
12293 break;
12294 case NODE_TEST_ALL:
12295 if (axis == AXIS_ATTRIBUTE) {
12296 if (cur->type == XML_ATTRIBUTE_NODE)
12297 {
12298 if (prefix == NULL)
12299 {
12300 XP_TEST_HIT
12301 } else if ((cur->ns != NULL) &&
12302 (xmlStrEqual(URI, cur->ns->href)))
12303 {
12304 XP_TEST_HIT
12305 }
12306 }
12307 } else if (axis == AXIS_NAMESPACE) {
12308 if (cur->type == XML_NAMESPACE_DECL)
12309 {
12310 XP_TEST_HIT_NS
12311 }
12312 } else {
12313 if (cur->type == XML_ELEMENT_NODE) {
12314 if (prefix == NULL)
12315 {
12316 XP_TEST_HIT
12317
12318 } else if ((cur->ns != NULL) &&
12319 (xmlStrEqual(URI, cur->ns->href)))
12320 {
12321 XP_TEST_HIT
12322 }
12323 }
12324 }
12325 break;
12326 case NODE_TEST_NS:{
12327 TODO;
12328 break;
12329 }
12330 case NODE_TEST_NAME:
12331 if (axis == AXIS_ATTRIBUTE) {
12332 if (cur->type != XML_ATTRIBUTE_NODE)
12333 break;
12334 } else if (axis == AXIS_NAMESPACE) {
12335 if (cur->type != XML_NAMESPACE_DECL)
12336 break;
12337 } else {
12338 if (cur->type != XML_ELEMENT_NODE)
12339 break;
12340 }
12341 switch (cur->type) {
12342 case XML_ELEMENT_NODE:
12343 if (xmlStrEqual(name, cur->name)) {
12344 if (prefix == NULL) {
12345 if (cur->ns == NULL)
12346 {
12347 XP_TEST_HIT
12348 }
12349 } else {
12350 if ((cur->ns != NULL) &&
12351 (xmlStrEqual(URI, cur->ns->href)))
12352 {
12353 XP_TEST_HIT
12354 }
12355 }
12356 }
12357 break;
12358 case XML_ATTRIBUTE_NODE:{
12359 xmlAttrPtr attr = (xmlAttrPtr) cur;
12360
12361 if (xmlStrEqual(name, attr->name)) {
12362 if (prefix == NULL) {
12363 if ((attr->ns == NULL) ||
12364 (attr->ns->prefix == NULL))
12365 {
12366 XP_TEST_HIT
12367 }
12368 } else {
12369 if ((attr->ns != NULL) &&
12370 (xmlStrEqual(URI,
12371 attr->ns->href)))
12372 {
12373 XP_TEST_HIT
12374 }
12375 }
12376 }
12377 break;
12378 }
12379 case XML_NAMESPACE_DECL:
12380 if (cur->type == XML_NAMESPACE_DECL) {
12381 xmlNsPtr ns = (xmlNsPtr) cur;
12382
12383 if ((ns->prefix != NULL) && (name != NULL)
12384 && (xmlStrEqual(ns->prefix, name)))
12385 {
12386 XP_TEST_HIT_NS
12387 }
12388 }
12389 break;
12390 default:
12391 break;
12392 }
12393 break;
12394 } /* switch(test) */
12395 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12396
12397 goto apply_predicates;
12398
12399 axis_range_end: /* ----------------------------------------------------- */
12400 /*
12401 * We have a "/foo[n]", and position() = n was reached.
12402 * Note that we can have as well "/foo/::parent::foo[1]", so
12403 * a duplicate-aware merge is still needed.
12404 * Merge with the result.
12405 */
12406 if (outSeq == NULL) {
12407 outSeq = seq;
12408 seq = NULL;
12409 } else
12410 /* TODO: Check memory error. */
12411 outSeq = mergeAndClear(outSeq, seq);
12412 /*
12413 * Break if only a true/false result was requested.
12414 */
12415 if (toBool)
12416 break;
12417 continue;
12418
12419 first_hit: /* ---------------------------------------------------------- */
12420 /*
12421 * Break if only a true/false result was requested and
12422 * no predicates existed and a node test succeeded.
12423 */
12424 if (outSeq == NULL) {
12425 outSeq = seq;
12426 seq = NULL;
12427 } else
12428 /* TODO: Check memory error. */
12429 outSeq = mergeAndClear(outSeq, seq);
12430 break;
12431
12432 #ifdef DEBUG_STEP
12433 if (seq != NULL)
12434 nbMatches += seq->nodeNr;
12435 #endif
12436
12437 apply_predicates: /* --------------------------------------------------- */
12438 if (ctxt->error != XPATH_EXPRESSION_OK)
12439 goto error;
12440
12441 /*
12442 * Apply predicates.
12443 */
12444 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12445 /*
12446 * E.g. when we have a "/foo[some expression][n]".
12447 */
12448 /*
12449 * QUESTION TODO: The old predicate evaluation took into
12450 * account location-sets.
12451 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12452 * Do we expect such a set here?
12453 * All what I learned now from the evaluation semantics
12454 * does not indicate that a location-set will be processed
12455 * here, so this looks OK.
12456 */
12457 /*
12458 * Iterate over all predicates, starting with the outermost
12459 * predicate.
12460 * TODO: Problem: we cannot execute the inner predicates first
12461 * since we cannot go back *up* the operator tree!
12462 * Options we have:
12463 * 1) Use of recursive functions (like is it currently done
12464 * via xmlXPathCompOpEval())
12465 * 2) Add a predicate evaluation information stack to the
12466 * context struct
12467 * 3) Change the way the operators are linked; we need a
12468 * "parent" field on xmlXPathStepOp
12469 *
12470 * For the moment, I'll try to solve this with a recursive
12471 * function: xmlXPathCompOpEvalPredicate().
12472 */
12473 if (hasPredicateRange != 0)
12474 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12475 hasNsNodes);
12476 else
12477 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12478 hasNsNodes);
12479
12480 if (ctxt->error != XPATH_EXPRESSION_OK) {
12481 total = 0;
12482 goto error;
12483 }
12484 }
12485
12486 if (seq->nodeNr > 0) {
12487 /*
12488 * Add to result set.
12489 */
12490 if (outSeq == NULL) {
12491 outSeq = seq;
12492 seq = NULL;
12493 } else {
12494 /* TODO: Check memory error. */
12495 outSeq = mergeAndClear(outSeq, seq);
12496 }
12497
12498 if (toBool)
12499 break;
12500 }
12501 }
12502
12503 error:
12504 if ((obj->boolval) && (obj->user != NULL)) {
12505 /*
12506 * QUESTION TODO: What does this do and why?
12507 * TODO: Do we have to do this also for the "error"
12508 * cleanup further down?
12509 */
12510 ctxt->value->boolval = 1;
12511 ctxt->value->user = obj->user;
12512 obj->user = NULL;
12513 obj->boolval = 0;
12514 }
12515 xmlXPathReleaseObject(xpctxt, obj);
12516
12517 /*
12518 * Ensure we return at least an empty set.
12519 */
12520 if (outSeq == NULL) {
12521 if ((seq != NULL) && (seq->nodeNr == 0))
12522 outSeq = seq;
12523 else
12524 /* TODO: Check memory error. */
12525 outSeq = xmlXPathNodeSetCreate(NULL);
12526 }
12527 if ((seq != NULL) && (seq != outSeq)) {
12528 xmlXPathFreeNodeSet(seq);
12529 }
12530 /*
12531 * Hand over the result. Better to push the set also in
12532 * case of errors.
12533 */
12534 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12535 /*
12536 * Reset the context node.
12537 */
12538 xpctxt->node = oldContextNode;
12539 /*
12540 * When traversing the namespace axis in "toBool" mode, it's
12541 * possible that tmpNsList wasn't freed.
12542 */
12543 if (xpctxt->tmpNsList != NULL) {
12544 xmlFree(xpctxt->tmpNsList);
12545 xpctxt->tmpNsList = NULL;
12546 }
12547
12548 #ifdef DEBUG_STEP
12549 xmlGenericError(xmlGenericErrorContext,
12550 "\nExamined %d nodes, found %d nodes at that step\n",
12551 total, nbMatches);
12552 #endif
12553
12554 return(total);
12555 }
12556
12557 static int
12558 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12559 xmlXPathStepOpPtr op, xmlNodePtr * first);
12560
12561 /**
12562 * xmlXPathCompOpEvalFirst:
12563 * @ctxt: the XPath parser context with the compiled expression
12564 * @op: an XPath compiled operation
12565 * @first: the first elem found so far
12566 *
12567 * Evaluate the Precompiled XPath operation searching only the first
12568 * element in document order
12569 *
12570 * Returns the number of examined objects.
12571 */
12572 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12573 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12574 xmlXPathStepOpPtr op, xmlNodePtr * first)
12575 {
12576 int total = 0, cur;
12577 xmlXPathCompExprPtr comp;
12578 xmlXPathObjectPtr arg1, arg2;
12579
12580 CHECK_ERROR0;
12581 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12582 return(0);
12583 if (ctxt->context->depth >= ctxt->context->maxDepth)
12584 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12585 ctxt->context->depth += 1;
12586 comp = ctxt->comp;
12587 switch (op->op) {
12588 case XPATH_OP_END:
12589 break;
12590 case XPATH_OP_UNION:
12591 total =
12592 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12593 first);
12594 CHECK_ERROR0;
12595 if ((ctxt->value != NULL)
12596 && (ctxt->value->type == XPATH_NODESET)
12597 && (ctxt->value->nodesetval != NULL)
12598 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12599 /*
12600 * limit tree traversing to first node in the result
12601 */
12602 /*
12603 * OPTIMIZE TODO: This implicitly sorts
12604 * the result, even if not needed. E.g. if the argument
12605 * of the count() function, no sorting is needed.
12606 * OPTIMIZE TODO: How do we know if the node-list wasn't
12607 * already sorted?
12608 */
12609 if (ctxt->value->nodesetval->nodeNr > 1)
12610 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12611 *first = ctxt->value->nodesetval->nodeTab[0];
12612 }
12613 cur =
12614 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12615 first);
12616 CHECK_ERROR0;
12617
12618 arg2 = valuePop(ctxt);
12619 arg1 = valuePop(ctxt);
12620 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12621 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12622 xmlXPathReleaseObject(ctxt->context, arg1);
12623 xmlXPathReleaseObject(ctxt->context, arg2);
12624 XP_ERROR0(XPATH_INVALID_TYPE);
12625 }
12626 if ((ctxt->context->opLimit != 0) &&
12627 (((arg1->nodesetval != NULL) &&
12628 (xmlXPathCheckOpLimit(ctxt,
12629 arg1->nodesetval->nodeNr) < 0)) ||
12630 ((arg2->nodesetval != NULL) &&
12631 (xmlXPathCheckOpLimit(ctxt,
12632 arg2->nodesetval->nodeNr) < 0)))) {
12633 xmlXPathReleaseObject(ctxt->context, arg1);
12634 xmlXPathReleaseObject(ctxt->context, arg2);
12635 break;
12636 }
12637
12638 /* TODO: Check memory error. */
12639 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12640 arg2->nodesetval);
12641 valuePush(ctxt, arg1);
12642 xmlXPathReleaseObject(ctxt->context, arg2);
12643 /* optimizer */
12644 if (total > cur)
12645 xmlXPathCompSwap(op);
12646 total += cur;
12647 break;
12648 case XPATH_OP_ROOT:
12649 xmlXPathRoot(ctxt);
12650 break;
12651 case XPATH_OP_NODE:
12652 if (op->ch1 != -1)
12653 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12654 CHECK_ERROR0;
12655 if (op->ch2 != -1)
12656 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12657 CHECK_ERROR0;
12658 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12659 ctxt->context->node));
12660 break;
12661 case XPATH_OP_COLLECT:{
12662 if (op->ch1 == -1)
12663 break;
12664
12665 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12666 CHECK_ERROR0;
12667
12668 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12669 break;
12670 }
12671 case XPATH_OP_VALUE:
12672 valuePush(ctxt,
12673 xmlXPathCacheObjectCopy(ctxt->context,
12674 (xmlXPathObjectPtr) op->value4));
12675 break;
12676 case XPATH_OP_SORT:
12677 if (op->ch1 != -1)
12678 total +=
12679 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12680 first);
12681 CHECK_ERROR0;
12682 if ((ctxt->value != NULL)
12683 && (ctxt->value->type == XPATH_NODESET)
12684 && (ctxt->value->nodesetval != NULL)
12685 && (ctxt->value->nodesetval->nodeNr > 1))
12686 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12687 break;
12688 #ifdef XP_OPTIMIZED_FILTER_FIRST
12689 case XPATH_OP_FILTER:
12690 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12691 break;
12692 #endif
12693 default:
12694 total += xmlXPathCompOpEval(ctxt, op);
12695 break;
12696 }
12697
12698 ctxt->context->depth -= 1;
12699 return(total);
12700 }
12701
12702 /**
12703 * xmlXPathCompOpEvalLast:
12704 * @ctxt: the XPath parser context with the compiled expression
12705 * @op: an XPath compiled operation
12706 * @last: the last elem found so far
12707 *
12708 * Evaluate the Precompiled XPath operation searching only the last
12709 * element in document order
12710 *
12711 * Returns the number of nodes traversed
12712 */
12713 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12714 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12715 xmlNodePtr * last)
12716 {
12717 int total = 0, cur;
12718 xmlXPathCompExprPtr comp;
12719 xmlXPathObjectPtr arg1, arg2;
12720
12721 CHECK_ERROR0;
12722 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12723 return(0);
12724 if (ctxt->context->depth >= ctxt->context->maxDepth)
12725 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12726 ctxt->context->depth += 1;
12727 comp = ctxt->comp;
12728 switch (op->op) {
12729 case XPATH_OP_END:
12730 break;
12731 case XPATH_OP_UNION:
12732 total =
12733 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12734 CHECK_ERROR0;
12735 if ((ctxt->value != NULL)
12736 && (ctxt->value->type == XPATH_NODESET)
12737 && (ctxt->value->nodesetval != NULL)
12738 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12739 /*
12740 * limit tree traversing to first node in the result
12741 */
12742 if (ctxt->value->nodesetval->nodeNr > 1)
12743 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12744 *last =
12745 ctxt->value->nodesetval->nodeTab[ctxt->value->
12746 nodesetval->nodeNr -
12747 1];
12748 }
12749 cur =
12750 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12751 CHECK_ERROR0;
12752 if ((ctxt->value != NULL)
12753 && (ctxt->value->type == XPATH_NODESET)
12754 && (ctxt->value->nodesetval != NULL)
12755 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12756 }
12757
12758 arg2 = valuePop(ctxt);
12759 arg1 = valuePop(ctxt);
12760 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12761 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12762 xmlXPathReleaseObject(ctxt->context, arg1);
12763 xmlXPathReleaseObject(ctxt->context, arg2);
12764 XP_ERROR0(XPATH_INVALID_TYPE);
12765 }
12766 if ((ctxt->context->opLimit != 0) &&
12767 (((arg1->nodesetval != NULL) &&
12768 (xmlXPathCheckOpLimit(ctxt,
12769 arg1->nodesetval->nodeNr) < 0)) ||
12770 ((arg2->nodesetval != NULL) &&
12771 (xmlXPathCheckOpLimit(ctxt,
12772 arg2->nodesetval->nodeNr) < 0)))) {
12773 xmlXPathReleaseObject(ctxt->context, arg1);
12774 xmlXPathReleaseObject(ctxt->context, arg2);
12775 break;
12776 }
12777
12778 /* TODO: Check memory error. */
12779 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12780 arg2->nodesetval);
12781 valuePush(ctxt, arg1);
12782 xmlXPathReleaseObject(ctxt->context, arg2);
12783 /* optimizer */
12784 if (total > cur)
12785 xmlXPathCompSwap(op);
12786 total += cur;
12787 break;
12788 case XPATH_OP_ROOT:
12789 xmlXPathRoot(ctxt);
12790 break;
12791 case XPATH_OP_NODE:
12792 if (op->ch1 != -1)
12793 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12794 CHECK_ERROR0;
12795 if (op->ch2 != -1)
12796 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12797 CHECK_ERROR0;
12798 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12799 ctxt->context->node));
12800 break;
12801 case XPATH_OP_COLLECT:{
12802 if (op->ch1 == -1)
12803 break;
12804
12805 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12806 CHECK_ERROR0;
12807
12808 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12809 break;
12810 }
12811 case XPATH_OP_VALUE:
12812 valuePush(ctxt,
12813 xmlXPathCacheObjectCopy(ctxt->context,
12814 (xmlXPathObjectPtr) op->value4));
12815 break;
12816 case XPATH_OP_SORT:
12817 if (op->ch1 != -1)
12818 total +=
12819 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12820 last);
12821 CHECK_ERROR0;
12822 if ((ctxt->value != NULL)
12823 && (ctxt->value->type == XPATH_NODESET)
12824 && (ctxt->value->nodesetval != NULL)
12825 && (ctxt->value->nodesetval->nodeNr > 1))
12826 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12827 break;
12828 default:
12829 total += xmlXPathCompOpEval(ctxt, op);
12830 break;
12831 }
12832
12833 ctxt->context->depth -= 1;
12834 return (total);
12835 }
12836
12837 #ifdef XP_OPTIMIZED_FILTER_FIRST
12838 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12839 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12840 xmlXPathStepOpPtr op, xmlNodePtr * first)
12841 {
12842 int total = 0;
12843 xmlXPathCompExprPtr comp;
12844 xmlNodeSetPtr set;
12845
12846 CHECK_ERROR0;
12847 comp = ctxt->comp;
12848 /*
12849 * Optimization for ()[last()] selection i.e. the last elem
12850 */
12851 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12852 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12853 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12854 int f = comp->steps[op->ch2].ch1;
12855
12856 if ((f != -1) &&
12857 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12858 (comp->steps[f].value5 == NULL) &&
12859 (comp->steps[f].value == 0) &&
12860 (comp->steps[f].value4 != NULL) &&
12861 (xmlStrEqual
12862 (comp->steps[f].value4, BAD_CAST "last"))) {
12863 xmlNodePtr last = NULL;
12864
12865 total +=
12866 xmlXPathCompOpEvalLast(ctxt,
12867 &comp->steps[op->ch1],
12868 &last);
12869 CHECK_ERROR0;
12870 /*
12871 * The nodeset should be in document order,
12872 * Keep only the last value
12873 */
12874 if ((ctxt->value != NULL) &&
12875 (ctxt->value->type == XPATH_NODESET) &&
12876 (ctxt->value->nodesetval != NULL) &&
12877 (ctxt->value->nodesetval->nodeTab != NULL) &&
12878 (ctxt->value->nodesetval->nodeNr > 1)) {
12879 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12880 *first = *(ctxt->value->nodesetval->nodeTab);
12881 }
12882 return (total);
12883 }
12884 }
12885
12886 if (op->ch1 != -1)
12887 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12888 CHECK_ERROR0;
12889 if (op->ch2 == -1)
12890 return (total);
12891 if (ctxt->value == NULL)
12892 return (total);
12893
12894 #ifdef LIBXML_XPTR_ENABLED
12895 /*
12896 * Hum are we filtering the result of an XPointer expression
12897 */
12898 if (ctxt->value->type == XPATH_LOCATIONSET) {
12899 xmlLocationSetPtr locset = ctxt->value->user;
12900
12901 if (locset != NULL) {
12902 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12903 if (locset->locNr > 0)
12904 *first = (xmlNodePtr) locset->locTab[0]->user;
12905 }
12906
12907 return (total);
12908 }
12909 #endif /* LIBXML_XPTR_ENABLED */
12910
12911 CHECK_TYPE0(XPATH_NODESET);
12912 set = ctxt->value->nodesetval;
12913 if (set != NULL) {
12914 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12915 if (set->nodeNr > 0)
12916 *first = set->nodeTab[0];
12917 }
12918
12919 return (total);
12920 }
12921 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12922
12923 /**
12924 * xmlXPathCompOpEval:
12925 * @ctxt: the XPath parser context with the compiled expression
12926 * @op: an XPath compiled operation
12927 *
12928 * Evaluate the Precompiled XPath operation
12929 * Returns the number of nodes traversed
12930 */
12931 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)12932 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12933 {
12934 int total = 0;
12935 int equal, ret;
12936 xmlXPathCompExprPtr comp;
12937 xmlXPathObjectPtr arg1, arg2;
12938
12939 CHECK_ERROR0;
12940 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12941 return(0);
12942 if (ctxt->context->depth >= ctxt->context->maxDepth)
12943 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12944 ctxt->context->depth += 1;
12945 comp = ctxt->comp;
12946 switch (op->op) {
12947 case XPATH_OP_END:
12948 break;
12949 case XPATH_OP_AND:
12950 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12951 CHECK_ERROR0;
12952 xmlXPathBooleanFunction(ctxt, 1);
12953 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12954 break;
12955 arg2 = valuePop(ctxt);
12956 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12957 if (ctxt->error) {
12958 xmlXPathFreeObject(arg2);
12959 break;
12960 }
12961 xmlXPathBooleanFunction(ctxt, 1);
12962 if (ctxt->value != NULL)
12963 ctxt->value->boolval &= arg2->boolval;
12964 xmlXPathReleaseObject(ctxt->context, arg2);
12965 break;
12966 case XPATH_OP_OR:
12967 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12968 CHECK_ERROR0;
12969 xmlXPathBooleanFunction(ctxt, 1);
12970 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12971 break;
12972 arg2 = valuePop(ctxt);
12973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12974 if (ctxt->error) {
12975 xmlXPathFreeObject(arg2);
12976 break;
12977 }
12978 xmlXPathBooleanFunction(ctxt, 1);
12979 if (ctxt->value != NULL)
12980 ctxt->value->boolval |= arg2->boolval;
12981 xmlXPathReleaseObject(ctxt->context, arg2);
12982 break;
12983 case XPATH_OP_EQUAL:
12984 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12985 CHECK_ERROR0;
12986 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12987 CHECK_ERROR0;
12988 if (op->value)
12989 equal = xmlXPathEqualValues(ctxt);
12990 else
12991 equal = xmlXPathNotEqualValues(ctxt);
12992 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12993 break;
12994 case XPATH_OP_CMP:
12995 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12996 CHECK_ERROR0;
12997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12998 CHECK_ERROR0;
12999 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13000 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13001 break;
13002 case XPATH_OP_PLUS:
13003 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13004 CHECK_ERROR0;
13005 if (op->ch2 != -1) {
13006 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13007 }
13008 CHECK_ERROR0;
13009 if (op->value == 0)
13010 xmlXPathSubValues(ctxt);
13011 else if (op->value == 1)
13012 xmlXPathAddValues(ctxt);
13013 else if (op->value == 2)
13014 xmlXPathValueFlipSign(ctxt);
13015 else if (op->value == 3) {
13016 CAST_TO_NUMBER;
13017 CHECK_TYPE0(XPATH_NUMBER);
13018 }
13019 break;
13020 case XPATH_OP_MULT:
13021 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13022 CHECK_ERROR0;
13023 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13024 CHECK_ERROR0;
13025 if (op->value == 0)
13026 xmlXPathMultValues(ctxt);
13027 else if (op->value == 1)
13028 xmlXPathDivValues(ctxt);
13029 else if (op->value == 2)
13030 xmlXPathModValues(ctxt);
13031 break;
13032 case XPATH_OP_UNION:
13033 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13034 CHECK_ERROR0;
13035 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13036 CHECK_ERROR0;
13037
13038 arg2 = valuePop(ctxt);
13039 arg1 = valuePop(ctxt);
13040 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13041 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13042 xmlXPathReleaseObject(ctxt->context, arg1);
13043 xmlXPathReleaseObject(ctxt->context, arg2);
13044 XP_ERROR0(XPATH_INVALID_TYPE);
13045 }
13046 if ((ctxt->context->opLimit != 0) &&
13047 (((arg1->nodesetval != NULL) &&
13048 (xmlXPathCheckOpLimit(ctxt,
13049 arg1->nodesetval->nodeNr) < 0)) ||
13050 ((arg2->nodesetval != NULL) &&
13051 (xmlXPathCheckOpLimit(ctxt,
13052 arg2->nodesetval->nodeNr) < 0)))) {
13053 xmlXPathReleaseObject(ctxt->context, arg1);
13054 xmlXPathReleaseObject(ctxt->context, arg2);
13055 break;
13056 }
13057
13058 if ((arg1->nodesetval == NULL) ||
13059 ((arg2->nodesetval != NULL) &&
13060 (arg2->nodesetval->nodeNr != 0)))
13061 {
13062 /* TODO: Check memory error. */
13063 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13064 arg2->nodesetval);
13065 }
13066
13067 valuePush(ctxt, arg1);
13068 xmlXPathReleaseObject(ctxt->context, arg2);
13069 break;
13070 case XPATH_OP_ROOT:
13071 xmlXPathRoot(ctxt);
13072 break;
13073 case XPATH_OP_NODE:
13074 if (op->ch1 != -1)
13075 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13076 CHECK_ERROR0;
13077 if (op->ch2 != -1)
13078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13079 CHECK_ERROR0;
13080 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13081 ctxt->context->node));
13082 break;
13083 case XPATH_OP_COLLECT:{
13084 if (op->ch1 == -1)
13085 break;
13086
13087 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13088 CHECK_ERROR0;
13089
13090 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13091 break;
13092 }
13093 case XPATH_OP_VALUE:
13094 valuePush(ctxt,
13095 xmlXPathCacheObjectCopy(ctxt->context,
13096 (xmlXPathObjectPtr) op->value4));
13097 break;
13098 case XPATH_OP_VARIABLE:{
13099 xmlXPathObjectPtr val;
13100
13101 if (op->ch1 != -1)
13102 total +=
13103 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13104 if (op->value5 == NULL) {
13105 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13106 if (val == NULL)
13107 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13108 valuePush(ctxt, val);
13109 } else {
13110 const xmlChar *URI;
13111
13112 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13113 if (URI == NULL) {
13114 xmlGenericError(xmlGenericErrorContext,
13115 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13116 (char *) op->value4, (char *)op->value5);
13117 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13118 break;
13119 }
13120 val = xmlXPathVariableLookupNS(ctxt->context,
13121 op->value4, URI);
13122 if (val == NULL)
13123 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13124 valuePush(ctxt, val);
13125 }
13126 break;
13127 }
13128 case XPATH_OP_FUNCTION:{
13129 xmlXPathFunction func;
13130 const xmlChar *oldFunc, *oldFuncURI;
13131 int i;
13132 int frame;
13133
13134 frame = xmlXPathSetFrame(ctxt);
13135 if (op->ch1 != -1) {
13136 total +=
13137 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13138 if (ctxt->error != XPATH_EXPRESSION_OK) {
13139 xmlXPathPopFrame(ctxt, frame);
13140 break;
13141 }
13142 }
13143 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13144 xmlGenericError(xmlGenericErrorContext,
13145 "xmlXPathCompOpEval: parameter error\n");
13146 ctxt->error = XPATH_INVALID_OPERAND;
13147 xmlXPathPopFrame(ctxt, frame);
13148 break;
13149 }
13150 for (i = 0; i < op->value; i++) {
13151 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13152 xmlGenericError(xmlGenericErrorContext,
13153 "xmlXPathCompOpEval: parameter error\n");
13154 ctxt->error = XPATH_INVALID_OPERAND;
13155 xmlXPathPopFrame(ctxt, frame);
13156 break;
13157 }
13158 }
13159 if (op->cache != NULL)
13160 func = op->cache;
13161 else {
13162 const xmlChar *URI = NULL;
13163
13164 if (op->value5 == NULL)
13165 func =
13166 xmlXPathFunctionLookup(ctxt->context,
13167 op->value4);
13168 else {
13169 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13170 if (URI == NULL) {
13171 xmlGenericError(xmlGenericErrorContext,
13172 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13173 (char *)op->value4, (char *)op->value5);
13174 xmlXPathPopFrame(ctxt, frame);
13175 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13176 break;
13177 }
13178 func = xmlXPathFunctionLookupNS(ctxt->context,
13179 op->value4, URI);
13180 }
13181 if (func == NULL) {
13182 xmlGenericError(xmlGenericErrorContext,
13183 "xmlXPathCompOpEval: function %s not found\n",
13184 (char *)op->value4);
13185 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13186 }
13187 op->cache = func;
13188 op->cacheURI = (void *) URI;
13189 }
13190 oldFunc = ctxt->context->function;
13191 oldFuncURI = ctxt->context->functionURI;
13192 ctxt->context->function = op->value4;
13193 ctxt->context->functionURI = op->cacheURI;
13194 func(ctxt, op->value);
13195 ctxt->context->function = oldFunc;
13196 ctxt->context->functionURI = oldFuncURI;
13197 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13198 (ctxt->valueNr != ctxt->valueFrame + 1))
13199 XP_ERROR0(XPATH_STACK_ERROR);
13200 xmlXPathPopFrame(ctxt, frame);
13201 break;
13202 }
13203 case XPATH_OP_ARG:
13204 if (op->ch1 != -1) {
13205 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13206 CHECK_ERROR0;
13207 }
13208 if (op->ch2 != -1) {
13209 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13210 CHECK_ERROR0;
13211 }
13212 break;
13213 case XPATH_OP_PREDICATE:
13214 case XPATH_OP_FILTER:{
13215 xmlNodeSetPtr set;
13216
13217 /*
13218 * Optimization for ()[1] selection i.e. the first elem
13219 */
13220 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13221 #ifdef XP_OPTIMIZED_FILTER_FIRST
13222 /*
13223 * FILTER TODO: Can we assume that the inner processing
13224 * will result in an ordered list if we have an
13225 * XPATH_OP_FILTER?
13226 * What about an additional field or flag on
13227 * xmlXPathObject like @sorted ? This way we wouldn't need
13228 * to assume anything, so it would be more robust and
13229 * easier to optimize.
13230 */
13231 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13232 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13233 #else
13234 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13235 #endif
13236 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13237 xmlXPathObjectPtr val;
13238
13239 val = comp->steps[op->ch2].value4;
13240 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13241 (val->floatval == 1.0)) {
13242 xmlNodePtr first = NULL;
13243
13244 total +=
13245 xmlXPathCompOpEvalFirst(ctxt,
13246 &comp->steps[op->ch1],
13247 &first);
13248 CHECK_ERROR0;
13249 /*
13250 * The nodeset should be in document order,
13251 * Keep only the first value
13252 */
13253 if ((ctxt->value != NULL) &&
13254 (ctxt->value->type == XPATH_NODESET) &&
13255 (ctxt->value->nodesetval != NULL) &&
13256 (ctxt->value->nodesetval->nodeNr > 1))
13257 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13258 1, 1);
13259 break;
13260 }
13261 }
13262 /*
13263 * Optimization for ()[last()] selection i.e. the last elem
13264 */
13265 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13266 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13267 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13268 int f = comp->steps[op->ch2].ch1;
13269
13270 if ((f != -1) &&
13271 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13272 (comp->steps[f].value5 == NULL) &&
13273 (comp->steps[f].value == 0) &&
13274 (comp->steps[f].value4 != NULL) &&
13275 (xmlStrEqual
13276 (comp->steps[f].value4, BAD_CAST "last"))) {
13277 xmlNodePtr last = NULL;
13278
13279 total +=
13280 xmlXPathCompOpEvalLast(ctxt,
13281 &comp->steps[op->ch1],
13282 &last);
13283 CHECK_ERROR0;
13284 /*
13285 * The nodeset should be in document order,
13286 * Keep only the last value
13287 */
13288 if ((ctxt->value != NULL) &&
13289 (ctxt->value->type == XPATH_NODESET) &&
13290 (ctxt->value->nodesetval != NULL) &&
13291 (ctxt->value->nodesetval->nodeTab != NULL) &&
13292 (ctxt->value->nodesetval->nodeNr > 1))
13293 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13294 break;
13295 }
13296 }
13297 /*
13298 * Process inner predicates first.
13299 * Example "index[parent::book][1]":
13300 * ...
13301 * PREDICATE <-- we are here "[1]"
13302 * PREDICATE <-- process "[parent::book]" first
13303 * SORT
13304 * COLLECT 'parent' 'name' 'node' book
13305 * NODE
13306 * ELEM Object is a number : 1
13307 */
13308 if (op->ch1 != -1)
13309 total +=
13310 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13311 CHECK_ERROR0;
13312 if (op->ch2 == -1)
13313 break;
13314 if (ctxt->value == NULL)
13315 break;
13316
13317 #ifdef LIBXML_XPTR_ENABLED
13318 /*
13319 * Hum are we filtering the result of an XPointer expression
13320 */
13321 if (ctxt->value->type == XPATH_LOCATIONSET) {
13322 xmlLocationSetPtr locset = ctxt->value->user;
13323 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13324 1, locset->locNr);
13325 break;
13326 }
13327 #endif /* LIBXML_XPTR_ENABLED */
13328
13329 CHECK_TYPE0(XPATH_NODESET);
13330 set = ctxt->value->nodesetval;
13331 if (set != NULL)
13332 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13333 1, set->nodeNr, 1);
13334 break;
13335 }
13336 case XPATH_OP_SORT:
13337 if (op->ch1 != -1)
13338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339 CHECK_ERROR0;
13340 if ((ctxt->value != NULL) &&
13341 (ctxt->value->type == XPATH_NODESET) &&
13342 (ctxt->value->nodesetval != NULL) &&
13343 (ctxt->value->nodesetval->nodeNr > 1))
13344 {
13345 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13346 }
13347 break;
13348 #ifdef LIBXML_XPTR_ENABLED
13349 case XPATH_OP_RANGETO:{
13350 xmlXPathObjectPtr range;
13351 xmlXPathObjectPtr res, obj;
13352 xmlXPathObjectPtr tmp;
13353 xmlLocationSetPtr newlocset = NULL;
13354 xmlLocationSetPtr oldlocset;
13355 xmlNodeSetPtr oldset;
13356 xmlNodePtr oldnode = ctxt->context->node;
13357 int oldcs = ctxt->context->contextSize;
13358 int oldpp = ctxt->context->proximityPosition;
13359 int i, j;
13360
13361 if (op->ch1 != -1) {
13362 total +=
13363 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13364 CHECK_ERROR0;
13365 }
13366 if (ctxt->value == NULL) {
13367 XP_ERROR0(XPATH_INVALID_OPERAND);
13368 }
13369 if (op->ch2 == -1)
13370 break;
13371
13372 if (ctxt->value->type == XPATH_LOCATIONSET) {
13373 /*
13374 * Extract the old locset, and then evaluate the result of the
13375 * expression for all the element in the locset. use it to grow
13376 * up a new locset.
13377 */
13378 CHECK_TYPE0(XPATH_LOCATIONSET);
13379
13380 if ((ctxt->value->user == NULL) ||
13381 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13382 break;
13383
13384 obj = valuePop(ctxt);
13385 oldlocset = obj->user;
13386
13387 newlocset = xmlXPtrLocationSetCreate(NULL);
13388
13389 for (i = 0; i < oldlocset->locNr; i++) {
13390 /*
13391 * Run the evaluation with a node list made of a
13392 * single item in the nodelocset.
13393 */
13394 ctxt->context->node = oldlocset->locTab[i]->user;
13395 ctxt->context->contextSize = oldlocset->locNr;
13396 ctxt->context->proximityPosition = i + 1;
13397 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13398 ctxt->context->node);
13399 valuePush(ctxt, tmp);
13400
13401 if (op->ch2 != -1)
13402 total +=
13403 xmlXPathCompOpEval(ctxt,
13404 &comp->steps[op->ch2]);
13405 if (ctxt->error != XPATH_EXPRESSION_OK) {
13406 xmlXPtrFreeLocationSet(newlocset);
13407 goto rangeto_error;
13408 }
13409
13410 res = valuePop(ctxt);
13411 if (res->type == XPATH_LOCATIONSET) {
13412 xmlLocationSetPtr rloc =
13413 (xmlLocationSetPtr)res->user;
13414 for (j=0; j<rloc->locNr; j++) {
13415 range = xmlXPtrNewRange(
13416 oldlocset->locTab[i]->user,
13417 oldlocset->locTab[i]->index,
13418 rloc->locTab[j]->user2,
13419 rloc->locTab[j]->index2);
13420 if (range != NULL) {
13421 xmlXPtrLocationSetAdd(newlocset, range);
13422 }
13423 }
13424 } else {
13425 range = xmlXPtrNewRangeNodeObject(
13426 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13427 if (range != NULL) {
13428 xmlXPtrLocationSetAdd(newlocset,range);
13429 }
13430 }
13431
13432 /*
13433 * Cleanup
13434 */
13435 if (res != NULL) {
13436 xmlXPathReleaseObject(ctxt->context, res);
13437 }
13438 if (ctxt->value == tmp) {
13439 res = valuePop(ctxt);
13440 xmlXPathReleaseObject(ctxt->context, res);
13441 }
13442 }
13443 } else { /* Not a location set */
13444 CHECK_TYPE0(XPATH_NODESET);
13445 obj = valuePop(ctxt);
13446 oldset = obj->nodesetval;
13447
13448 newlocset = xmlXPtrLocationSetCreate(NULL);
13449
13450 if (oldset != NULL) {
13451 for (i = 0; i < oldset->nodeNr; i++) {
13452 /*
13453 * Run the evaluation with a node list made of a single item
13454 * in the nodeset.
13455 */
13456 ctxt->context->node = oldset->nodeTab[i];
13457 /*
13458 * OPTIMIZE TODO: Avoid recreation for every iteration.
13459 */
13460 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13461 ctxt->context->node);
13462 valuePush(ctxt, tmp);
13463
13464 if (op->ch2 != -1)
13465 total +=
13466 xmlXPathCompOpEval(ctxt,
13467 &comp->steps[op->ch2]);
13468 if (ctxt->error != XPATH_EXPRESSION_OK) {
13469 xmlXPtrFreeLocationSet(newlocset);
13470 goto rangeto_error;
13471 }
13472
13473 res = valuePop(ctxt);
13474 range =
13475 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13476 res);
13477 if (range != NULL) {
13478 xmlXPtrLocationSetAdd(newlocset, range);
13479 }
13480
13481 /*
13482 * Cleanup
13483 */
13484 if (res != NULL) {
13485 xmlXPathReleaseObject(ctxt->context, res);
13486 }
13487 if (ctxt->value == tmp) {
13488 res = valuePop(ctxt);
13489 xmlXPathReleaseObject(ctxt->context, res);
13490 }
13491 }
13492 }
13493 }
13494
13495 /*
13496 * The result is used as the new evaluation set.
13497 */
13498 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13499 rangeto_error:
13500 xmlXPathReleaseObject(ctxt->context, obj);
13501 ctxt->context->node = oldnode;
13502 ctxt->context->contextSize = oldcs;
13503 ctxt->context->proximityPosition = oldpp;
13504 break;
13505 }
13506 #endif /* LIBXML_XPTR_ENABLED */
13507 default:
13508 xmlGenericError(xmlGenericErrorContext,
13509 "XPath: unknown precompiled operation %d\n", op->op);
13510 ctxt->error = XPATH_INVALID_OPERAND;
13511 break;
13512 }
13513
13514 ctxt->context->depth -= 1;
13515 return (total);
13516 }
13517
13518 /**
13519 * xmlXPathCompOpEvalToBoolean:
13520 * @ctxt: the XPath parser context
13521 *
13522 * Evaluates if the expression evaluates to true.
13523 *
13524 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13525 */
13526 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13527 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13528 xmlXPathStepOpPtr op,
13529 int isPredicate)
13530 {
13531 xmlXPathObjectPtr resObj = NULL;
13532
13533 start:
13534 if (OP_LIMIT_EXCEEDED(ctxt, 1))
13535 return(0);
13536 /* comp = ctxt->comp; */
13537 switch (op->op) {
13538 case XPATH_OP_END:
13539 return (0);
13540 case XPATH_OP_VALUE:
13541 resObj = (xmlXPathObjectPtr) op->value4;
13542 if (isPredicate)
13543 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13544 return(xmlXPathCastToBoolean(resObj));
13545 case XPATH_OP_SORT:
13546 /*
13547 * We don't need sorting for boolean results. Skip this one.
13548 */
13549 if (op->ch1 != -1) {
13550 op = &ctxt->comp->steps[op->ch1];
13551 goto start;
13552 }
13553 return(0);
13554 case XPATH_OP_COLLECT:
13555 if (op->ch1 == -1)
13556 return(0);
13557
13558 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13559 if (ctxt->error != XPATH_EXPRESSION_OK)
13560 return(-1);
13561
13562 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13563 if (ctxt->error != XPATH_EXPRESSION_OK)
13564 return(-1);
13565
13566 resObj = valuePop(ctxt);
13567 if (resObj == NULL)
13568 return(-1);
13569 break;
13570 default:
13571 /*
13572 * Fallback to call xmlXPathCompOpEval().
13573 */
13574 xmlXPathCompOpEval(ctxt, op);
13575 if (ctxt->error != XPATH_EXPRESSION_OK)
13576 return(-1);
13577
13578 resObj = valuePop(ctxt);
13579 if (resObj == NULL)
13580 return(-1);
13581 break;
13582 }
13583
13584 if (resObj) {
13585 int res;
13586
13587 if (resObj->type == XPATH_BOOLEAN) {
13588 res = resObj->boolval;
13589 } else if (isPredicate) {
13590 /*
13591 * For predicates a result of type "number" is handled
13592 * differently:
13593 * SPEC XPath 1.0:
13594 * "If the result is a number, the result will be converted
13595 * to true if the number is equal to the context position
13596 * and will be converted to false otherwise;"
13597 */
13598 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13599 } else {
13600 res = xmlXPathCastToBoolean(resObj);
13601 }
13602 xmlXPathReleaseObject(ctxt->context, resObj);
13603 return(res);
13604 }
13605
13606 return(0);
13607 }
13608
13609 #ifdef XPATH_STREAMING
13610 /**
13611 * xmlXPathRunStreamEval:
13612 * @ctxt: the XPath parser context with the compiled expression
13613 *
13614 * Evaluate the Precompiled Streamable XPath expression in the given context.
13615 */
13616 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)13617 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13618 xmlXPathObjectPtr *resultSeq, int toBool)
13619 {
13620 int max_depth, min_depth;
13621 int from_root;
13622 int ret, depth;
13623 int eval_all_nodes;
13624 xmlNodePtr cur = NULL, limit = NULL;
13625 xmlStreamCtxtPtr patstream = NULL;
13626
13627 int nb_nodes = 0;
13628
13629 if ((ctxt == NULL) || (comp == NULL))
13630 return(-1);
13631 max_depth = xmlPatternMaxDepth(comp);
13632 if (max_depth == -1)
13633 return(-1);
13634 if (max_depth == -2)
13635 max_depth = 10000;
13636 min_depth = xmlPatternMinDepth(comp);
13637 if (min_depth == -1)
13638 return(-1);
13639 from_root = xmlPatternFromRoot(comp);
13640 if (from_root < 0)
13641 return(-1);
13642 #if 0
13643 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13644 #endif
13645
13646 if (! toBool) {
13647 if (resultSeq == NULL)
13648 return(-1);
13649 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13650 if (*resultSeq == NULL)
13651 return(-1);
13652 }
13653
13654 /*
13655 * handle the special cases of "/" amd "." being matched
13656 */
13657 if (min_depth == 0) {
13658 if (from_root) {
13659 /* Select "/" */
13660 if (toBool)
13661 return(1);
13662 /* TODO: Check memory error. */
13663 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13664 (xmlNodePtr) ctxt->doc);
13665 } else {
13666 /* Select "self::node()" */
13667 if (toBool)
13668 return(1);
13669 /* TODO: Check memory error. */
13670 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13671 }
13672 }
13673 if (max_depth == 0) {
13674 return(0);
13675 }
13676
13677 if (from_root) {
13678 cur = (xmlNodePtr)ctxt->doc;
13679 } else if (ctxt->node != NULL) {
13680 switch (ctxt->node->type) {
13681 case XML_ELEMENT_NODE:
13682 case XML_DOCUMENT_NODE:
13683 case XML_DOCUMENT_FRAG_NODE:
13684 case XML_HTML_DOCUMENT_NODE:
13685 #ifdef LIBXML_DOCB_ENABLED
13686 case XML_DOCB_DOCUMENT_NODE:
13687 #endif
13688 cur = ctxt->node;
13689 break;
13690 case XML_ATTRIBUTE_NODE:
13691 case XML_TEXT_NODE:
13692 case XML_CDATA_SECTION_NODE:
13693 case XML_ENTITY_REF_NODE:
13694 case XML_ENTITY_NODE:
13695 case XML_PI_NODE:
13696 case XML_COMMENT_NODE:
13697 case XML_NOTATION_NODE:
13698 case XML_DTD_NODE:
13699 case XML_DOCUMENT_TYPE_NODE:
13700 case XML_ELEMENT_DECL:
13701 case XML_ATTRIBUTE_DECL:
13702 case XML_ENTITY_DECL:
13703 case XML_NAMESPACE_DECL:
13704 case XML_XINCLUDE_START:
13705 case XML_XINCLUDE_END:
13706 break;
13707 }
13708 limit = cur;
13709 }
13710 if (cur == NULL) {
13711 return(0);
13712 }
13713
13714 patstream = xmlPatternGetStreamCtxt(comp);
13715 if (patstream == NULL) {
13716 /*
13717 * QUESTION TODO: Is this an error?
13718 */
13719 return(0);
13720 }
13721
13722 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13723
13724 if (from_root) {
13725 ret = xmlStreamPush(patstream, NULL, NULL);
13726 if (ret < 0) {
13727 } else if (ret == 1) {
13728 if (toBool)
13729 goto return_1;
13730 /* TODO: Check memory error. */
13731 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13732 }
13733 }
13734 depth = 0;
13735 goto scan_children;
13736 next_node:
13737 do {
13738 if (ctxt->opLimit != 0) {
13739 if (ctxt->opCount >= ctxt->opLimit) {
13740 xmlGenericError(xmlGenericErrorContext,
13741 "XPath operation limit exceeded\n");
13742 xmlFreeStreamCtxt(patstream);
13743 return(-1);
13744 }
13745 ctxt->opCount++;
13746 }
13747
13748 nb_nodes++;
13749
13750 switch (cur->type) {
13751 case XML_ELEMENT_NODE:
13752 case XML_TEXT_NODE:
13753 case XML_CDATA_SECTION_NODE:
13754 case XML_COMMENT_NODE:
13755 case XML_PI_NODE:
13756 if (cur->type == XML_ELEMENT_NODE) {
13757 ret = xmlStreamPush(patstream, cur->name,
13758 (cur->ns ? cur->ns->href : NULL));
13759 } else if (eval_all_nodes)
13760 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13761 else
13762 break;
13763
13764 if (ret < 0) {
13765 /* NOP. */
13766 } else if (ret == 1) {
13767 if (toBool)
13768 goto return_1;
13769 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13770 < 0) {
13771 ctxt->lastError.domain = XML_FROM_XPATH;
13772 ctxt->lastError.code = XML_ERR_NO_MEMORY;
13773 }
13774 }
13775 if ((cur->children == NULL) || (depth >= max_depth)) {
13776 ret = xmlStreamPop(patstream);
13777 while (cur->next != NULL) {
13778 cur = cur->next;
13779 if ((cur->type != XML_ENTITY_DECL) &&
13780 (cur->type != XML_DTD_NODE))
13781 goto next_node;
13782 }
13783 }
13784 default:
13785 break;
13786 }
13787
13788 scan_children:
13789 if (cur->type == XML_NAMESPACE_DECL) break;
13790 if ((cur->children != NULL) && (depth < max_depth)) {
13791 /*
13792 * Do not descend on entities declarations
13793 */
13794 if (cur->children->type != XML_ENTITY_DECL) {
13795 cur = cur->children;
13796 depth++;
13797 /*
13798 * Skip DTDs
13799 */
13800 if (cur->type != XML_DTD_NODE)
13801 continue;
13802 }
13803 }
13804
13805 if (cur == limit)
13806 break;
13807
13808 while (cur->next != NULL) {
13809 cur = cur->next;
13810 if ((cur->type != XML_ENTITY_DECL) &&
13811 (cur->type != XML_DTD_NODE))
13812 goto next_node;
13813 }
13814
13815 do {
13816 cur = cur->parent;
13817 depth--;
13818 if ((cur == NULL) || (cur == limit))
13819 goto done;
13820 if (cur->type == XML_ELEMENT_NODE) {
13821 ret = xmlStreamPop(patstream);
13822 } else if ((eval_all_nodes) &&
13823 ((cur->type == XML_TEXT_NODE) ||
13824 (cur->type == XML_CDATA_SECTION_NODE) ||
13825 (cur->type == XML_COMMENT_NODE) ||
13826 (cur->type == XML_PI_NODE)))
13827 {
13828 ret = xmlStreamPop(patstream);
13829 }
13830 if (cur->next != NULL) {
13831 cur = cur->next;
13832 break;
13833 }
13834 } while (cur != NULL);
13835
13836 } while ((cur != NULL) && (depth >= 0));
13837
13838 done:
13839
13840 #if 0
13841 printf("stream eval: checked %d nodes selected %d\n",
13842 nb_nodes, retObj->nodesetval->nodeNr);
13843 #endif
13844
13845 if (patstream)
13846 xmlFreeStreamCtxt(patstream);
13847 return(0);
13848
13849 return_1:
13850 if (patstream)
13851 xmlFreeStreamCtxt(patstream);
13852 return(1);
13853 }
13854 #endif /* XPATH_STREAMING */
13855
13856 /**
13857 * xmlXPathRunEval:
13858 * @ctxt: the XPath parser context with the compiled expression
13859 * @toBool: evaluate to a boolean result
13860 *
13861 * Evaluate the Precompiled XPath expression in the given context.
13862 */
13863 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)13864 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13865 {
13866 xmlXPathCompExprPtr comp;
13867
13868 if ((ctxt == NULL) || (ctxt->comp == NULL))
13869 return(-1);
13870
13871 ctxt->context->depth = 0;
13872
13873 if (ctxt->valueTab == NULL) {
13874 /* Allocate the value stack */
13875 ctxt->valueTab = (xmlXPathObjectPtr *)
13876 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13877 if (ctxt->valueTab == NULL) {
13878 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13879 xmlFree(ctxt);
13880 }
13881 ctxt->valueNr = 0;
13882 ctxt->valueMax = 10;
13883 ctxt->value = NULL;
13884 ctxt->valueFrame = 0;
13885 }
13886 #ifdef XPATH_STREAMING
13887 if (ctxt->comp->stream) {
13888 int res;
13889
13890 if (toBool) {
13891 /*
13892 * Evaluation to boolean result.
13893 */
13894 res = xmlXPathRunStreamEval(ctxt->context,
13895 ctxt->comp->stream, NULL, 1);
13896 if (res != -1)
13897 return(res);
13898 } else {
13899 xmlXPathObjectPtr resObj = NULL;
13900
13901 /*
13902 * Evaluation to a sequence.
13903 */
13904 res = xmlXPathRunStreamEval(ctxt->context,
13905 ctxt->comp->stream, &resObj, 0);
13906
13907 if ((res != -1) && (resObj != NULL)) {
13908 valuePush(ctxt, resObj);
13909 return(0);
13910 }
13911 if (resObj != NULL)
13912 xmlXPathReleaseObject(ctxt->context, resObj);
13913 }
13914 /*
13915 * QUESTION TODO: This falls back to normal XPath evaluation
13916 * if res == -1. Is this intended?
13917 */
13918 }
13919 #endif
13920 comp = ctxt->comp;
13921 if (comp->last < 0) {
13922 xmlGenericError(xmlGenericErrorContext,
13923 "xmlXPathRunEval: last is less than zero\n");
13924 return(-1);
13925 }
13926 if (toBool)
13927 return(xmlXPathCompOpEvalToBoolean(ctxt,
13928 &comp->steps[comp->last], 0));
13929 else
13930 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13931
13932 return(0);
13933 }
13934
13935 /************************************************************************
13936 * *
13937 * Public interfaces *
13938 * *
13939 ************************************************************************/
13940
13941 /**
13942 * xmlXPathEvalPredicate:
13943 * @ctxt: the XPath context
13944 * @res: the Predicate Expression evaluation result
13945 *
13946 * Evaluate a predicate result for the current node.
13947 * A PredicateExpr is evaluated by evaluating the Expr and converting
13948 * the result to a boolean. If the result is a number, the result will
13949 * be converted to true if the number is equal to the position of the
13950 * context node in the context node list (as returned by the position
13951 * function) and will be converted to false otherwise; if the result
13952 * is not a number, then the result will be converted as if by a call
13953 * to the boolean function.
13954 *
13955 * Returns 1 if predicate is true, 0 otherwise
13956 */
13957 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)13958 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13959 if ((ctxt == NULL) || (res == NULL)) return(0);
13960 switch (res->type) {
13961 case XPATH_BOOLEAN:
13962 return(res->boolval);
13963 case XPATH_NUMBER:
13964 return(res->floatval == ctxt->proximityPosition);
13965 case XPATH_NODESET:
13966 case XPATH_XSLT_TREE:
13967 if (res->nodesetval == NULL)
13968 return(0);
13969 return(res->nodesetval->nodeNr != 0);
13970 case XPATH_STRING:
13971 return((res->stringval != NULL) &&
13972 (xmlStrlen(res->stringval) != 0));
13973 default:
13974 STRANGE
13975 }
13976 return(0);
13977 }
13978
13979 /**
13980 * xmlXPathEvaluatePredicateResult:
13981 * @ctxt: the XPath Parser context
13982 * @res: the Predicate Expression evaluation result
13983 *
13984 * Evaluate a predicate result for the current node.
13985 * A PredicateExpr is evaluated by evaluating the Expr and converting
13986 * the result to a boolean. If the result is a number, the result will
13987 * be converted to true if the number is equal to the position of the
13988 * context node in the context node list (as returned by the position
13989 * function) and will be converted to false otherwise; if the result
13990 * is not a number, then the result will be converted as if by a call
13991 * to the boolean function.
13992 *
13993 * Returns 1 if predicate is true, 0 otherwise
13994 */
13995 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)13996 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13997 xmlXPathObjectPtr res) {
13998 if ((ctxt == NULL) || (res == NULL)) return(0);
13999 switch (res->type) {
14000 case XPATH_BOOLEAN:
14001 return(res->boolval);
14002 case XPATH_NUMBER:
14003 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14004 return((res->floatval == ctxt->context->proximityPosition) &&
14005 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14006 #else
14007 return(res->floatval == ctxt->context->proximityPosition);
14008 #endif
14009 case XPATH_NODESET:
14010 case XPATH_XSLT_TREE:
14011 if (res->nodesetval == NULL)
14012 return(0);
14013 return(res->nodesetval->nodeNr != 0);
14014 case XPATH_STRING:
14015 return((res->stringval != NULL) && (res->stringval[0] != 0));
14016 #ifdef LIBXML_XPTR_ENABLED
14017 case XPATH_LOCATIONSET:{
14018 xmlLocationSetPtr ptr = res->user;
14019 if (ptr == NULL)
14020 return(0);
14021 return (ptr->locNr != 0);
14022 }
14023 #endif
14024 default:
14025 STRANGE
14026 }
14027 return(0);
14028 }
14029
14030 #ifdef XPATH_STREAMING
14031 /**
14032 * xmlXPathTryStreamCompile:
14033 * @ctxt: an XPath context
14034 * @str: the XPath expression
14035 *
14036 * Try to compile the XPath expression as a streamable subset.
14037 *
14038 * Returns the compiled expression or NULL if failed to compile.
14039 */
14040 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14041 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14042 /*
14043 * Optimization: use streaming patterns when the XPath expression can
14044 * be compiled to a stream lookup
14045 */
14046 xmlPatternPtr stream;
14047 xmlXPathCompExprPtr comp;
14048 xmlDictPtr dict = NULL;
14049 const xmlChar **namespaces = NULL;
14050 xmlNsPtr ns;
14051 int i, j;
14052
14053 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14054 (!xmlStrchr(str, '@'))) {
14055 const xmlChar *tmp;
14056
14057 /*
14058 * We don't try to handle expressions using the verbose axis
14059 * specifiers ("::"), just the simplified form at this point.
14060 * Additionally, if there is no list of namespaces available and
14061 * there's a ":" in the expression, indicating a prefixed QName,
14062 * then we won't try to compile either. xmlPatterncompile() needs
14063 * to have a list of namespaces at compilation time in order to
14064 * compile prefixed name tests.
14065 */
14066 tmp = xmlStrchr(str, ':');
14067 if ((tmp != NULL) &&
14068 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14069 return(NULL);
14070
14071 if (ctxt != NULL) {
14072 dict = ctxt->dict;
14073 if (ctxt->nsNr > 0) {
14074 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14075 if (namespaces == NULL) {
14076 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14077 return(NULL);
14078 }
14079 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14080 ns = ctxt->namespaces[j];
14081 namespaces[i++] = ns->href;
14082 namespaces[i++] = ns->prefix;
14083 }
14084 namespaces[i++] = NULL;
14085 namespaces[i] = NULL;
14086 }
14087 }
14088
14089 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14090 &namespaces[0]);
14091 if (namespaces != NULL) {
14092 xmlFree((xmlChar **)namespaces);
14093 }
14094 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14095 comp = xmlXPathNewCompExpr();
14096 if (comp == NULL) {
14097 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14098 return(NULL);
14099 }
14100 comp->stream = stream;
14101 comp->dict = dict;
14102 if (comp->dict)
14103 xmlDictReference(comp->dict);
14104 return(comp);
14105 }
14106 xmlFreePattern(stream);
14107 }
14108 return(NULL);
14109 }
14110 #endif /* XPATH_STREAMING */
14111
14112 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)14113 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14114 xmlXPathStepOpPtr op)
14115 {
14116 xmlXPathCompExprPtr comp = pctxt->comp;
14117 xmlXPathContextPtr ctxt;
14118
14119 /*
14120 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14121 * internal representation.
14122 */
14123
14124 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14125 (op->ch1 != -1) &&
14126 (op->ch2 == -1 /* no predicate */))
14127 {
14128 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14129
14130 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14131 ((xmlXPathAxisVal) prevop->value ==
14132 AXIS_DESCENDANT_OR_SELF) &&
14133 (prevop->ch2 == -1) &&
14134 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14135 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14136 {
14137 /*
14138 * This is a "descendant-or-self::node()" without predicates.
14139 * Try to eliminate it.
14140 */
14141
14142 switch ((xmlXPathAxisVal) op->value) {
14143 case AXIS_CHILD:
14144 case AXIS_DESCENDANT:
14145 /*
14146 * Convert "descendant-or-self::node()/child::" or
14147 * "descendant-or-self::node()/descendant::" to
14148 * "descendant::"
14149 */
14150 op->ch1 = prevop->ch1;
14151 op->value = AXIS_DESCENDANT;
14152 break;
14153 case AXIS_SELF:
14154 case AXIS_DESCENDANT_OR_SELF:
14155 /*
14156 * Convert "descendant-or-self::node()/self::" or
14157 * "descendant-or-self::node()/descendant-or-self::" to
14158 * to "descendant-or-self::"
14159 */
14160 op->ch1 = prevop->ch1;
14161 op->value = AXIS_DESCENDANT_OR_SELF;
14162 break;
14163 default:
14164 break;
14165 }
14166 }
14167 }
14168
14169 /* OP_VALUE has invalid ch1. */
14170 if (op->op == XPATH_OP_VALUE)
14171 return;
14172
14173 /* Recurse */
14174 ctxt = pctxt->context;
14175 if (ctxt != NULL) {
14176 if (ctxt->depth >= ctxt->maxDepth)
14177 return;
14178 ctxt->depth += 1;
14179 }
14180 if (op->ch1 != -1)
14181 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14182 if (op->ch2 != -1)
14183 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14184 if (ctxt != NULL)
14185 ctxt->depth -= 1;
14186 }
14187
14188 /**
14189 * xmlXPathCtxtCompile:
14190 * @ctxt: an XPath context
14191 * @str: the XPath expression
14192 *
14193 * Compile an XPath expression
14194 *
14195 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14196 * the caller has to free the object.
14197 */
14198 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14199 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14200 xmlXPathParserContextPtr pctxt;
14201 xmlXPathCompExprPtr comp;
14202
14203 #ifdef XPATH_STREAMING
14204 comp = xmlXPathTryStreamCompile(ctxt, str);
14205 if (comp != NULL)
14206 return(comp);
14207 #endif
14208
14209 xmlXPathInit();
14210
14211 pctxt = xmlXPathNewParserContext(str, ctxt);
14212 if (pctxt == NULL)
14213 return NULL;
14214 if (ctxt != NULL)
14215 ctxt->depth = 0;
14216 xmlXPathCompileExpr(pctxt, 1);
14217
14218 if( pctxt->error != XPATH_EXPRESSION_OK )
14219 {
14220 xmlXPathFreeParserContext(pctxt);
14221 return(NULL);
14222 }
14223
14224 if (*pctxt->cur != 0) {
14225 /*
14226 * aleksey: in some cases this line prints *second* error message
14227 * (see bug #78858) and probably this should be fixed.
14228 * However, we are not sure that all error messages are printed
14229 * out in other places. It's not critical so we leave it as-is for now
14230 */
14231 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14232 comp = NULL;
14233 } else {
14234 comp = pctxt->comp;
14235 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14236 if (ctxt != NULL)
14237 ctxt->depth = 0;
14238 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14239 }
14240 pctxt->comp = NULL;
14241 }
14242 xmlXPathFreeParserContext(pctxt);
14243
14244 if (comp != NULL) {
14245 comp->expr = xmlStrdup(str);
14246 #ifdef DEBUG_EVAL_COUNTS
14247 comp->string = xmlStrdup(str);
14248 comp->nb = 0;
14249 #endif
14250 }
14251 return(comp);
14252 }
14253
14254 /**
14255 * xmlXPathCompile:
14256 * @str: the XPath expression
14257 *
14258 * Compile an XPath expression
14259 *
14260 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14261 * the caller has to free the object.
14262 */
14263 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14264 xmlXPathCompile(const xmlChar *str) {
14265 return(xmlXPathCtxtCompile(NULL, str));
14266 }
14267
14268 /**
14269 * xmlXPathCompiledEvalInternal:
14270 * @comp: the compiled XPath expression
14271 * @ctxt: the XPath context
14272 * @resObj: the resulting XPath object or NULL
14273 * @toBool: 1 if only a boolean result is requested
14274 *
14275 * Evaluate the Precompiled XPath expression in the given context.
14276 * The caller has to free @resObj.
14277 *
14278 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14279 * the caller has to free the object.
14280 */
14281 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14282 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14283 xmlXPathContextPtr ctxt,
14284 xmlXPathObjectPtr *resObjPtr,
14285 int toBool)
14286 {
14287 xmlXPathParserContextPtr pctxt;
14288 xmlXPathObjectPtr resObj;
14289 #ifndef LIBXML_THREAD_ENABLED
14290 static int reentance = 0;
14291 #endif
14292 int res;
14293
14294 CHECK_CTXT_NEG(ctxt)
14295
14296 if (comp == NULL)
14297 return(-1);
14298 xmlXPathInit();
14299
14300 #ifndef LIBXML_THREAD_ENABLED
14301 reentance++;
14302 if (reentance > 1)
14303 xmlXPathDisableOptimizer = 1;
14304 #endif
14305
14306 #ifdef DEBUG_EVAL_COUNTS
14307 comp->nb++;
14308 if ((comp->string != NULL) && (comp->nb > 100)) {
14309 fprintf(stderr, "100 x %s\n", comp->string);
14310 comp->nb = 0;
14311 }
14312 #endif
14313 pctxt = xmlXPathCompParserContext(comp, ctxt);
14314 res = xmlXPathRunEval(pctxt, toBool);
14315
14316 if (pctxt->error != XPATH_EXPRESSION_OK) {
14317 resObj = NULL;
14318 } else {
14319 resObj = valuePop(pctxt);
14320 if (resObj == NULL) {
14321 if (!toBool)
14322 xmlGenericError(xmlGenericErrorContext,
14323 "xmlXPathCompiledEval: No result on the stack.\n");
14324 } else if (pctxt->valueNr > 0) {
14325 xmlGenericError(xmlGenericErrorContext,
14326 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14327 pctxt->valueNr);
14328 }
14329 }
14330
14331 if (resObjPtr)
14332 *resObjPtr = resObj;
14333 else
14334 xmlXPathReleaseObject(ctxt, resObj);
14335
14336 pctxt->comp = NULL;
14337 xmlXPathFreeParserContext(pctxt);
14338 #ifndef LIBXML_THREAD_ENABLED
14339 reentance--;
14340 #endif
14341
14342 return(res);
14343 }
14344
14345 /**
14346 * xmlXPathCompiledEval:
14347 * @comp: the compiled XPath expression
14348 * @ctx: the XPath context
14349 *
14350 * Evaluate the Precompiled XPath expression in the given context.
14351 *
14352 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14353 * the caller has to free the object.
14354 */
14355 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14356 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14357 {
14358 xmlXPathObjectPtr res = NULL;
14359
14360 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14361 return(res);
14362 }
14363
14364 /**
14365 * xmlXPathCompiledEvalToBoolean:
14366 * @comp: the compiled XPath expression
14367 * @ctxt: the XPath context
14368 *
14369 * Applies the XPath boolean() function on the result of the given
14370 * compiled expression.
14371 *
14372 * Returns 1 if the expression evaluated to true, 0 if to false and
14373 * -1 in API and internal errors.
14374 */
14375 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14376 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14377 xmlXPathContextPtr ctxt)
14378 {
14379 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14380 }
14381
14382 /**
14383 * xmlXPathEvalExpr:
14384 * @ctxt: the XPath Parser context
14385 *
14386 * Parse and evaluate an XPath expression in the given context,
14387 * then push the result on the context stack
14388 */
14389 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14390 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14391 #ifdef XPATH_STREAMING
14392 xmlXPathCompExprPtr comp;
14393 #endif
14394
14395 if (ctxt == NULL) return;
14396
14397 #ifdef XPATH_STREAMING
14398 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14399 if (comp != NULL) {
14400 if (ctxt->comp != NULL)
14401 xmlXPathFreeCompExpr(ctxt->comp);
14402 ctxt->comp = comp;
14403 } else
14404 #endif
14405 {
14406 if (ctxt->context != NULL)
14407 ctxt->context->depth = 0;
14408 xmlXPathCompileExpr(ctxt, 1);
14409 CHECK_ERROR;
14410
14411 /* Check for trailing characters. */
14412 if (*ctxt->cur != 0)
14413 XP_ERROR(XPATH_EXPR_ERROR);
14414
14415 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14416 if (ctxt->context != NULL)
14417 ctxt->context->depth = 0;
14418 xmlXPathOptimizeExpression(ctxt,
14419 &ctxt->comp->steps[ctxt->comp->last]);
14420 }
14421 }
14422
14423 xmlXPathRunEval(ctxt, 0);
14424 }
14425
14426 /**
14427 * xmlXPathEval:
14428 * @str: the XPath expression
14429 * @ctx: the XPath context
14430 *
14431 * Evaluate the XPath Location Path in the given context.
14432 *
14433 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14434 * the caller has to free the object.
14435 */
14436 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14437 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14438 xmlXPathParserContextPtr ctxt;
14439 xmlXPathObjectPtr res;
14440
14441 CHECK_CTXT(ctx)
14442
14443 xmlXPathInit();
14444
14445 ctxt = xmlXPathNewParserContext(str, ctx);
14446 if (ctxt == NULL)
14447 return NULL;
14448 xmlXPathEvalExpr(ctxt);
14449
14450 if (ctxt->error != XPATH_EXPRESSION_OK) {
14451 res = NULL;
14452 } else {
14453 res = valuePop(ctxt);
14454 if (res == NULL) {
14455 xmlGenericError(xmlGenericErrorContext,
14456 "xmlXPathCompiledEval: No result on the stack.\n");
14457 } else if (ctxt->valueNr > 0) {
14458 xmlGenericError(xmlGenericErrorContext,
14459 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14460 ctxt->valueNr);
14461 }
14462 }
14463
14464 xmlXPathFreeParserContext(ctxt);
14465 return(res);
14466 }
14467
14468 /**
14469 * xmlXPathSetContextNode:
14470 * @node: the node to to use as the context node
14471 * @ctx: the XPath context
14472 *
14473 * Sets 'node' as the context node. The node must be in the same
14474 * document as that associated with the context.
14475 *
14476 * Returns -1 in case of error or 0 if successful
14477 */
14478 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14479 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14480 if ((node == NULL) || (ctx == NULL))
14481 return(-1);
14482
14483 if (node->doc == ctx->doc) {
14484 ctx->node = node;
14485 return(0);
14486 }
14487 return(-1);
14488 }
14489
14490 /**
14491 * xmlXPathNodeEval:
14492 * @node: the node to to use as the context node
14493 * @str: the XPath expression
14494 * @ctx: the XPath context
14495 *
14496 * Evaluate the XPath Location Path in the given context. The node 'node'
14497 * is set as the context node. The context node is not restored.
14498 *
14499 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14500 * the caller has to free the object.
14501 */
14502 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14503 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14504 if (str == NULL)
14505 return(NULL);
14506 if (xmlXPathSetContextNode(node, ctx) < 0)
14507 return(NULL);
14508 return(xmlXPathEval(str, ctx));
14509 }
14510
14511 /**
14512 * xmlXPathEvalExpression:
14513 * @str: the XPath expression
14514 * @ctxt: the XPath context
14515 *
14516 * Alias for xmlXPathEval().
14517 *
14518 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14519 * the caller has to free the object.
14520 */
14521 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14522 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14523 return(xmlXPathEval(str, ctxt));
14524 }
14525
14526 /************************************************************************
14527 * *
14528 * Extra functions not pertaining to the XPath spec *
14529 * *
14530 ************************************************************************/
14531 /**
14532 * xmlXPathEscapeUriFunction:
14533 * @ctxt: the XPath Parser context
14534 * @nargs: the number of arguments
14535 *
14536 * Implement the escape-uri() XPath function
14537 * string escape-uri(string $str, bool $escape-reserved)
14538 *
14539 * This function applies the URI escaping rules defined in section 2 of [RFC
14540 * 2396] to the string supplied as $uri-part, which typically represents all
14541 * or part of a URI. The effect of the function is to replace any special
14542 * character in the string by an escape sequence of the form %xx%yy...,
14543 * where xxyy... is the hexadecimal representation of the octets used to
14544 * represent the character in UTF-8.
14545 *
14546 * The set of characters that are escaped depends on the setting of the
14547 * boolean argument $escape-reserved.
14548 *
14549 * If $escape-reserved is true, all characters are escaped other than lower
14550 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14551 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14552 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14553 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14554 * A-F).
14555 *
14556 * If $escape-reserved is false, the behavior differs in that characters
14557 * referred to in [RFC 2396] as reserved characters are not escaped. These
14558 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14559 *
14560 * [RFC 2396] does not define whether escaped URIs should use lower case or
14561 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14562 * compared using string comparison functions, this function must always use
14563 * the upper-case letters A-F.
14564 *
14565 * Generally, $escape-reserved should be set to true when escaping a string
14566 * that is to form a single part of a URI, and to false when escaping an
14567 * entire URI or URI reference.
14568 *
14569 * In the case of non-ascii characters, the string is encoded according to
14570 * utf-8 and then converted according to RFC 2396.
14571 *
14572 * Examples
14573 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14574 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14575 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14576 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14577 *
14578 */
14579 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)14580 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14581 xmlXPathObjectPtr str;
14582 int escape_reserved;
14583 xmlBufPtr target;
14584 xmlChar *cptr;
14585 xmlChar escape[4];
14586
14587 CHECK_ARITY(2);
14588
14589 escape_reserved = xmlXPathPopBoolean(ctxt);
14590
14591 CAST_TO_STRING;
14592 str = valuePop(ctxt);
14593
14594 target = xmlBufCreate();
14595
14596 escape[0] = '%';
14597 escape[3] = 0;
14598
14599 if (target) {
14600 for (cptr = str->stringval; *cptr; cptr++) {
14601 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14602 (*cptr >= 'a' && *cptr <= 'z') ||
14603 (*cptr >= '0' && *cptr <= '9') ||
14604 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14605 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14606 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14607 (*cptr == '%' &&
14608 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14609 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14610 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14611 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14612 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14613 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14614 (!escape_reserved &&
14615 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14616 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14617 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14618 *cptr == ','))) {
14619 xmlBufAdd(target, cptr, 1);
14620 } else {
14621 if ((*cptr >> 4) < 10)
14622 escape[1] = '0' + (*cptr >> 4);
14623 else
14624 escape[1] = 'A' - 10 + (*cptr >> 4);
14625 if ((*cptr & 0xF) < 10)
14626 escape[2] = '0' + (*cptr & 0xF);
14627 else
14628 escape[2] = 'A' - 10 + (*cptr & 0xF);
14629
14630 xmlBufAdd(target, &escape[0], 3);
14631 }
14632 }
14633 }
14634 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14635 xmlBufContent(target)));
14636 xmlBufFree(target);
14637 xmlXPathReleaseObject(ctxt->context, str);
14638 }
14639
14640 /**
14641 * xmlXPathRegisterAllFunctions:
14642 * @ctxt: the XPath context
14643 *
14644 * Registers all default XPath functions in this context
14645 */
14646 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)14647 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14648 {
14649 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14650 xmlXPathBooleanFunction);
14651 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14652 xmlXPathCeilingFunction);
14653 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14654 xmlXPathCountFunction);
14655 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14656 xmlXPathConcatFunction);
14657 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14658 xmlXPathContainsFunction);
14659 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14660 xmlXPathIdFunction);
14661 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14662 xmlXPathFalseFunction);
14663 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14664 xmlXPathFloorFunction);
14665 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14666 xmlXPathLastFunction);
14667 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14668 xmlXPathLangFunction);
14669 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14670 xmlXPathLocalNameFunction);
14671 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14672 xmlXPathNotFunction);
14673 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14674 xmlXPathNameFunction);
14675 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14676 xmlXPathNamespaceURIFunction);
14677 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14678 xmlXPathNormalizeFunction);
14679 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14680 xmlXPathNumberFunction);
14681 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14682 xmlXPathPositionFunction);
14683 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14684 xmlXPathRoundFunction);
14685 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14686 xmlXPathStringFunction);
14687 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14688 xmlXPathStringLengthFunction);
14689 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14690 xmlXPathStartsWithFunction);
14691 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14692 xmlXPathSubstringFunction);
14693 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14694 xmlXPathSubstringBeforeFunction);
14695 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14696 xmlXPathSubstringAfterFunction);
14697 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14698 xmlXPathSumFunction);
14699 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14700 xmlXPathTrueFunction);
14701 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14702 xmlXPathTranslateFunction);
14703
14704 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14705 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14706 xmlXPathEscapeUriFunction);
14707 }
14708
14709 #endif /* LIBXML_XPATH_ENABLED */
14710 #define bottom_xpath
14711 #include "elfgcchack.h"
14712