1 /*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21
22 #define IN_LIBXML
23 #include "libxml.h"
24
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <math.h>
29 #include <float.h>
30 #include <ctype.h>
31
32 #include <libxml/xmlmemory.h>
33 #include <libxml/tree.h>
34 #include <libxml/valid.h>
35 #include <libxml/xpath.h>
36 #include <libxml/xpathInternals.h>
37 #include <libxml/parserInternals.h>
38 #include <libxml/hash.h>
39 #ifdef LIBXML_XPTR_LOCS_ENABLED
40 #include <libxml/xpointer.h>
41 #endif
42 #ifdef LIBXML_DEBUG_ENABLED
43 #include <libxml/debugXML.h>
44 #endif
45 #include <libxml/xmlerror.h>
46 #include <libxml/threads.h>
47 #include <libxml/globals.h>
48 #ifdef LIBXML_PATTERN_ENABLED
49 #include <libxml/pattern.h>
50 #endif
51
52 #include "buf.h"
53
54 #ifdef LIBXML_PATTERN_ENABLED
55 #define XPATH_STREAMING
56 #endif
57
58 #define TODO \
59 xmlGenericError(xmlGenericErrorContext, \
60 "Unimplemented block at %s:%d\n", \
61 __FILE__, __LINE__);
62
63 /**
64 * WITH_TIM_SORT:
65 *
66 * Use the Timsort algorithm provided in timsort.h to sort
67 * nodeset as this is a great improvement over the old Shell sort
68 * used in xmlXPathNodeSetSort()
69 */
70 #define WITH_TIM_SORT
71
72 /*
73 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
74 * If defined, this will use xmlXPathCmpNodesExt() instead of
75 * xmlXPathCmpNodes(). The new function is optimized comparison of
76 * non-element nodes; actually it will speed up comparison only if
77 * xmlXPathOrderDocElems() was called in order to index the elements of
78 * a tree in document order; Libxslt does such an indexing, thus it will
79 * benefit from this optimization.
80 */
81 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
82
83 /*
84 * XP_OPTIMIZED_FILTER_FIRST:
85 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
86 * in a way, that it stop evaluation at the first node.
87 */
88 #define XP_OPTIMIZED_FILTER_FIRST
89
90 /*
91 * XP_DEBUG_OBJ_USAGE:
92 * Internal flag to enable tracking of how much XPath objects have been
93 * created.
94 */
95 /* #define XP_DEBUG_OBJ_USAGE */
96
97 /*
98 * XPATH_MAX_STEPS:
99 * when compiling an XPath expression we arbitrary limit the maximum
100 * number of step operation in the compiled expression. 1000000 is
101 * an insanely large value which should never be reached under normal
102 * circumstances
103 */
104 #define XPATH_MAX_STEPS 1000000
105
106 /*
107 * XPATH_MAX_STACK_DEPTH:
108 * when evaluating an XPath expression we arbitrary limit the maximum
109 * number of object allowed to be pushed on the stack. 1000000 is
110 * an insanely large value which should never be reached under normal
111 * circumstances
112 */
113 #define XPATH_MAX_STACK_DEPTH 1000000
114
115 /*
116 * XPATH_MAX_NODESET_LENGTH:
117 * when evaluating an XPath expression nodesets are created and we
118 * arbitrary limit the maximum length of those node set. 10000000 is
119 * an insanely large value which should never be reached under normal
120 * circumstances, one would first need to construct an in memory tree
121 * with more than 10 millions nodes.
122 */
123 #define XPATH_MAX_NODESET_LENGTH 10000000
124
125 /*
126 * XPATH_MAX_RECRUSION_DEPTH:
127 * Maximum amount of nested functions calls when parsing or evaluating
128 * expressions
129 */
130 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
131 #define XPATH_MAX_RECURSION_DEPTH 500
132 #else
133 #define XPATH_MAX_RECURSION_DEPTH 5000
134 #endif
135
136 /*
137 * TODO:
138 * There are a few spots where some tests are done which depend upon ascii
139 * data. These should be enhanced for full UTF8 support (see particularly
140 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
141 */
142
143 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
144 /**
145 * xmlXPathCmpNodesExt:
146 * @node1: the first node
147 * @node2: the second node
148 *
149 * Compare two nodes w.r.t document order.
150 * This one is optimized for handling of non-element nodes.
151 *
152 * Returns -2 in case of error 1 if first point < second point, 0 if
153 * it's the same node, -1 otherwise
154 */
155 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)156 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
157 int depth1, depth2;
158 int misc = 0, precedence1 = 0, precedence2 = 0;
159 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
160 xmlNodePtr cur, root;
161 ptrdiff_t l1, l2;
162
163 if ((node1 == NULL) || (node2 == NULL))
164 return(-2);
165
166 if (node1 == node2)
167 return(0);
168
169 /*
170 * a couple of optimizations which will avoid computations in most cases
171 */
172 switch (node1->type) {
173 case XML_ELEMENT_NODE:
174 if (node2->type == XML_ELEMENT_NODE) {
175 if ((0 > (ptrdiff_t) node1->content) &&
176 (0 > (ptrdiff_t) node2->content) &&
177 (node1->doc == node2->doc))
178 {
179 l1 = -((ptrdiff_t) node1->content);
180 l2 = -((ptrdiff_t) node2->content);
181 if (l1 < l2)
182 return(1);
183 if (l1 > l2)
184 return(-1);
185 } else
186 goto turtle_comparison;
187 }
188 break;
189 case XML_ATTRIBUTE_NODE:
190 precedence1 = 1; /* element is owner */
191 miscNode1 = node1;
192 node1 = node1->parent;
193 misc = 1;
194 break;
195 case XML_TEXT_NODE:
196 case XML_CDATA_SECTION_NODE:
197 case XML_COMMENT_NODE:
198 case XML_PI_NODE: {
199 miscNode1 = node1;
200 /*
201 * Find nearest element node.
202 */
203 if (node1->prev != NULL) {
204 do {
205 node1 = node1->prev;
206 if (node1->type == XML_ELEMENT_NODE) {
207 precedence1 = 3; /* element in prev-sibl axis */
208 break;
209 }
210 if (node1->prev == NULL) {
211 precedence1 = 2; /* element is parent */
212 /*
213 * URGENT TODO: Are there any cases, where the
214 * parent of such a node is not an element node?
215 */
216 node1 = node1->parent;
217 break;
218 }
219 } while (1);
220 } else {
221 precedence1 = 2; /* element is parent */
222 node1 = node1->parent;
223 }
224 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
225 (0 <= (ptrdiff_t) node1->content)) {
226 /*
227 * Fallback for whatever case.
228 */
229 node1 = miscNode1;
230 precedence1 = 0;
231 } else
232 misc = 1;
233 }
234 break;
235 case XML_NAMESPACE_DECL:
236 /*
237 * TODO: why do we return 1 for namespace nodes?
238 */
239 return(1);
240 default:
241 break;
242 }
243 switch (node2->type) {
244 case XML_ELEMENT_NODE:
245 break;
246 case XML_ATTRIBUTE_NODE:
247 precedence2 = 1; /* element is owner */
248 miscNode2 = node2;
249 node2 = node2->parent;
250 misc = 1;
251 break;
252 case XML_TEXT_NODE:
253 case XML_CDATA_SECTION_NODE:
254 case XML_COMMENT_NODE:
255 case XML_PI_NODE: {
256 miscNode2 = node2;
257 if (node2->prev != NULL) {
258 do {
259 node2 = node2->prev;
260 if (node2->type == XML_ELEMENT_NODE) {
261 precedence2 = 3; /* element in prev-sibl axis */
262 break;
263 }
264 if (node2->prev == NULL) {
265 precedence2 = 2; /* element is parent */
266 node2 = node2->parent;
267 break;
268 }
269 } while (1);
270 } else {
271 precedence2 = 2; /* element is parent */
272 node2 = node2->parent;
273 }
274 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
275 (0 <= (ptrdiff_t) node2->content))
276 {
277 node2 = miscNode2;
278 precedence2 = 0;
279 } else
280 misc = 1;
281 }
282 break;
283 case XML_NAMESPACE_DECL:
284 return(1);
285 default:
286 break;
287 }
288 if (misc) {
289 if (node1 == node2) {
290 if (precedence1 == precedence2) {
291 /*
292 * The ugly case; but normally there aren't many
293 * adjacent non-element nodes around.
294 */
295 cur = miscNode2->prev;
296 while (cur != NULL) {
297 if (cur == miscNode1)
298 return(1);
299 if (cur->type == XML_ELEMENT_NODE)
300 return(-1);
301 cur = cur->prev;
302 }
303 return (-1);
304 } else {
305 /*
306 * Evaluate based on higher precedence wrt to the element.
307 * TODO: This assumes attributes are sorted before content.
308 * Is this 100% correct?
309 */
310 if (precedence1 < precedence2)
311 return(1);
312 else
313 return(-1);
314 }
315 }
316 /*
317 * Special case: One of the helper-elements is contained by the other.
318 * <foo>
319 * <node2>
320 * <node1>Text-1(precedence1 == 2)</node1>
321 * </node2>
322 * Text-6(precedence2 == 3)
323 * </foo>
324 */
325 if ((precedence2 == 3) && (precedence1 > 1)) {
326 cur = node1->parent;
327 while (cur) {
328 if (cur == node2)
329 return(1);
330 cur = cur->parent;
331 }
332 }
333 if ((precedence1 == 3) && (precedence2 > 1)) {
334 cur = node2->parent;
335 while (cur) {
336 if (cur == node1)
337 return(-1);
338 cur = cur->parent;
339 }
340 }
341 }
342
343 /*
344 * Speedup using document order if available.
345 */
346 if ((node1->type == XML_ELEMENT_NODE) &&
347 (node2->type == XML_ELEMENT_NODE) &&
348 (0 > (ptrdiff_t) node1->content) &&
349 (0 > (ptrdiff_t) node2->content) &&
350 (node1->doc == node2->doc)) {
351
352 l1 = -((ptrdiff_t) node1->content);
353 l2 = -((ptrdiff_t) node2->content);
354 if (l1 < l2)
355 return(1);
356 if (l1 > l2)
357 return(-1);
358 }
359
360 turtle_comparison:
361
362 if (node1 == node2->prev)
363 return(1);
364 if (node1 == node2->next)
365 return(-1);
366 /*
367 * compute depth to root
368 */
369 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
370 if (cur->parent == node1)
371 return(1);
372 depth2++;
373 }
374 root = cur;
375 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
376 if (cur->parent == node2)
377 return(-1);
378 depth1++;
379 }
380 /*
381 * Distinct document (or distinct entities :-( ) case.
382 */
383 if (root != cur) {
384 return(-2);
385 }
386 /*
387 * get the nearest common ancestor.
388 */
389 while (depth1 > depth2) {
390 depth1--;
391 node1 = node1->parent;
392 }
393 while (depth2 > depth1) {
394 depth2--;
395 node2 = node2->parent;
396 }
397 while (node1->parent != node2->parent) {
398 node1 = node1->parent;
399 node2 = node2->parent;
400 /* should not happen but just in case ... */
401 if ((node1 == NULL) || (node2 == NULL))
402 return(-2);
403 }
404 /*
405 * Find who's first.
406 */
407 if (node1 == node2->prev)
408 return(1);
409 if (node1 == node2->next)
410 return(-1);
411 /*
412 * Speedup using document order if available.
413 */
414 if ((node1->type == XML_ELEMENT_NODE) &&
415 (node2->type == XML_ELEMENT_NODE) &&
416 (0 > (ptrdiff_t) node1->content) &&
417 (0 > (ptrdiff_t) node2->content) &&
418 (node1->doc == node2->doc)) {
419
420 l1 = -((ptrdiff_t) node1->content);
421 l2 = -((ptrdiff_t) node2->content);
422 if (l1 < l2)
423 return(1);
424 if (l1 > l2)
425 return(-1);
426 }
427
428 for (cur = node1->next;cur != NULL;cur = cur->next)
429 if (cur == node2)
430 return(1);
431 return(-1); /* assume there is no sibling list corruption */
432 }
433 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
434
435 /*
436 * Wrapper for the Timsort algorithm from timsort.h
437 */
438 #ifdef WITH_TIM_SORT
439 #define SORT_NAME libxml_domnode
440 #define SORT_TYPE xmlNodePtr
441 /**
442 * wrap_cmp:
443 * @x: a node
444 * @y: another node
445 *
446 * Comparison function for the Timsort implementation
447 *
448 * Returns -2 in case of error -1 if first point < second point, 0 if
449 * it's the same node, +1 otherwise
450 */
451 static
452 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
453 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)454 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
455 {
456 int res = xmlXPathCmpNodesExt(x, y);
457 return res == -2 ? res : -res;
458 }
459 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)460 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
461 {
462 int res = xmlXPathCmpNodes(x, y);
463 return res == -2 ? res : -res;
464 }
465 #endif
466 #define SORT_CMP(x, y) (wrap_cmp(x, y))
467 #include "timsort.h"
468 #endif /* WITH_TIM_SORT */
469
470 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
471
472 /************************************************************************
473 * *
474 * Floating point stuff *
475 * *
476 ************************************************************************/
477
478 double xmlXPathNAN = 0.0;
479 double xmlXPathPINF = 0.0;
480 double xmlXPathNINF = 0.0;
481
482 /**
483 * xmlXPathInit:
484 *
485 * DEPRECATED: This function will be made private. Call xmlInitParser to
486 * initialize the library.
487 *
488 * Initialize the XPath environment
489 */
490 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
491 void
xmlXPathInit(void)492 xmlXPathInit(void) {
493 #if defined(NAN) && defined(INFINITY)
494 xmlXPathNAN = NAN;
495 xmlXPathPINF = INFINITY;
496 xmlXPathNINF = -INFINITY;
497 #else
498 /* MSVC doesn't allow division by zero in constant expressions. */
499 double zero = 0.0;
500 xmlXPathNAN = 0.0 / zero;
501 xmlXPathPINF = 1.0 / zero;
502 xmlXPathNINF = -xmlXPathPINF;
503 #endif
504 }
505
506 /**
507 * xmlXPathIsNaN:
508 * @val: a double value
509 *
510 * Returns 1 if the value is a NaN, 0 otherwise
511 */
512 int
xmlXPathIsNaN(double val)513 xmlXPathIsNaN(double val) {
514 #ifdef isnan
515 return isnan(val);
516 #else
517 return !(val == val);
518 #endif
519 }
520
521 /**
522 * xmlXPathIsInf:
523 * @val: a double value
524 *
525 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
526 */
527 int
xmlXPathIsInf(double val)528 xmlXPathIsInf(double val) {
529 #ifdef isinf
530 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
531 #else
532 if (val >= xmlXPathPINF)
533 return 1;
534 if (val <= -xmlXPathPINF)
535 return -1;
536 return 0;
537 #endif
538 }
539
540 #endif /* SCHEMAS or XPATH */
541
542 #ifdef LIBXML_XPATH_ENABLED
543
544 /*
545 * TODO: when compatibility allows remove all "fake node libxslt" strings
546 * the test should just be name[0] = ' '
547 */
548 #ifdef DEBUG_XPATH_EXPRESSION
549 #define DEBUG_STEP
550 #define DEBUG_EXPR
551 #define DEBUG_EVAL_COUNTS
552 #endif
553
554 static xmlNs xmlXPathXMLNamespaceStruct = {
555 NULL,
556 XML_NAMESPACE_DECL,
557 XML_XML_NAMESPACE,
558 BAD_CAST "xml",
559 NULL,
560 NULL
561 };
562 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
563 #ifndef LIBXML_THREAD_ENABLED
564 /*
565 * Optimizer is disabled only when threaded apps are detected while
566 * the library ain't compiled for thread safety.
567 */
568 static int xmlXPathDisableOptimizer = 0;
569 #endif
570
571 /************************************************************************
572 * *
573 * Error handling routines *
574 * *
575 ************************************************************************/
576
577 /**
578 * XP_ERRORNULL:
579 * @X: the error code
580 *
581 * Macro to raise an XPath error and return NULL.
582 */
583 #define XP_ERRORNULL(X) \
584 { xmlXPathErr(ctxt, X); return(NULL); }
585
586 /*
587 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
588 */
589 static const char* const xmlXPathErrorMessages[] = {
590 "Ok\n",
591 "Number encoding\n",
592 "Unfinished literal\n",
593 "Start of literal\n",
594 "Expected $ for variable reference\n",
595 "Undefined variable\n",
596 "Invalid predicate\n",
597 "Invalid expression\n",
598 "Missing closing curly brace\n",
599 "Unregistered function\n",
600 "Invalid operand\n",
601 "Invalid type\n",
602 "Invalid number of arguments\n",
603 "Invalid context size\n",
604 "Invalid context position\n",
605 "Memory allocation error\n",
606 "Syntax error\n",
607 "Resource error\n",
608 "Sub resource error\n",
609 "Undefined namespace prefix\n",
610 "Encoding error\n",
611 "Char out of XML range\n",
612 "Invalid or incomplete context\n",
613 "Stack usage error\n",
614 "Forbidden variable\n",
615 "Operation limit exceeded\n",
616 "Recursion limit exceeded\n",
617 "?? Unknown error ??\n" /* Must be last in the list! */
618 };
619 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
620 sizeof(xmlXPathErrorMessages[0])) - 1)
621 /**
622 * xmlXPathErrMemory:
623 * @ctxt: an XPath context
624 * @extra: extra information
625 *
626 * Handle a redefinition of attribute error
627 */
628 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)629 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
630 {
631 if (ctxt != NULL) {
632 xmlResetError(&ctxt->lastError);
633 if (extra) {
634 xmlChar buf[200];
635
636 xmlStrPrintf(buf, 200,
637 "Memory allocation failed : %s\n",
638 extra);
639 ctxt->lastError.message = (char *) xmlStrdup(buf);
640 } else {
641 ctxt->lastError.message = (char *)
642 xmlStrdup(BAD_CAST "Memory allocation failed\n");
643 }
644 ctxt->lastError.domain = XML_FROM_XPATH;
645 ctxt->lastError.code = XML_ERR_NO_MEMORY;
646 if (ctxt->error != NULL)
647 ctxt->error(ctxt->userData, &ctxt->lastError);
648 } else {
649 if (extra)
650 __xmlRaiseError(NULL, NULL, NULL,
651 NULL, NULL, XML_FROM_XPATH,
652 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
653 extra, NULL, NULL, 0, 0,
654 "Memory allocation failed : %s\n", extra);
655 else
656 __xmlRaiseError(NULL, NULL, NULL,
657 NULL, NULL, XML_FROM_XPATH,
658 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
659 NULL, NULL, NULL, 0, 0,
660 "Memory allocation failed\n");
661 }
662 }
663
664 /**
665 * xmlXPathPErrMemory:
666 * @ctxt: an XPath parser context
667 * @extra: extra information
668 *
669 * Handle a redefinition of attribute error
670 */
671 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)672 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
673 {
674 if (ctxt == NULL)
675 xmlXPathErrMemory(NULL, extra);
676 else {
677 ctxt->error = XPATH_MEMORY_ERROR;
678 xmlXPathErrMemory(ctxt->context, extra);
679 }
680 }
681
682 /**
683 * xmlXPathErr:
684 * @ctxt: a XPath parser context
685 * @error: the error code
686 *
687 * Handle an XPath error
688 */
689 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)690 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
691 {
692 if ((error < 0) || (error > MAXERRNO))
693 error = MAXERRNO;
694 if (ctxt == NULL) {
695 __xmlRaiseError(NULL, NULL, NULL,
696 NULL, NULL, XML_FROM_XPATH,
697 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
698 XML_ERR_ERROR, NULL, 0,
699 NULL, NULL, NULL, 0, 0,
700 "%s", xmlXPathErrorMessages[error]);
701 return;
702 }
703 ctxt->error = error;
704 if (ctxt->context == NULL) {
705 __xmlRaiseError(NULL, NULL, NULL,
706 NULL, NULL, XML_FROM_XPATH,
707 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
708 XML_ERR_ERROR, NULL, 0,
709 (const char *) ctxt->base, NULL, NULL,
710 ctxt->cur - ctxt->base, 0,
711 "%s", xmlXPathErrorMessages[error]);
712 return;
713 }
714
715 /* cleanup current last error */
716 xmlResetError(&ctxt->context->lastError);
717
718 ctxt->context->lastError.domain = XML_FROM_XPATH;
719 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
720 XPATH_EXPRESSION_OK;
721 ctxt->context->lastError.level = XML_ERR_ERROR;
722 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
723 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
724 ctxt->context->lastError.node = ctxt->context->debugNode;
725 if (ctxt->context->error != NULL) {
726 ctxt->context->error(ctxt->context->userData,
727 &ctxt->context->lastError);
728 } else {
729 __xmlRaiseError(NULL, NULL, NULL,
730 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
731 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
732 XML_ERR_ERROR, NULL, 0,
733 (const char *) ctxt->base, NULL, NULL,
734 ctxt->cur - ctxt->base, 0,
735 "%s", xmlXPathErrorMessages[error]);
736 }
737
738 }
739
740 /**
741 * xmlXPatherror:
742 * @ctxt: the XPath Parser context
743 * @file: the file name
744 * @line: the line number
745 * @no: the error number
746 *
747 * Formats an error message.
748 */
749 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)750 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
751 int line ATTRIBUTE_UNUSED, int no) {
752 xmlXPathErr(ctxt, no);
753 }
754
755 /**
756 * xmlXPathCheckOpLimit:
757 * @ctxt: the XPath Parser context
758 * @opCount: the number of operations to be added
759 *
760 * Adds opCount to the running total of operations and returns -1 if the
761 * operation limit is exceeded. Returns 0 otherwise.
762 */
763 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)764 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
765 xmlXPathContextPtr xpctxt = ctxt->context;
766
767 if ((opCount > xpctxt->opLimit) ||
768 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
769 xpctxt->opCount = xpctxt->opLimit;
770 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
771 return(-1);
772 }
773
774 xpctxt->opCount += opCount;
775 return(0);
776 }
777
778 #define OP_LIMIT_EXCEEDED(ctxt, n) \
779 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
780
781 /************************************************************************
782 * *
783 * Utilities *
784 * *
785 ************************************************************************/
786
787 /**
788 * xsltPointerList:
789 *
790 * Pointer-list for various purposes.
791 */
792 typedef struct _xmlPointerList xmlPointerList;
793 typedef xmlPointerList *xmlPointerListPtr;
794 struct _xmlPointerList {
795 void **items;
796 int number;
797 int size;
798 };
799 /*
800 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
801 * and here, we should make the functions public.
802 */
803 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)804 xmlPointerListAddSize(xmlPointerListPtr list,
805 void *item,
806 int initialSize)
807 {
808 if (list->items == NULL) {
809 if (initialSize <= 0)
810 initialSize = 1;
811 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
812 if (list->items == NULL) {
813 xmlXPathErrMemory(NULL,
814 "xmlPointerListCreate: allocating item\n");
815 return(-1);
816 }
817 list->number = 0;
818 list->size = initialSize;
819 } else if (list->size <= list->number) {
820 if (list->size > 50000000) {
821 xmlXPathErrMemory(NULL,
822 "xmlPointerListAddSize: re-allocating item\n");
823 return(-1);
824 }
825 list->size *= 2;
826 list->items = (void **) xmlRealloc(list->items,
827 list->size * sizeof(void *));
828 if (list->items == NULL) {
829 xmlXPathErrMemory(NULL,
830 "xmlPointerListAddSize: re-allocating item\n");
831 list->size = 0;
832 return(-1);
833 }
834 }
835 list->items[list->number++] = item;
836 return(0);
837 }
838
839 /**
840 * xsltPointerListCreate:
841 *
842 * Creates an xsltPointerList structure.
843 *
844 * Returns a xsltPointerList structure or NULL in case of an error.
845 */
846 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)847 xmlPointerListCreate(int initialSize)
848 {
849 xmlPointerListPtr ret;
850
851 ret = xmlMalloc(sizeof(xmlPointerList));
852 if (ret == NULL) {
853 xmlXPathErrMemory(NULL,
854 "xmlPointerListCreate: allocating item\n");
855 return (NULL);
856 }
857 memset(ret, 0, sizeof(xmlPointerList));
858 if (initialSize > 0) {
859 xmlPointerListAddSize(ret, NULL, initialSize);
860 ret->number = 0;
861 }
862 return (ret);
863 }
864
865 /**
866 * xsltPointerListFree:
867 *
868 * Frees the xsltPointerList structure. This does not free
869 * the content of the list.
870 */
871 static void
xmlPointerListFree(xmlPointerListPtr list)872 xmlPointerListFree(xmlPointerListPtr list)
873 {
874 if (list == NULL)
875 return;
876 if (list->items != NULL)
877 xmlFree(list->items);
878 xmlFree(list);
879 }
880
881 /************************************************************************
882 * *
883 * Parser Types *
884 * *
885 ************************************************************************/
886
887 /*
888 * Types are private:
889 */
890
891 typedef enum {
892 XPATH_OP_END=0,
893 XPATH_OP_AND,
894 XPATH_OP_OR,
895 XPATH_OP_EQUAL,
896 XPATH_OP_CMP,
897 XPATH_OP_PLUS,
898 XPATH_OP_MULT,
899 XPATH_OP_UNION,
900 XPATH_OP_ROOT,
901 XPATH_OP_NODE,
902 XPATH_OP_COLLECT,
903 XPATH_OP_VALUE, /* 11 */
904 XPATH_OP_VARIABLE,
905 XPATH_OP_FUNCTION,
906 XPATH_OP_ARG,
907 XPATH_OP_PREDICATE,
908 XPATH_OP_FILTER, /* 16 */
909 XPATH_OP_SORT /* 17 */
910 #ifdef LIBXML_XPTR_LOCS_ENABLED
911 ,XPATH_OP_RANGETO
912 #endif
913 } xmlXPathOp;
914
915 typedef enum {
916 AXIS_ANCESTOR = 1,
917 AXIS_ANCESTOR_OR_SELF,
918 AXIS_ATTRIBUTE,
919 AXIS_CHILD,
920 AXIS_DESCENDANT,
921 AXIS_DESCENDANT_OR_SELF,
922 AXIS_FOLLOWING,
923 AXIS_FOLLOWING_SIBLING,
924 AXIS_NAMESPACE,
925 AXIS_PARENT,
926 AXIS_PRECEDING,
927 AXIS_PRECEDING_SIBLING,
928 AXIS_SELF
929 } xmlXPathAxisVal;
930
931 typedef enum {
932 NODE_TEST_NONE = 0,
933 NODE_TEST_TYPE = 1,
934 NODE_TEST_PI = 2,
935 NODE_TEST_ALL = 3,
936 NODE_TEST_NS = 4,
937 NODE_TEST_NAME = 5
938 } xmlXPathTestVal;
939
940 typedef enum {
941 NODE_TYPE_NODE = 0,
942 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
943 NODE_TYPE_TEXT = XML_TEXT_NODE,
944 NODE_TYPE_PI = XML_PI_NODE
945 } xmlXPathTypeVal;
946
947 typedef struct _xmlXPathStepOp xmlXPathStepOp;
948 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
949 struct _xmlXPathStepOp {
950 xmlXPathOp op; /* The identifier of the operation */
951 int ch1; /* First child */
952 int ch2; /* Second child */
953 int value;
954 int value2;
955 int value3;
956 void *value4;
957 void *value5;
958 xmlXPathFunction cache;
959 void *cacheURI;
960 };
961
962 struct _xmlXPathCompExpr {
963 int nbStep; /* Number of steps in this expression */
964 int maxStep; /* Maximum number of steps allocated */
965 xmlXPathStepOp *steps; /* ops for computation of this expression */
966 int last; /* index of last step in expression */
967 xmlChar *expr; /* the expression being computed */
968 xmlDictPtr dict; /* the dictionary to use if any */
969 #ifdef DEBUG_EVAL_COUNTS
970 int nb;
971 xmlChar *string;
972 #endif
973 #ifdef XPATH_STREAMING
974 xmlPatternPtr stream;
975 #endif
976 };
977
978 /************************************************************************
979 * *
980 * Forward declarations *
981 * *
982 ************************************************************************/
983 static void
984 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
985 static void
986 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
987 static int
988 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
989 xmlXPathStepOpPtr op, xmlNodePtr *first);
990 static int
991 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
992 xmlXPathStepOpPtr op,
993 int isPredicate);
994 static void
995 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
996
997 /************************************************************************
998 * *
999 * Parser Type functions *
1000 * *
1001 ************************************************************************/
1002
1003 /**
1004 * xmlXPathNewCompExpr:
1005 *
1006 * Create a new Xpath component
1007 *
1008 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1009 */
1010 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)1011 xmlXPathNewCompExpr(void) {
1012 xmlXPathCompExprPtr cur;
1013
1014 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1015 if (cur == NULL) {
1016 xmlXPathErrMemory(NULL, "allocating component\n");
1017 return(NULL);
1018 }
1019 memset(cur, 0, sizeof(xmlXPathCompExpr));
1020 cur->maxStep = 10;
1021 cur->nbStep = 0;
1022 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1023 sizeof(xmlXPathStepOp));
1024 if (cur->steps == NULL) {
1025 xmlXPathErrMemory(NULL, "allocating steps\n");
1026 xmlFree(cur);
1027 return(NULL);
1028 }
1029 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1030 cur->last = -1;
1031 #ifdef DEBUG_EVAL_COUNTS
1032 cur->nb = 0;
1033 #endif
1034 return(cur);
1035 }
1036
1037 /**
1038 * xmlXPathFreeCompExpr:
1039 * @comp: an XPATH comp
1040 *
1041 * Free up the memory allocated by @comp
1042 */
1043 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1044 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1045 {
1046 xmlXPathStepOpPtr op;
1047 int i;
1048
1049 if (comp == NULL)
1050 return;
1051 if (comp->dict == NULL) {
1052 for (i = 0; i < comp->nbStep; i++) {
1053 op = &comp->steps[i];
1054 if (op->value4 != NULL) {
1055 if (op->op == XPATH_OP_VALUE)
1056 xmlXPathFreeObject(op->value4);
1057 else
1058 xmlFree(op->value4);
1059 }
1060 if (op->value5 != NULL)
1061 xmlFree(op->value5);
1062 }
1063 } else {
1064 for (i = 0; i < comp->nbStep; i++) {
1065 op = &comp->steps[i];
1066 if (op->value4 != NULL) {
1067 if (op->op == XPATH_OP_VALUE)
1068 xmlXPathFreeObject(op->value4);
1069 }
1070 }
1071 xmlDictFree(comp->dict);
1072 }
1073 if (comp->steps != NULL) {
1074 xmlFree(comp->steps);
1075 }
1076 #ifdef DEBUG_EVAL_COUNTS
1077 if (comp->string != NULL) {
1078 xmlFree(comp->string);
1079 }
1080 #endif
1081 #ifdef XPATH_STREAMING
1082 if (comp->stream != NULL) {
1083 xmlFreePatternList(comp->stream);
1084 }
1085 #endif
1086 if (comp->expr != NULL) {
1087 xmlFree(comp->expr);
1088 }
1089
1090 xmlFree(comp);
1091 }
1092
1093 /**
1094 * xmlXPathCompExprAdd:
1095 * @comp: the compiled expression
1096 * @ch1: first child index
1097 * @ch2: second child index
1098 * @op: an op
1099 * @value: the first int value
1100 * @value2: the second int value
1101 * @value3: the third int value
1102 * @value4: the first string value
1103 * @value5: the second string value
1104 *
1105 * Add a step to an XPath Compiled Expression
1106 *
1107 * Returns -1 in case of failure, the index otherwise
1108 */
1109 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1110 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1111 xmlXPathOp op, int value,
1112 int value2, int value3, void *value4, void *value5) {
1113 xmlXPathCompExprPtr comp = ctxt->comp;
1114 if (comp->nbStep >= comp->maxStep) {
1115 xmlXPathStepOp *real;
1116
1117 if (comp->maxStep >= XPATH_MAX_STEPS) {
1118 xmlXPathPErrMemory(ctxt, "adding step\n");
1119 return(-1);
1120 }
1121 comp->maxStep *= 2;
1122 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1123 comp->maxStep * sizeof(xmlXPathStepOp));
1124 if (real == NULL) {
1125 comp->maxStep /= 2;
1126 xmlXPathPErrMemory(ctxt, "adding step\n");
1127 return(-1);
1128 }
1129 comp->steps = real;
1130 }
1131 comp->last = comp->nbStep;
1132 comp->steps[comp->nbStep].ch1 = ch1;
1133 comp->steps[comp->nbStep].ch2 = ch2;
1134 comp->steps[comp->nbStep].op = op;
1135 comp->steps[comp->nbStep].value = value;
1136 comp->steps[comp->nbStep].value2 = value2;
1137 comp->steps[comp->nbStep].value3 = value3;
1138 if ((comp->dict != NULL) &&
1139 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1140 (op == XPATH_OP_COLLECT))) {
1141 if (value4 != NULL) {
1142 comp->steps[comp->nbStep].value4 = (xmlChar *)
1143 (void *)xmlDictLookup(comp->dict, value4, -1);
1144 xmlFree(value4);
1145 } else
1146 comp->steps[comp->nbStep].value4 = NULL;
1147 if (value5 != NULL) {
1148 comp->steps[comp->nbStep].value5 = (xmlChar *)
1149 (void *)xmlDictLookup(comp->dict, value5, -1);
1150 xmlFree(value5);
1151 } else
1152 comp->steps[comp->nbStep].value5 = NULL;
1153 } else {
1154 comp->steps[comp->nbStep].value4 = value4;
1155 comp->steps[comp->nbStep].value5 = value5;
1156 }
1157 comp->steps[comp->nbStep].cache = NULL;
1158 return(comp->nbStep++);
1159 }
1160
1161 /**
1162 * xmlXPathCompSwap:
1163 * @comp: the compiled expression
1164 * @op: operation index
1165 *
1166 * Swaps 2 operations in the compiled expression
1167 */
1168 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1169 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1170 int tmp;
1171
1172 #ifndef LIBXML_THREAD_ENABLED
1173 /*
1174 * Since this manipulates possibly shared variables, this is
1175 * disabled if one detects that the library is used in a multithreaded
1176 * application
1177 */
1178 if (xmlXPathDisableOptimizer)
1179 return;
1180 #endif
1181
1182 tmp = op->ch1;
1183 op->ch1 = op->ch2;
1184 op->ch2 = tmp;
1185 }
1186
1187 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1188 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1189 (op), (val), (val2), (val3), (val4), (val5))
1190 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1191 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1192 (op), (val), (val2), (val3), (val4), (val5))
1193
1194 #define PUSH_LEAVE_EXPR(op, val, val2) \
1195 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1196
1197 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1198 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1199
1200 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1201 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1202 (val), (val2), 0 ,NULL ,NULL)
1203
1204 /************************************************************************
1205 * *
1206 * XPath object cache structures *
1207 * *
1208 ************************************************************************/
1209
1210 /* #define XP_DEFAULT_CACHE_ON */
1211
1212 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1213
1214 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1215 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1216 struct _xmlXPathContextCache {
1217 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1218 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1219 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1220 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1221 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1222 int maxNodeset;
1223 int maxString;
1224 int maxBoolean;
1225 int maxNumber;
1226 int maxMisc;
1227 #ifdef XP_DEBUG_OBJ_USAGE
1228 int dbgCachedAll;
1229 int dbgCachedNodeset;
1230 int dbgCachedString;
1231 int dbgCachedBool;
1232 int dbgCachedNumber;
1233 int dbgCachedPoint;
1234 int dbgCachedRange;
1235 int dbgCachedLocset;
1236 int dbgCachedUsers;
1237 int dbgCachedXSLTTree;
1238 int dbgCachedUndefined;
1239
1240
1241 int dbgReusedAll;
1242 int dbgReusedNodeset;
1243 int dbgReusedString;
1244 int dbgReusedBool;
1245 int dbgReusedNumber;
1246 int dbgReusedPoint;
1247 int dbgReusedRange;
1248 int dbgReusedLocset;
1249 int dbgReusedUsers;
1250 int dbgReusedXSLTTree;
1251 int dbgReusedUndefined;
1252
1253 #endif
1254 };
1255
1256 /************************************************************************
1257 * *
1258 * Debugging related functions *
1259 * *
1260 ************************************************************************/
1261
1262 #define STRANGE \
1263 xmlGenericError(xmlGenericErrorContext, \
1264 "Internal error at %s:%d\n", \
1265 __FILE__, __LINE__);
1266
1267 #ifdef LIBXML_DEBUG_ENABLED
1268 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1269 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1270 int i;
1271 char shift[100];
1272
1273 for (i = 0;((i < depth) && (i < 25));i++)
1274 shift[2 * i] = shift[2 * i + 1] = ' ';
1275 shift[2 * i] = shift[2 * i + 1] = 0;
1276 if (cur == NULL) {
1277 fprintf(output, "%s", shift);
1278 fprintf(output, "Node is NULL !\n");
1279 return;
1280
1281 }
1282
1283 if ((cur->type == XML_DOCUMENT_NODE) ||
1284 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1285 fprintf(output, "%s", shift);
1286 fprintf(output, " /\n");
1287 } else if (cur->type == XML_ATTRIBUTE_NODE)
1288 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1289 else
1290 xmlDebugDumpOneNode(output, cur, depth);
1291 }
1292 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1293 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1294 xmlNodePtr tmp;
1295 int i;
1296 char shift[100];
1297
1298 for (i = 0;((i < depth) && (i < 25));i++)
1299 shift[2 * i] = shift[2 * i + 1] = ' ';
1300 shift[2 * i] = shift[2 * i + 1] = 0;
1301 if (cur == NULL) {
1302 fprintf(output, "%s", shift);
1303 fprintf(output, "Node is NULL !\n");
1304 return;
1305
1306 }
1307
1308 while (cur != NULL) {
1309 tmp = cur;
1310 cur = cur->next;
1311 xmlDebugDumpOneNode(output, tmp, depth);
1312 }
1313 }
1314
1315 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1316 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1317 int i;
1318 char shift[100];
1319
1320 for (i = 0;((i < depth) && (i < 25));i++)
1321 shift[2 * i] = shift[2 * i + 1] = ' ';
1322 shift[2 * i] = shift[2 * i + 1] = 0;
1323
1324 if (cur == NULL) {
1325 fprintf(output, "%s", shift);
1326 fprintf(output, "NodeSet is NULL !\n");
1327 return;
1328
1329 }
1330
1331 if (cur != NULL) {
1332 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1333 for (i = 0;i < cur->nodeNr;i++) {
1334 fprintf(output, "%s", shift);
1335 fprintf(output, "%d", i + 1);
1336 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1337 }
1338 }
1339 }
1340
1341 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1342 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1343 int i;
1344 char shift[100];
1345
1346 for (i = 0;((i < depth) && (i < 25));i++)
1347 shift[2 * i] = shift[2 * i + 1] = ' ';
1348 shift[2 * i] = shift[2 * i + 1] = 0;
1349
1350 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1351 fprintf(output, "%s", shift);
1352 fprintf(output, "Value Tree is NULL !\n");
1353 return;
1354
1355 }
1356
1357 fprintf(output, "%s", shift);
1358 fprintf(output, "%d", i + 1);
1359 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1360 }
1361 #if defined(LIBXML_XPTR_LOCS_ENABLED)
1362 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1363 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1364 int i;
1365 char shift[100];
1366
1367 for (i = 0;((i < depth) && (i < 25));i++)
1368 shift[2 * i] = shift[2 * i + 1] = ' ';
1369 shift[2 * i] = shift[2 * i + 1] = 0;
1370
1371 if (cur == NULL) {
1372 fprintf(output, "%s", shift);
1373 fprintf(output, "LocationSet is NULL !\n");
1374 return;
1375
1376 }
1377
1378 for (i = 0;i < cur->locNr;i++) {
1379 fprintf(output, "%s", shift);
1380 fprintf(output, "%d : ", i + 1);
1381 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1382 }
1383 }
1384 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1385
1386 /**
1387 * xmlXPathDebugDumpObject:
1388 * @output: the FILE * to dump the output
1389 * @cur: the object to inspect
1390 * @depth: indentation level
1391 *
1392 * Dump the content of the object for debugging purposes
1393 */
1394 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1395 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1396 int i;
1397 char shift[100];
1398
1399 if (output == NULL) return;
1400
1401 for (i = 0;((i < depth) && (i < 25));i++)
1402 shift[2 * i] = shift[2 * i + 1] = ' ';
1403 shift[2 * i] = shift[2 * i + 1] = 0;
1404
1405
1406 fprintf(output, "%s", shift);
1407
1408 if (cur == NULL) {
1409 fprintf(output, "Object is empty (NULL)\n");
1410 return;
1411 }
1412 switch(cur->type) {
1413 case XPATH_UNDEFINED:
1414 fprintf(output, "Object is uninitialized\n");
1415 break;
1416 case XPATH_NODESET:
1417 fprintf(output, "Object is a Node Set :\n");
1418 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1419 break;
1420 case XPATH_XSLT_TREE:
1421 fprintf(output, "Object is an XSLT value tree :\n");
1422 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1423 break;
1424 case XPATH_BOOLEAN:
1425 fprintf(output, "Object is a Boolean : ");
1426 if (cur->boolval) fprintf(output, "true\n");
1427 else fprintf(output, "false\n");
1428 break;
1429 case XPATH_NUMBER:
1430 switch (xmlXPathIsInf(cur->floatval)) {
1431 case 1:
1432 fprintf(output, "Object is a number : Infinity\n");
1433 break;
1434 case -1:
1435 fprintf(output, "Object is a number : -Infinity\n");
1436 break;
1437 default:
1438 if (xmlXPathIsNaN(cur->floatval)) {
1439 fprintf(output, "Object is a number : NaN\n");
1440 } else if (cur->floatval == 0) {
1441 /* Omit sign for negative zero. */
1442 fprintf(output, "Object is a number : 0\n");
1443 } else {
1444 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1445 }
1446 }
1447 break;
1448 case XPATH_STRING:
1449 fprintf(output, "Object is a string : ");
1450 xmlDebugDumpString(output, cur->stringval);
1451 fprintf(output, "\n");
1452 break;
1453 #ifdef LIBXML_XPTR_LOCS_ENABLED
1454 case XPATH_POINT:
1455 fprintf(output, "Object is a point : index %d in node", cur->index);
1456 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1457 fprintf(output, "\n");
1458 break;
1459 case XPATH_RANGE:
1460 if ((cur->user2 == NULL) ||
1461 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1462 fprintf(output, "Object is a collapsed range :\n");
1463 fprintf(output, "%s", shift);
1464 if (cur->index >= 0)
1465 fprintf(output, "index %d in ", cur->index);
1466 fprintf(output, "node\n");
1467 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1468 depth + 1);
1469 } else {
1470 fprintf(output, "Object is a range :\n");
1471 fprintf(output, "%s", shift);
1472 fprintf(output, "From ");
1473 if (cur->index >= 0)
1474 fprintf(output, "index %d in ", cur->index);
1475 fprintf(output, "node\n");
1476 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1477 depth + 1);
1478 fprintf(output, "%s", shift);
1479 fprintf(output, "To ");
1480 if (cur->index2 >= 0)
1481 fprintf(output, "index %d in ", cur->index2);
1482 fprintf(output, "node\n");
1483 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1484 depth + 1);
1485 fprintf(output, "\n");
1486 }
1487 break;
1488 case XPATH_LOCATIONSET:
1489 fprintf(output, "Object is a Location Set:\n");
1490 xmlXPathDebugDumpLocationSet(output,
1491 (xmlLocationSetPtr) cur->user, depth);
1492 break;
1493 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1494 case XPATH_USERS:
1495 fprintf(output, "Object is user defined\n");
1496 break;
1497 }
1498 }
1499
1500 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1501 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1502 xmlXPathStepOpPtr op, int depth) {
1503 int i;
1504 char shift[100];
1505
1506 for (i = 0;((i < depth) && (i < 25));i++)
1507 shift[2 * i] = shift[2 * i + 1] = ' ';
1508 shift[2 * i] = shift[2 * i + 1] = 0;
1509
1510 fprintf(output, "%s", shift);
1511 if (op == NULL) {
1512 fprintf(output, "Step is NULL\n");
1513 return;
1514 }
1515 switch (op->op) {
1516 case XPATH_OP_END:
1517 fprintf(output, "END"); break;
1518 case XPATH_OP_AND:
1519 fprintf(output, "AND"); break;
1520 case XPATH_OP_OR:
1521 fprintf(output, "OR"); break;
1522 case XPATH_OP_EQUAL:
1523 if (op->value)
1524 fprintf(output, "EQUAL =");
1525 else
1526 fprintf(output, "EQUAL !=");
1527 break;
1528 case XPATH_OP_CMP:
1529 if (op->value)
1530 fprintf(output, "CMP <");
1531 else
1532 fprintf(output, "CMP >");
1533 if (!op->value2)
1534 fprintf(output, "=");
1535 break;
1536 case XPATH_OP_PLUS:
1537 if (op->value == 0)
1538 fprintf(output, "PLUS -");
1539 else if (op->value == 1)
1540 fprintf(output, "PLUS +");
1541 else if (op->value == 2)
1542 fprintf(output, "PLUS unary -");
1543 else if (op->value == 3)
1544 fprintf(output, "PLUS unary - -");
1545 break;
1546 case XPATH_OP_MULT:
1547 if (op->value == 0)
1548 fprintf(output, "MULT *");
1549 else if (op->value == 1)
1550 fprintf(output, "MULT div");
1551 else
1552 fprintf(output, "MULT mod");
1553 break;
1554 case XPATH_OP_UNION:
1555 fprintf(output, "UNION"); break;
1556 case XPATH_OP_ROOT:
1557 fprintf(output, "ROOT"); break;
1558 case XPATH_OP_NODE:
1559 fprintf(output, "NODE"); break;
1560 case XPATH_OP_SORT:
1561 fprintf(output, "SORT"); break;
1562 case XPATH_OP_COLLECT: {
1563 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1564 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1565 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1566 const xmlChar *prefix = op->value4;
1567 const xmlChar *name = op->value5;
1568
1569 fprintf(output, "COLLECT ");
1570 switch (axis) {
1571 case AXIS_ANCESTOR:
1572 fprintf(output, " 'ancestors' "); break;
1573 case AXIS_ANCESTOR_OR_SELF:
1574 fprintf(output, " 'ancestors-or-self' "); break;
1575 case AXIS_ATTRIBUTE:
1576 fprintf(output, " 'attributes' "); break;
1577 case AXIS_CHILD:
1578 fprintf(output, " 'child' "); break;
1579 case AXIS_DESCENDANT:
1580 fprintf(output, " 'descendant' "); break;
1581 case AXIS_DESCENDANT_OR_SELF:
1582 fprintf(output, " 'descendant-or-self' "); break;
1583 case AXIS_FOLLOWING:
1584 fprintf(output, " 'following' "); break;
1585 case AXIS_FOLLOWING_SIBLING:
1586 fprintf(output, " 'following-siblings' "); break;
1587 case AXIS_NAMESPACE:
1588 fprintf(output, " 'namespace' "); break;
1589 case AXIS_PARENT:
1590 fprintf(output, " 'parent' "); break;
1591 case AXIS_PRECEDING:
1592 fprintf(output, " 'preceding' "); break;
1593 case AXIS_PRECEDING_SIBLING:
1594 fprintf(output, " 'preceding-sibling' "); break;
1595 case AXIS_SELF:
1596 fprintf(output, " 'self' "); break;
1597 }
1598 switch (test) {
1599 case NODE_TEST_NONE:
1600 fprintf(output, "'none' "); break;
1601 case NODE_TEST_TYPE:
1602 fprintf(output, "'type' "); break;
1603 case NODE_TEST_PI:
1604 fprintf(output, "'PI' "); break;
1605 case NODE_TEST_ALL:
1606 fprintf(output, "'all' "); break;
1607 case NODE_TEST_NS:
1608 fprintf(output, "'namespace' "); break;
1609 case NODE_TEST_NAME:
1610 fprintf(output, "'name' "); break;
1611 }
1612 switch (type) {
1613 case NODE_TYPE_NODE:
1614 fprintf(output, "'node' "); break;
1615 case NODE_TYPE_COMMENT:
1616 fprintf(output, "'comment' "); break;
1617 case NODE_TYPE_TEXT:
1618 fprintf(output, "'text' "); break;
1619 case NODE_TYPE_PI:
1620 fprintf(output, "'PI' "); break;
1621 }
1622 if (prefix != NULL)
1623 fprintf(output, "%s:", prefix);
1624 if (name != NULL)
1625 fprintf(output, "%s", (const char *) name);
1626 break;
1627
1628 }
1629 case XPATH_OP_VALUE: {
1630 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1631
1632 fprintf(output, "ELEM ");
1633 xmlXPathDebugDumpObject(output, object, 0);
1634 goto finish;
1635 }
1636 case XPATH_OP_VARIABLE: {
1637 const xmlChar *prefix = op->value5;
1638 const xmlChar *name = op->value4;
1639
1640 if (prefix != NULL)
1641 fprintf(output, "VARIABLE %s:%s", prefix, name);
1642 else
1643 fprintf(output, "VARIABLE %s", name);
1644 break;
1645 }
1646 case XPATH_OP_FUNCTION: {
1647 int nbargs = op->value;
1648 const xmlChar *prefix = op->value5;
1649 const xmlChar *name = op->value4;
1650
1651 if (prefix != NULL)
1652 fprintf(output, "FUNCTION %s:%s(%d args)",
1653 prefix, name, nbargs);
1654 else
1655 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1656 break;
1657 }
1658 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1659 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1660 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1661 #ifdef LIBXML_XPTR_LOCS_ENABLED
1662 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1663 #endif
1664 default:
1665 fprintf(output, "UNKNOWN %d\n", op->op); return;
1666 }
1667 fprintf(output, "\n");
1668 finish:
1669 if (op->ch1 >= 0)
1670 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1671 if (op->ch2 >= 0)
1672 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1673 }
1674
1675 /**
1676 * xmlXPathDebugDumpCompExpr:
1677 * @output: the FILE * for the output
1678 * @comp: the precompiled XPath expression
1679 * @depth: the indentation level.
1680 *
1681 * Dumps the tree of the compiled XPath expression.
1682 */
1683 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1684 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1685 int depth) {
1686 int i;
1687 char shift[100];
1688
1689 if ((output == NULL) || (comp == NULL)) return;
1690
1691 for (i = 0;((i < depth) && (i < 25));i++)
1692 shift[2 * i] = shift[2 * i + 1] = ' ';
1693 shift[2 * i] = shift[2 * i + 1] = 0;
1694
1695 fprintf(output, "%s", shift);
1696
1697 #ifdef XPATH_STREAMING
1698 if (comp->stream) {
1699 fprintf(output, "Streaming Expression\n");
1700 } else
1701 #endif
1702 {
1703 fprintf(output, "Compiled Expression : %d elements\n",
1704 comp->nbStep);
1705 i = comp->last;
1706 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1707 }
1708 }
1709
1710 #ifdef XP_DEBUG_OBJ_USAGE
1711
1712 /*
1713 * XPath object usage related debugging variables.
1714 */
1715 static int xmlXPathDebugObjCounterUndefined = 0;
1716 static int xmlXPathDebugObjCounterNodeset = 0;
1717 static int xmlXPathDebugObjCounterBool = 0;
1718 static int xmlXPathDebugObjCounterNumber = 0;
1719 static int xmlXPathDebugObjCounterString = 0;
1720 static int xmlXPathDebugObjCounterPoint = 0;
1721 static int xmlXPathDebugObjCounterRange = 0;
1722 static int xmlXPathDebugObjCounterLocset = 0;
1723 static int xmlXPathDebugObjCounterUsers = 0;
1724 static int xmlXPathDebugObjCounterXSLTTree = 0;
1725 static int xmlXPathDebugObjCounterAll = 0;
1726
1727 static int xmlXPathDebugObjTotalUndefined = 0;
1728 static int xmlXPathDebugObjTotalNodeset = 0;
1729 static int xmlXPathDebugObjTotalBool = 0;
1730 static int xmlXPathDebugObjTotalNumber = 0;
1731 static int xmlXPathDebugObjTotalString = 0;
1732 static int xmlXPathDebugObjTotalPoint = 0;
1733 static int xmlXPathDebugObjTotalRange = 0;
1734 static int xmlXPathDebugObjTotalLocset = 0;
1735 static int xmlXPathDebugObjTotalUsers = 0;
1736 static int xmlXPathDebugObjTotalXSLTTree = 0;
1737 static int xmlXPathDebugObjTotalAll = 0;
1738
1739 static int xmlXPathDebugObjMaxUndefined = 0;
1740 static int xmlXPathDebugObjMaxNodeset = 0;
1741 static int xmlXPathDebugObjMaxBool = 0;
1742 static int xmlXPathDebugObjMaxNumber = 0;
1743 static int xmlXPathDebugObjMaxString = 0;
1744 static int xmlXPathDebugObjMaxPoint = 0;
1745 static int xmlXPathDebugObjMaxRange = 0;
1746 static int xmlXPathDebugObjMaxLocset = 0;
1747 static int xmlXPathDebugObjMaxUsers = 0;
1748 static int xmlXPathDebugObjMaxXSLTTree = 0;
1749 static int xmlXPathDebugObjMaxAll = 0;
1750
1751 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1752 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1753 {
1754 if (ctxt != NULL) {
1755 if (ctxt->cache != NULL) {
1756 xmlXPathContextCachePtr cache =
1757 (xmlXPathContextCachePtr) ctxt->cache;
1758
1759 cache->dbgCachedAll = 0;
1760 cache->dbgCachedNodeset = 0;
1761 cache->dbgCachedString = 0;
1762 cache->dbgCachedBool = 0;
1763 cache->dbgCachedNumber = 0;
1764 cache->dbgCachedPoint = 0;
1765 cache->dbgCachedRange = 0;
1766 cache->dbgCachedLocset = 0;
1767 cache->dbgCachedUsers = 0;
1768 cache->dbgCachedXSLTTree = 0;
1769 cache->dbgCachedUndefined = 0;
1770
1771 cache->dbgReusedAll = 0;
1772 cache->dbgReusedNodeset = 0;
1773 cache->dbgReusedString = 0;
1774 cache->dbgReusedBool = 0;
1775 cache->dbgReusedNumber = 0;
1776 cache->dbgReusedPoint = 0;
1777 cache->dbgReusedRange = 0;
1778 cache->dbgReusedLocset = 0;
1779 cache->dbgReusedUsers = 0;
1780 cache->dbgReusedXSLTTree = 0;
1781 cache->dbgReusedUndefined = 0;
1782 }
1783 }
1784
1785 xmlXPathDebugObjCounterUndefined = 0;
1786 xmlXPathDebugObjCounterNodeset = 0;
1787 xmlXPathDebugObjCounterBool = 0;
1788 xmlXPathDebugObjCounterNumber = 0;
1789 xmlXPathDebugObjCounterString = 0;
1790 xmlXPathDebugObjCounterPoint = 0;
1791 xmlXPathDebugObjCounterRange = 0;
1792 xmlXPathDebugObjCounterLocset = 0;
1793 xmlXPathDebugObjCounterUsers = 0;
1794 xmlXPathDebugObjCounterXSLTTree = 0;
1795 xmlXPathDebugObjCounterAll = 0;
1796
1797 xmlXPathDebugObjTotalUndefined = 0;
1798 xmlXPathDebugObjTotalNodeset = 0;
1799 xmlXPathDebugObjTotalBool = 0;
1800 xmlXPathDebugObjTotalNumber = 0;
1801 xmlXPathDebugObjTotalString = 0;
1802 xmlXPathDebugObjTotalPoint = 0;
1803 xmlXPathDebugObjTotalRange = 0;
1804 xmlXPathDebugObjTotalLocset = 0;
1805 xmlXPathDebugObjTotalUsers = 0;
1806 xmlXPathDebugObjTotalXSLTTree = 0;
1807 xmlXPathDebugObjTotalAll = 0;
1808
1809 xmlXPathDebugObjMaxUndefined = 0;
1810 xmlXPathDebugObjMaxNodeset = 0;
1811 xmlXPathDebugObjMaxBool = 0;
1812 xmlXPathDebugObjMaxNumber = 0;
1813 xmlXPathDebugObjMaxString = 0;
1814 xmlXPathDebugObjMaxPoint = 0;
1815 xmlXPathDebugObjMaxRange = 0;
1816 xmlXPathDebugObjMaxLocset = 0;
1817 xmlXPathDebugObjMaxUsers = 0;
1818 xmlXPathDebugObjMaxXSLTTree = 0;
1819 xmlXPathDebugObjMaxAll = 0;
1820
1821 }
1822
1823 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1824 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1825 xmlXPathObjectType objType)
1826 {
1827 int isCached = 0;
1828
1829 if (ctxt != NULL) {
1830 if (ctxt->cache != NULL) {
1831 xmlXPathContextCachePtr cache =
1832 (xmlXPathContextCachePtr) ctxt->cache;
1833
1834 isCached = 1;
1835
1836 cache->dbgReusedAll++;
1837 switch (objType) {
1838 case XPATH_UNDEFINED:
1839 cache->dbgReusedUndefined++;
1840 break;
1841 case XPATH_NODESET:
1842 cache->dbgReusedNodeset++;
1843 break;
1844 case XPATH_BOOLEAN:
1845 cache->dbgReusedBool++;
1846 break;
1847 case XPATH_NUMBER:
1848 cache->dbgReusedNumber++;
1849 break;
1850 case XPATH_STRING:
1851 cache->dbgReusedString++;
1852 break;
1853 #ifdef LIBXML_XPTR_LOCS_ENABLED
1854 case XPATH_POINT:
1855 cache->dbgReusedPoint++;
1856 break;
1857 case XPATH_RANGE:
1858 cache->dbgReusedRange++;
1859 break;
1860 case XPATH_LOCATIONSET:
1861 cache->dbgReusedLocset++;
1862 break;
1863 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1864 case XPATH_USERS:
1865 cache->dbgReusedUsers++;
1866 break;
1867 case XPATH_XSLT_TREE:
1868 cache->dbgReusedXSLTTree++;
1869 break;
1870 default:
1871 break;
1872 }
1873 }
1874 }
1875
1876 switch (objType) {
1877 case XPATH_UNDEFINED:
1878 if (! isCached)
1879 xmlXPathDebugObjTotalUndefined++;
1880 xmlXPathDebugObjCounterUndefined++;
1881 if (xmlXPathDebugObjCounterUndefined >
1882 xmlXPathDebugObjMaxUndefined)
1883 xmlXPathDebugObjMaxUndefined =
1884 xmlXPathDebugObjCounterUndefined;
1885 break;
1886 case XPATH_NODESET:
1887 if (! isCached)
1888 xmlXPathDebugObjTotalNodeset++;
1889 xmlXPathDebugObjCounterNodeset++;
1890 if (xmlXPathDebugObjCounterNodeset >
1891 xmlXPathDebugObjMaxNodeset)
1892 xmlXPathDebugObjMaxNodeset =
1893 xmlXPathDebugObjCounterNodeset;
1894 break;
1895 case XPATH_BOOLEAN:
1896 if (! isCached)
1897 xmlXPathDebugObjTotalBool++;
1898 xmlXPathDebugObjCounterBool++;
1899 if (xmlXPathDebugObjCounterBool >
1900 xmlXPathDebugObjMaxBool)
1901 xmlXPathDebugObjMaxBool =
1902 xmlXPathDebugObjCounterBool;
1903 break;
1904 case XPATH_NUMBER:
1905 if (! isCached)
1906 xmlXPathDebugObjTotalNumber++;
1907 xmlXPathDebugObjCounterNumber++;
1908 if (xmlXPathDebugObjCounterNumber >
1909 xmlXPathDebugObjMaxNumber)
1910 xmlXPathDebugObjMaxNumber =
1911 xmlXPathDebugObjCounterNumber;
1912 break;
1913 case XPATH_STRING:
1914 if (! isCached)
1915 xmlXPathDebugObjTotalString++;
1916 xmlXPathDebugObjCounterString++;
1917 if (xmlXPathDebugObjCounterString >
1918 xmlXPathDebugObjMaxString)
1919 xmlXPathDebugObjMaxString =
1920 xmlXPathDebugObjCounterString;
1921 break;
1922 #ifdef LIBXML_XPTR_LOCS_ENABLED
1923 case XPATH_POINT:
1924 if (! isCached)
1925 xmlXPathDebugObjTotalPoint++;
1926 xmlXPathDebugObjCounterPoint++;
1927 if (xmlXPathDebugObjCounterPoint >
1928 xmlXPathDebugObjMaxPoint)
1929 xmlXPathDebugObjMaxPoint =
1930 xmlXPathDebugObjCounterPoint;
1931 break;
1932 case XPATH_RANGE:
1933 if (! isCached)
1934 xmlXPathDebugObjTotalRange++;
1935 xmlXPathDebugObjCounterRange++;
1936 if (xmlXPathDebugObjCounterRange >
1937 xmlXPathDebugObjMaxRange)
1938 xmlXPathDebugObjMaxRange =
1939 xmlXPathDebugObjCounterRange;
1940 break;
1941 case XPATH_LOCATIONSET:
1942 if (! isCached)
1943 xmlXPathDebugObjTotalLocset++;
1944 xmlXPathDebugObjCounterLocset++;
1945 if (xmlXPathDebugObjCounterLocset >
1946 xmlXPathDebugObjMaxLocset)
1947 xmlXPathDebugObjMaxLocset =
1948 xmlXPathDebugObjCounterLocset;
1949 break;
1950 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1951 case XPATH_USERS:
1952 if (! isCached)
1953 xmlXPathDebugObjTotalUsers++;
1954 xmlXPathDebugObjCounterUsers++;
1955 if (xmlXPathDebugObjCounterUsers >
1956 xmlXPathDebugObjMaxUsers)
1957 xmlXPathDebugObjMaxUsers =
1958 xmlXPathDebugObjCounterUsers;
1959 break;
1960 case XPATH_XSLT_TREE:
1961 if (! isCached)
1962 xmlXPathDebugObjTotalXSLTTree++;
1963 xmlXPathDebugObjCounterXSLTTree++;
1964 if (xmlXPathDebugObjCounterXSLTTree >
1965 xmlXPathDebugObjMaxXSLTTree)
1966 xmlXPathDebugObjMaxXSLTTree =
1967 xmlXPathDebugObjCounterXSLTTree;
1968 break;
1969 default:
1970 break;
1971 }
1972 if (! isCached)
1973 xmlXPathDebugObjTotalAll++;
1974 xmlXPathDebugObjCounterAll++;
1975 if (xmlXPathDebugObjCounterAll >
1976 xmlXPathDebugObjMaxAll)
1977 xmlXPathDebugObjMaxAll =
1978 xmlXPathDebugObjCounterAll;
1979 }
1980
1981 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1982 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1983 xmlXPathObjectType objType)
1984 {
1985 int isCached = 0;
1986
1987 if (ctxt != NULL) {
1988 if (ctxt->cache != NULL) {
1989 xmlXPathContextCachePtr cache =
1990 (xmlXPathContextCachePtr) ctxt->cache;
1991
1992 isCached = 1;
1993
1994 cache->dbgCachedAll++;
1995 switch (objType) {
1996 case XPATH_UNDEFINED:
1997 cache->dbgCachedUndefined++;
1998 break;
1999 case XPATH_NODESET:
2000 cache->dbgCachedNodeset++;
2001 break;
2002 case XPATH_BOOLEAN:
2003 cache->dbgCachedBool++;
2004 break;
2005 case XPATH_NUMBER:
2006 cache->dbgCachedNumber++;
2007 break;
2008 case XPATH_STRING:
2009 cache->dbgCachedString++;
2010 break;
2011 #ifdef LIBXML_XPTR_LOCS_ENABLED
2012 case XPATH_POINT:
2013 cache->dbgCachedPoint++;
2014 break;
2015 case XPATH_RANGE:
2016 cache->dbgCachedRange++;
2017 break;
2018 case XPATH_LOCATIONSET:
2019 cache->dbgCachedLocset++;
2020 break;
2021 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2022 case XPATH_USERS:
2023 cache->dbgCachedUsers++;
2024 break;
2025 case XPATH_XSLT_TREE:
2026 cache->dbgCachedXSLTTree++;
2027 break;
2028 default:
2029 break;
2030 }
2031
2032 }
2033 }
2034 switch (objType) {
2035 case XPATH_UNDEFINED:
2036 xmlXPathDebugObjCounterUndefined--;
2037 break;
2038 case XPATH_NODESET:
2039 xmlXPathDebugObjCounterNodeset--;
2040 break;
2041 case XPATH_BOOLEAN:
2042 xmlXPathDebugObjCounterBool--;
2043 break;
2044 case XPATH_NUMBER:
2045 xmlXPathDebugObjCounterNumber--;
2046 break;
2047 case XPATH_STRING:
2048 xmlXPathDebugObjCounterString--;
2049 break;
2050 #ifdef LIBXML_XPTR_LOCS_ENABLED
2051 case XPATH_POINT:
2052 xmlXPathDebugObjCounterPoint--;
2053 break;
2054 case XPATH_RANGE:
2055 xmlXPathDebugObjCounterRange--;
2056 break;
2057 case XPATH_LOCATIONSET:
2058 xmlXPathDebugObjCounterLocset--;
2059 break;
2060 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2061 case XPATH_USERS:
2062 xmlXPathDebugObjCounterUsers--;
2063 break;
2064 case XPATH_XSLT_TREE:
2065 xmlXPathDebugObjCounterXSLTTree--;
2066 break;
2067 default:
2068 break;
2069 }
2070 xmlXPathDebugObjCounterAll--;
2071 }
2072
2073 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2074 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2075 {
2076 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2077 reqXSLTTree, reqUndefined;
2078 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2079 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2080 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2081 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2082 int leftObjs = xmlXPathDebugObjCounterAll;
2083
2084 reqAll = xmlXPathDebugObjTotalAll;
2085 reqNodeset = xmlXPathDebugObjTotalNodeset;
2086 reqString = xmlXPathDebugObjTotalString;
2087 reqBool = xmlXPathDebugObjTotalBool;
2088 reqNumber = xmlXPathDebugObjTotalNumber;
2089 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2090 reqUndefined = xmlXPathDebugObjTotalUndefined;
2091
2092 printf("# XPath object usage:\n");
2093
2094 if (ctxt != NULL) {
2095 if (ctxt->cache != NULL) {
2096 xmlXPathContextCachePtr cache =
2097 (xmlXPathContextCachePtr) ctxt->cache;
2098
2099 reAll = cache->dbgReusedAll;
2100 reqAll += reAll;
2101 reNodeset = cache->dbgReusedNodeset;
2102 reqNodeset += reNodeset;
2103 reString = cache->dbgReusedString;
2104 reqString += reString;
2105 reBool = cache->dbgReusedBool;
2106 reqBool += reBool;
2107 reNumber = cache->dbgReusedNumber;
2108 reqNumber += reNumber;
2109 reXSLTTree = cache->dbgReusedXSLTTree;
2110 reqXSLTTree += reXSLTTree;
2111 reUndefined = cache->dbgReusedUndefined;
2112 reqUndefined += reUndefined;
2113
2114 caAll = cache->dbgCachedAll;
2115 caBool = cache->dbgCachedBool;
2116 caNodeset = cache->dbgCachedNodeset;
2117 caString = cache->dbgCachedString;
2118 caNumber = cache->dbgCachedNumber;
2119 caXSLTTree = cache->dbgCachedXSLTTree;
2120 caUndefined = cache->dbgCachedUndefined;
2121
2122 if (cache->nodesetObjs)
2123 leftObjs -= cache->nodesetObjs->number;
2124 if (cache->stringObjs)
2125 leftObjs -= cache->stringObjs->number;
2126 if (cache->booleanObjs)
2127 leftObjs -= cache->booleanObjs->number;
2128 if (cache->numberObjs)
2129 leftObjs -= cache->numberObjs->number;
2130 if (cache->miscObjs)
2131 leftObjs -= cache->miscObjs->number;
2132 }
2133 }
2134
2135 printf("# all\n");
2136 printf("# total : %d\n", reqAll);
2137 printf("# left : %d\n", leftObjs);
2138 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2139 printf("# reused : %d\n", reAll);
2140 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2141
2142 printf("# node-sets\n");
2143 printf("# total : %d\n", reqNodeset);
2144 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2145 printf("# reused : %d\n", reNodeset);
2146 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2147
2148 printf("# strings\n");
2149 printf("# total : %d\n", reqString);
2150 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2151 printf("# reused : %d\n", reString);
2152 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2153
2154 printf("# booleans\n");
2155 printf("# total : %d\n", reqBool);
2156 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2157 printf("# reused : %d\n", reBool);
2158 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2159
2160 printf("# numbers\n");
2161 printf("# total : %d\n", reqNumber);
2162 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2163 printf("# reused : %d\n", reNumber);
2164 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2165
2166 printf("# XSLT result tree fragments\n");
2167 printf("# total : %d\n", reqXSLTTree);
2168 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2169 printf("# reused : %d\n", reXSLTTree);
2170 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2171
2172 printf("# undefined\n");
2173 printf("# total : %d\n", reqUndefined);
2174 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2175 printf("# reused : %d\n", reUndefined);
2176 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2177
2178 }
2179
2180 #endif /* XP_DEBUG_OBJ_USAGE */
2181
2182 #endif /* LIBXML_DEBUG_ENABLED */
2183
2184 /************************************************************************
2185 * *
2186 * XPath object caching *
2187 * *
2188 ************************************************************************/
2189
2190 /**
2191 * xmlXPathNewCache:
2192 *
2193 * Create a new object cache
2194 *
2195 * Returns the xmlXPathCache just allocated.
2196 */
2197 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2198 xmlXPathNewCache(void)
2199 {
2200 xmlXPathContextCachePtr ret;
2201
2202 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2203 if (ret == NULL) {
2204 xmlXPathErrMemory(NULL, "creating object cache\n");
2205 return(NULL);
2206 }
2207 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2208 ret->maxNodeset = 100;
2209 ret->maxString = 100;
2210 ret->maxBoolean = 100;
2211 ret->maxNumber = 100;
2212 ret->maxMisc = 100;
2213 return(ret);
2214 }
2215
2216 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2217 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2218 {
2219 int i;
2220 xmlXPathObjectPtr obj;
2221
2222 if (list == NULL)
2223 return;
2224
2225 for (i = 0; i < list->number; i++) {
2226 obj = list->items[i];
2227 /*
2228 * Note that it is already assured that we don't need to
2229 * look out for namespace nodes in the node-set.
2230 */
2231 if (obj->nodesetval != NULL) {
2232 if (obj->nodesetval->nodeTab != NULL)
2233 xmlFree(obj->nodesetval->nodeTab);
2234 xmlFree(obj->nodesetval);
2235 }
2236 xmlFree(obj);
2237 #ifdef XP_DEBUG_OBJ_USAGE
2238 xmlXPathDebugObjCounterAll--;
2239 #endif
2240 }
2241 xmlPointerListFree(list);
2242 }
2243
2244 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2245 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2246 {
2247 if (cache == NULL)
2248 return;
2249 if (cache->nodesetObjs)
2250 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2251 if (cache->stringObjs)
2252 xmlXPathCacheFreeObjectList(cache->stringObjs);
2253 if (cache->booleanObjs)
2254 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2255 if (cache->numberObjs)
2256 xmlXPathCacheFreeObjectList(cache->numberObjs);
2257 if (cache->miscObjs)
2258 xmlXPathCacheFreeObjectList(cache->miscObjs);
2259 xmlFree(cache);
2260 }
2261
2262 /**
2263 * xmlXPathContextSetCache:
2264 *
2265 * @ctxt: the XPath context
2266 * @active: enables/disables (creates/frees) the cache
2267 * @value: a value with semantics dependent on @options
2268 * @options: options (currently only the value 0 is used)
2269 *
2270 * Creates/frees an object cache on the XPath context.
2271 * If activates XPath objects (xmlXPathObject) will be cached internally
2272 * to be reused.
2273 * @options:
2274 * 0: This will set the XPath object caching:
2275 * @value:
2276 * This will set the maximum number of XPath objects
2277 * to be cached per slot
2278 * There are 5 slots for: node-set, string, number, boolean, and
2279 * misc objects. Use <0 for the default number (100).
2280 * Other values for @options have currently no effect.
2281 *
2282 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2283 */
2284 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2285 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2286 int active,
2287 int value,
2288 int options)
2289 {
2290 if (ctxt == NULL)
2291 return(-1);
2292 if (active) {
2293 xmlXPathContextCachePtr cache;
2294
2295 if (ctxt->cache == NULL) {
2296 ctxt->cache = xmlXPathNewCache();
2297 if (ctxt->cache == NULL)
2298 return(-1);
2299 }
2300 cache = (xmlXPathContextCachePtr) ctxt->cache;
2301 if (options == 0) {
2302 if (value < 0)
2303 value = 100;
2304 cache->maxNodeset = value;
2305 cache->maxString = value;
2306 cache->maxNumber = value;
2307 cache->maxBoolean = value;
2308 cache->maxMisc = value;
2309 }
2310 } else if (ctxt->cache != NULL) {
2311 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2312 ctxt->cache = NULL;
2313 }
2314 return(0);
2315 }
2316
2317 /**
2318 * xmlXPathCacheWrapNodeSet:
2319 * @ctxt: the XPath context
2320 * @val: the NodePtr value
2321 *
2322 * This is the cached version of xmlXPathWrapNodeSet().
2323 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2324 *
2325 * Returns the created or reused object.
2326 */
2327 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2328 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2329 {
2330 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2331 xmlXPathContextCachePtr cache =
2332 (xmlXPathContextCachePtr) ctxt->cache;
2333
2334 if ((cache->miscObjs != NULL) &&
2335 (cache->miscObjs->number != 0))
2336 {
2337 xmlXPathObjectPtr ret;
2338
2339 ret = (xmlXPathObjectPtr)
2340 cache->miscObjs->items[--cache->miscObjs->number];
2341 ret->type = XPATH_NODESET;
2342 ret->nodesetval = val;
2343 #ifdef XP_DEBUG_OBJ_USAGE
2344 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2345 #endif
2346 return(ret);
2347 }
2348 }
2349
2350 return(xmlXPathWrapNodeSet(val));
2351
2352 }
2353
2354 /**
2355 * xmlXPathCacheWrapString:
2356 * @ctxt: the XPath context
2357 * @val: the xmlChar * value
2358 *
2359 * This is the cached version of xmlXPathWrapString().
2360 * Wraps the @val string into an XPath object.
2361 *
2362 * Returns the created or reused object.
2363 */
2364 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2365 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2366 {
2367 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2368 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2369
2370 if ((cache->stringObjs != NULL) &&
2371 (cache->stringObjs->number != 0))
2372 {
2373
2374 xmlXPathObjectPtr ret;
2375
2376 ret = (xmlXPathObjectPtr)
2377 cache->stringObjs->items[--cache->stringObjs->number];
2378 ret->type = XPATH_STRING;
2379 ret->stringval = val;
2380 #ifdef XP_DEBUG_OBJ_USAGE
2381 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2382 #endif
2383 return(ret);
2384 } else if ((cache->miscObjs != NULL) &&
2385 (cache->miscObjs->number != 0))
2386 {
2387 xmlXPathObjectPtr ret;
2388 /*
2389 * Fallback to misc-cache.
2390 */
2391 ret = (xmlXPathObjectPtr)
2392 cache->miscObjs->items[--cache->miscObjs->number];
2393
2394 ret->type = XPATH_STRING;
2395 ret->stringval = val;
2396 #ifdef XP_DEBUG_OBJ_USAGE
2397 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2398 #endif
2399 return(ret);
2400 }
2401 }
2402 return(xmlXPathWrapString(val));
2403 }
2404
2405 /**
2406 * xmlXPathCacheNewNodeSet:
2407 * @ctxt: the XPath context
2408 * @val: the NodePtr value
2409 *
2410 * This is the cached version of xmlXPathNewNodeSet().
2411 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2412 * it with the single Node @val
2413 *
2414 * Returns the created or reused object.
2415 */
2416 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2417 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2418 {
2419 if ((ctxt != NULL) && (ctxt->cache)) {
2420 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2421
2422 if ((cache->nodesetObjs != NULL) &&
2423 (cache->nodesetObjs->number != 0))
2424 {
2425 xmlXPathObjectPtr ret;
2426 /*
2427 * Use the nodeset-cache.
2428 */
2429 ret = (xmlXPathObjectPtr)
2430 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2431 ret->type = XPATH_NODESET;
2432 ret->boolval = 0;
2433 if (val) {
2434 if ((ret->nodesetval->nodeMax == 0) ||
2435 (val->type == XML_NAMESPACE_DECL))
2436 {
2437 /* TODO: Check memory error. */
2438 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2439 } else {
2440 ret->nodesetval->nodeTab[0] = val;
2441 ret->nodesetval->nodeNr = 1;
2442 }
2443 }
2444 #ifdef XP_DEBUG_OBJ_USAGE
2445 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2446 #endif
2447 return(ret);
2448 } else if ((cache->miscObjs != NULL) &&
2449 (cache->miscObjs->number != 0))
2450 {
2451 xmlXPathObjectPtr ret;
2452 /*
2453 * Fallback to misc-cache.
2454 */
2455
2456 ret = (xmlXPathObjectPtr)
2457 cache->miscObjs->items[--cache->miscObjs->number];
2458
2459 ret->type = XPATH_NODESET;
2460 ret->boolval = 0;
2461 ret->nodesetval = xmlXPathNodeSetCreate(val);
2462 if (ret->nodesetval == NULL) {
2463 ctxt->lastError.domain = XML_FROM_XPATH;
2464 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2465 return(NULL);
2466 }
2467 #ifdef XP_DEBUG_OBJ_USAGE
2468 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2469 #endif
2470 return(ret);
2471 }
2472 }
2473 return(xmlXPathNewNodeSet(val));
2474 }
2475
2476 /**
2477 * xmlXPathCacheNewCString:
2478 * @ctxt: the XPath context
2479 * @val: the char * value
2480 *
2481 * This is the cached version of xmlXPathNewCString().
2482 * Acquire an xmlXPathObjectPtr of type string and of value @val
2483 *
2484 * Returns the created or reused object.
2485 */
2486 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2487 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2488 {
2489 if ((ctxt != NULL) && (ctxt->cache)) {
2490 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2491
2492 if ((cache->stringObjs != NULL) &&
2493 (cache->stringObjs->number != 0))
2494 {
2495 xmlXPathObjectPtr ret;
2496
2497 ret = (xmlXPathObjectPtr)
2498 cache->stringObjs->items[--cache->stringObjs->number];
2499
2500 ret->type = XPATH_STRING;
2501 ret->stringval = xmlStrdup(BAD_CAST val);
2502 #ifdef XP_DEBUG_OBJ_USAGE
2503 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2504 #endif
2505 return(ret);
2506 } else if ((cache->miscObjs != NULL) &&
2507 (cache->miscObjs->number != 0))
2508 {
2509 xmlXPathObjectPtr ret;
2510
2511 ret = (xmlXPathObjectPtr)
2512 cache->miscObjs->items[--cache->miscObjs->number];
2513
2514 ret->type = XPATH_STRING;
2515 ret->stringval = xmlStrdup(BAD_CAST val);
2516 #ifdef XP_DEBUG_OBJ_USAGE
2517 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2518 #endif
2519 return(ret);
2520 }
2521 }
2522 return(xmlXPathNewCString(val));
2523 }
2524
2525 /**
2526 * xmlXPathCacheNewString:
2527 * @ctxt: the XPath context
2528 * @val: the xmlChar * value
2529 *
2530 * This is the cached version of xmlXPathNewString().
2531 * Acquire an xmlXPathObjectPtr of type string and of value @val
2532 *
2533 * Returns the created or reused object.
2534 */
2535 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2536 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2537 {
2538 if ((ctxt != NULL) && (ctxt->cache)) {
2539 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2540
2541 if ((cache->stringObjs != NULL) &&
2542 (cache->stringObjs->number != 0))
2543 {
2544 xmlXPathObjectPtr ret;
2545
2546 ret = (xmlXPathObjectPtr)
2547 cache->stringObjs->items[--cache->stringObjs->number];
2548 ret->type = XPATH_STRING;
2549 if (val != NULL)
2550 ret->stringval = xmlStrdup(val);
2551 else
2552 ret->stringval = xmlStrdup((const xmlChar *)"");
2553 #ifdef XP_DEBUG_OBJ_USAGE
2554 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2555 #endif
2556 return(ret);
2557 } else if ((cache->miscObjs != NULL) &&
2558 (cache->miscObjs->number != 0))
2559 {
2560 xmlXPathObjectPtr ret;
2561
2562 ret = (xmlXPathObjectPtr)
2563 cache->miscObjs->items[--cache->miscObjs->number];
2564
2565 ret->type = XPATH_STRING;
2566 if (val != NULL)
2567 ret->stringval = xmlStrdup(val);
2568 else
2569 ret->stringval = xmlStrdup((const xmlChar *)"");
2570 #ifdef XP_DEBUG_OBJ_USAGE
2571 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2572 #endif
2573 return(ret);
2574 }
2575 }
2576 return(xmlXPathNewString(val));
2577 }
2578
2579 /**
2580 * xmlXPathCacheNewBoolean:
2581 * @ctxt: the XPath context
2582 * @val: the boolean value
2583 *
2584 * This is the cached version of xmlXPathNewBoolean().
2585 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2586 *
2587 * Returns the created or reused object.
2588 */
2589 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2590 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591 {
2592 if ((ctxt != NULL) && (ctxt->cache)) {
2593 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595 if ((cache->booleanObjs != NULL) &&
2596 (cache->booleanObjs->number != 0))
2597 {
2598 xmlXPathObjectPtr ret;
2599
2600 ret = (xmlXPathObjectPtr)
2601 cache->booleanObjs->items[--cache->booleanObjs->number];
2602 ret->type = XPATH_BOOLEAN;
2603 ret->boolval = (val != 0);
2604 #ifdef XP_DEBUG_OBJ_USAGE
2605 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606 #endif
2607 return(ret);
2608 } else if ((cache->miscObjs != NULL) &&
2609 (cache->miscObjs->number != 0))
2610 {
2611 xmlXPathObjectPtr ret;
2612
2613 ret = (xmlXPathObjectPtr)
2614 cache->miscObjs->items[--cache->miscObjs->number];
2615
2616 ret->type = XPATH_BOOLEAN;
2617 ret->boolval = (val != 0);
2618 #ifdef XP_DEBUG_OBJ_USAGE
2619 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620 #endif
2621 return(ret);
2622 }
2623 }
2624 return(xmlXPathNewBoolean(val));
2625 }
2626
2627 /**
2628 * xmlXPathCacheNewFloat:
2629 * @ctxt: the XPath context
2630 * @val: the double value
2631 *
2632 * This is the cached version of xmlXPathNewFloat().
2633 * Acquires an xmlXPathObjectPtr of type double and of value @val
2634 *
2635 * Returns the created or reused object.
2636 */
2637 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2638 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639 {
2640 if ((ctxt != NULL) && (ctxt->cache)) {
2641 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643 if ((cache->numberObjs != NULL) &&
2644 (cache->numberObjs->number != 0))
2645 {
2646 xmlXPathObjectPtr ret;
2647
2648 ret = (xmlXPathObjectPtr)
2649 cache->numberObjs->items[--cache->numberObjs->number];
2650 ret->type = XPATH_NUMBER;
2651 ret->floatval = val;
2652 #ifdef XP_DEBUG_OBJ_USAGE
2653 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654 #endif
2655 return(ret);
2656 } else if ((cache->miscObjs != NULL) &&
2657 (cache->miscObjs->number != 0))
2658 {
2659 xmlXPathObjectPtr ret;
2660
2661 ret = (xmlXPathObjectPtr)
2662 cache->miscObjs->items[--cache->miscObjs->number];
2663
2664 ret->type = XPATH_NUMBER;
2665 ret->floatval = val;
2666 #ifdef XP_DEBUG_OBJ_USAGE
2667 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668 #endif
2669 return(ret);
2670 }
2671 }
2672 return(xmlXPathNewFloat(val));
2673 }
2674
2675 /**
2676 * xmlXPathCacheConvertString:
2677 * @ctxt: the XPath context
2678 * @val: an XPath object
2679 *
2680 * This is the cached version of xmlXPathConvertString().
2681 * Converts an existing object to its string() equivalent
2682 *
2683 * Returns a created or reused object, the old one is freed (cached)
2684 * (or the operation is done directly on @val)
2685 */
2686
2687 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2688 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689 xmlChar *res = NULL;
2690
2691 if (val == NULL)
2692 return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694 switch (val->type) {
2695 case XPATH_UNDEFINED:
2696 #ifdef DEBUG_EXPR
2697 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698 #endif
2699 break;
2700 case XPATH_NODESET:
2701 case XPATH_XSLT_TREE:
2702 res = xmlXPathCastNodeSetToString(val->nodesetval);
2703 break;
2704 case XPATH_STRING:
2705 return(val);
2706 case XPATH_BOOLEAN:
2707 res = xmlXPathCastBooleanToString(val->boolval);
2708 break;
2709 case XPATH_NUMBER:
2710 res = xmlXPathCastNumberToString(val->floatval);
2711 break;
2712 case XPATH_USERS:
2713 #ifdef LIBXML_XPTR_LOCS_ENABLED
2714 case XPATH_POINT:
2715 case XPATH_RANGE:
2716 case XPATH_LOCATIONSET:
2717 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2718 TODO;
2719 break;
2720 }
2721 xmlXPathReleaseObject(ctxt, val);
2722 if (res == NULL)
2723 return(xmlXPathCacheNewCString(ctxt, ""));
2724 return(xmlXPathCacheWrapString(ctxt, res));
2725 }
2726
2727 /**
2728 * xmlXPathCacheObjectCopy:
2729 * @ctxt: the XPath context
2730 * @val: the original object
2731 *
2732 * This is the cached version of xmlXPathObjectCopy().
2733 * Acquire a copy of a given object
2734 *
2735 * Returns a created or reused created object.
2736 */
2737 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2738 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739 {
2740 if (val == NULL)
2741 return(NULL);
2742
2743 if (XP_HAS_CACHE(ctxt)) {
2744 switch (val->type) {
2745 case XPATH_NODESET:
2746 return(xmlXPathCacheWrapNodeSet(ctxt,
2747 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748 case XPATH_STRING:
2749 return(xmlXPathCacheNewString(ctxt, val->stringval));
2750 case XPATH_BOOLEAN:
2751 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752 case XPATH_NUMBER:
2753 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754 default:
2755 break;
2756 }
2757 }
2758 return(xmlXPathObjectCopy(val));
2759 }
2760
2761 /**
2762 * xmlXPathCacheConvertBoolean:
2763 * @ctxt: the XPath context
2764 * @val: an XPath object
2765 *
2766 * This is the cached version of xmlXPathConvertBoolean().
2767 * Converts an existing object to its boolean() equivalent
2768 *
2769 * Returns a created or reused object, the old one is freed (or the operation
2770 * is done directly on @val)
2771 */
2772 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2773 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774 xmlXPathObjectPtr ret;
2775
2776 if (val == NULL)
2777 return(xmlXPathCacheNewBoolean(ctxt, 0));
2778 if (val->type == XPATH_BOOLEAN)
2779 return(val);
2780 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781 xmlXPathReleaseObject(ctxt, val);
2782 return(ret);
2783 }
2784
2785 /**
2786 * xmlXPathCacheConvertNumber:
2787 * @ctxt: the XPath context
2788 * @val: an XPath object
2789 *
2790 * This is the cached version of xmlXPathConvertNumber().
2791 * Converts an existing object to its number() equivalent
2792 *
2793 * Returns a created or reused object, the old one is freed (or the operation
2794 * is done directly on @val)
2795 */
2796 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2797 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798 xmlXPathObjectPtr ret;
2799
2800 if (val == NULL)
2801 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802 if (val->type == XPATH_NUMBER)
2803 return(val);
2804 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805 xmlXPathReleaseObject(ctxt, val);
2806 return(ret);
2807 }
2808
2809 /************************************************************************
2810 * *
2811 * Parser stacks related functions and macros *
2812 * *
2813 ************************************************************************/
2814
2815 /**
2816 * xmlXPathSetFrame:
2817 * @ctxt: an XPath parser context
2818 *
2819 * Set the callee evaluation frame
2820 *
2821 * Returns the previous frame value to be restored once done
2822 */
2823 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2824 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2825 int ret;
2826
2827 if (ctxt == NULL)
2828 return(0);
2829 ret = ctxt->valueFrame;
2830 ctxt->valueFrame = ctxt->valueNr;
2831 return(ret);
2832 }
2833
2834 /**
2835 * xmlXPathPopFrame:
2836 * @ctxt: an XPath parser context
2837 * @frame: the previous frame value
2838 *
2839 * Remove the callee evaluation frame
2840 */
2841 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2842 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2843 if (ctxt == NULL)
2844 return;
2845 if (ctxt->valueNr < ctxt->valueFrame) {
2846 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2847 }
2848 ctxt->valueFrame = frame;
2849 }
2850
2851 /**
2852 * valuePop:
2853 * @ctxt: an XPath evaluation context
2854 *
2855 * Pops the top XPath object from the value stack
2856 *
2857 * Returns the XPath object just removed
2858 */
2859 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2860 valuePop(xmlXPathParserContextPtr ctxt)
2861 {
2862 xmlXPathObjectPtr ret;
2863
2864 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2865 return (NULL);
2866
2867 if (ctxt->valueNr <= ctxt->valueFrame) {
2868 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2869 return (NULL);
2870 }
2871
2872 ctxt->valueNr--;
2873 if (ctxt->valueNr > 0)
2874 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2875 else
2876 ctxt->value = NULL;
2877 ret = ctxt->valueTab[ctxt->valueNr];
2878 ctxt->valueTab[ctxt->valueNr] = NULL;
2879 return (ret);
2880 }
2881 /**
2882 * valuePush:
2883 * @ctxt: an XPath evaluation context
2884 * @value: the XPath object
2885 *
2886 * Pushes a new XPath object on top of the value stack. If value is NULL,
2887 * a memory error is recorded in the parser context.
2888 *
2889 * Returns the number of items on the value stack, or -1 in case of error.
2890 */
2891 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2892 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2893 {
2894 if (ctxt == NULL) return(-1);
2895 if (value == NULL) {
2896 /*
2897 * A NULL value typically indicates that a memory allocation failed,
2898 * so we set ctxt->error here to propagate the error.
2899 */
2900 ctxt->error = XPATH_MEMORY_ERROR;
2901 return(-1);
2902 }
2903 if (ctxt->valueNr >= ctxt->valueMax) {
2904 xmlXPathObjectPtr *tmp;
2905
2906 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2907 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2908 return (-1);
2909 }
2910 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2911 2 * ctxt->valueMax *
2912 sizeof(ctxt->valueTab[0]));
2913 if (tmp == NULL) {
2914 xmlXPathPErrMemory(ctxt, "pushing value\n");
2915 return (-1);
2916 }
2917 ctxt->valueMax *= 2;
2918 ctxt->valueTab = tmp;
2919 }
2920 ctxt->valueTab[ctxt->valueNr] = value;
2921 ctxt->value = value;
2922 return (ctxt->valueNr++);
2923 }
2924
2925 /**
2926 * xmlXPathPopBoolean:
2927 * @ctxt: an XPath parser context
2928 *
2929 * Pops a boolean from the stack, handling conversion if needed.
2930 * Check error with #xmlXPathCheckError.
2931 *
2932 * Returns the boolean
2933 */
2934 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2935 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2936 xmlXPathObjectPtr obj;
2937 int ret;
2938
2939 obj = valuePop(ctxt);
2940 if (obj == NULL) {
2941 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2942 return(0);
2943 }
2944 if (obj->type != XPATH_BOOLEAN)
2945 ret = xmlXPathCastToBoolean(obj);
2946 else
2947 ret = obj->boolval;
2948 xmlXPathReleaseObject(ctxt->context, obj);
2949 return(ret);
2950 }
2951
2952 /**
2953 * xmlXPathPopNumber:
2954 * @ctxt: an XPath parser context
2955 *
2956 * Pops a number from the stack, handling conversion if needed.
2957 * Check error with #xmlXPathCheckError.
2958 *
2959 * Returns the number
2960 */
2961 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2962 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2963 xmlXPathObjectPtr obj;
2964 double ret;
2965
2966 obj = valuePop(ctxt);
2967 if (obj == NULL) {
2968 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2969 return(0);
2970 }
2971 if (obj->type != XPATH_NUMBER)
2972 ret = xmlXPathCastToNumber(obj);
2973 else
2974 ret = obj->floatval;
2975 xmlXPathReleaseObject(ctxt->context, obj);
2976 return(ret);
2977 }
2978
2979 /**
2980 * xmlXPathPopString:
2981 * @ctxt: an XPath parser context
2982 *
2983 * Pops a string from the stack, handling conversion if needed.
2984 * Check error with #xmlXPathCheckError.
2985 *
2986 * Returns the string
2987 */
2988 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2989 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2990 xmlXPathObjectPtr obj;
2991 xmlChar * ret;
2992
2993 obj = valuePop(ctxt);
2994 if (obj == NULL) {
2995 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2996 return(NULL);
2997 }
2998 ret = xmlXPathCastToString(obj); /* this does required strdup */
2999 /* TODO: needs refactoring somewhere else */
3000 if (obj->stringval == ret)
3001 obj->stringval = NULL;
3002 xmlXPathReleaseObject(ctxt->context, obj);
3003 return(ret);
3004 }
3005
3006 /**
3007 * xmlXPathPopNodeSet:
3008 * @ctxt: an XPath parser context
3009 *
3010 * Pops a node-set from the stack, handling conversion if needed.
3011 * Check error with #xmlXPathCheckError.
3012 *
3013 * Returns the node-set
3014 */
3015 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)3016 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3017 xmlXPathObjectPtr obj;
3018 xmlNodeSetPtr ret;
3019
3020 if (ctxt == NULL) return(NULL);
3021 if (ctxt->value == NULL) {
3022 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3023 return(NULL);
3024 }
3025 if (!xmlXPathStackIsNodeSet(ctxt)) {
3026 xmlXPathSetTypeError(ctxt);
3027 return(NULL);
3028 }
3029 obj = valuePop(ctxt);
3030 ret = obj->nodesetval;
3031 #if 0
3032 /* to fix memory leak of not clearing obj->user */
3033 if (obj->boolval && obj->user != NULL)
3034 xmlFreeNodeList((xmlNodePtr) obj->user);
3035 #endif
3036 obj->nodesetval = NULL;
3037 xmlXPathReleaseObject(ctxt->context, obj);
3038 return(ret);
3039 }
3040
3041 /**
3042 * xmlXPathPopExternal:
3043 * @ctxt: an XPath parser context
3044 *
3045 * Pops an external object from the stack, handling conversion if needed.
3046 * Check error with #xmlXPathCheckError.
3047 *
3048 * Returns the object
3049 */
3050 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3051 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3052 xmlXPathObjectPtr obj;
3053 void * ret;
3054
3055 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3056 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3057 return(NULL);
3058 }
3059 if (ctxt->value->type != XPATH_USERS) {
3060 xmlXPathSetTypeError(ctxt);
3061 return(NULL);
3062 }
3063 obj = valuePop(ctxt);
3064 ret = obj->user;
3065 obj->user = NULL;
3066 xmlXPathReleaseObject(ctxt->context, obj);
3067 return(ret);
3068 }
3069
3070 /*
3071 * Macros for accessing the content. Those should be used only by the parser,
3072 * and not exported.
3073 *
3074 * Dirty macros, i.e. one need to make assumption on the context to use them
3075 *
3076 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3077 * CUR returns the current xmlChar value, i.e. a 8 bit value
3078 * in ISO-Latin or UTF-8.
3079 * This should be used internally by the parser
3080 * only to compare to ASCII values otherwise it would break when
3081 * running with UTF-8 encoding.
3082 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3083 * to compare on ASCII based substring.
3084 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3085 * strings within the parser.
3086 * CURRENT Returns the current char value, with the full decoding of
3087 * UTF-8 if we are using this mode. It returns an int.
3088 * NEXT Skip to the next character, this does the proper decoding
3089 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3090 * It returns the pointer to the current xmlChar.
3091 */
3092
3093 #define CUR (*ctxt->cur)
3094 #define SKIP(val) ctxt->cur += (val)
3095 #define NXT(val) ctxt->cur[(val)]
3096 #define CUR_PTR ctxt->cur
3097 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3098
3099 #define COPY_BUF(l,b,i,v) \
3100 if (l == 1) b[i++] = (xmlChar) v; \
3101 else i += xmlCopyChar(l,&b[i],v)
3102
3103 #define NEXTL(l) ctxt->cur += l
3104
3105 #define SKIP_BLANKS \
3106 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3107
3108 #define CURRENT (*ctxt->cur)
3109 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3110
3111
3112 #ifndef DBL_DIG
3113 #define DBL_DIG 16
3114 #endif
3115 #ifndef DBL_EPSILON
3116 #define DBL_EPSILON 1E-9
3117 #endif
3118
3119 #define UPPER_DOUBLE 1E9
3120 #define LOWER_DOUBLE 1E-5
3121 #define LOWER_DOUBLE_EXP 5
3122
3123 #define INTEGER_DIGITS DBL_DIG
3124 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3125 #define EXPONENT_DIGITS (3 + 2)
3126
3127 /**
3128 * xmlXPathFormatNumber:
3129 * @number: number to format
3130 * @buffer: output buffer
3131 * @buffersize: size of output buffer
3132 *
3133 * Convert the number into a string representation.
3134 */
3135 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3136 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3137 {
3138 switch (xmlXPathIsInf(number)) {
3139 case 1:
3140 if (buffersize > (int)sizeof("Infinity"))
3141 snprintf(buffer, buffersize, "Infinity");
3142 break;
3143 case -1:
3144 if (buffersize > (int)sizeof("-Infinity"))
3145 snprintf(buffer, buffersize, "-Infinity");
3146 break;
3147 default:
3148 if (xmlXPathIsNaN(number)) {
3149 if (buffersize > (int)sizeof("NaN"))
3150 snprintf(buffer, buffersize, "NaN");
3151 } else if (number == 0) {
3152 /* Omit sign for negative zero. */
3153 snprintf(buffer, buffersize, "0");
3154 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3155 (number == (int) number)) {
3156 char work[30];
3157 char *ptr, *cur;
3158 int value = (int) number;
3159
3160 ptr = &buffer[0];
3161 if (value == 0) {
3162 *ptr++ = '0';
3163 } else {
3164 snprintf(work, 29, "%d", value);
3165 cur = &work[0];
3166 while ((*cur) && (ptr - buffer < buffersize)) {
3167 *ptr++ = *cur++;
3168 }
3169 }
3170 if (ptr - buffer < buffersize) {
3171 *ptr = 0;
3172 } else if (buffersize > 0) {
3173 ptr--;
3174 *ptr = 0;
3175 }
3176 } else {
3177 /*
3178 For the dimension of work,
3179 DBL_DIG is number of significant digits
3180 EXPONENT is only needed for "scientific notation"
3181 3 is sign, decimal point, and terminating zero
3182 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3183 Note that this dimension is slightly (a few characters)
3184 larger than actually necessary.
3185 */
3186 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3187 int integer_place, fraction_place;
3188 char *ptr;
3189 char *after_fraction;
3190 double absolute_value;
3191 int size;
3192
3193 absolute_value = fabs(number);
3194
3195 /*
3196 * First choose format - scientific or regular floating point.
3197 * In either case, result is in work, and after_fraction points
3198 * just past the fractional part.
3199 */
3200 if ( ((absolute_value > UPPER_DOUBLE) ||
3201 (absolute_value < LOWER_DOUBLE)) &&
3202 (absolute_value != 0.0) ) {
3203 /* Use scientific notation */
3204 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3205 fraction_place = DBL_DIG - 1;
3206 size = snprintf(work, sizeof(work),"%*.*e",
3207 integer_place, fraction_place, number);
3208 while ((size > 0) && (work[size] != 'e')) size--;
3209
3210 }
3211 else {
3212 /* Use regular notation */
3213 if (absolute_value > 0.0) {
3214 integer_place = (int)log10(absolute_value);
3215 if (integer_place > 0)
3216 fraction_place = DBL_DIG - integer_place - 1;
3217 else
3218 fraction_place = DBL_DIG - integer_place;
3219 } else {
3220 fraction_place = 1;
3221 }
3222 size = snprintf(work, sizeof(work), "%0.*f",
3223 fraction_place, number);
3224 }
3225
3226 /* Remove leading spaces sometimes inserted by snprintf */
3227 while (work[0] == ' ') {
3228 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3229 size--;
3230 }
3231
3232 /* Remove fractional trailing zeroes */
3233 after_fraction = work + size;
3234 ptr = after_fraction;
3235 while (*(--ptr) == '0')
3236 ;
3237 if (*ptr != '.')
3238 ptr++;
3239 while ((*ptr++ = *after_fraction++) != 0);
3240
3241 /* Finally copy result back to caller */
3242 size = strlen(work) + 1;
3243 if (size > buffersize) {
3244 work[buffersize - 1] = 0;
3245 size = buffersize;
3246 }
3247 memmove(buffer, work, size);
3248 }
3249 break;
3250 }
3251 }
3252
3253
3254 /************************************************************************
3255 * *
3256 * Routines to handle NodeSets *
3257 * *
3258 ************************************************************************/
3259
3260 /**
3261 * xmlXPathOrderDocElems:
3262 * @doc: an input document
3263 *
3264 * Call this routine to speed up XPath computation on static documents.
3265 * This stamps all the element nodes with the document order
3266 * Like for line information, the order is kept in the element->content
3267 * field, the value stored is actually - the node number (starting at -1)
3268 * to be able to differentiate from line numbers.
3269 *
3270 * Returns the number of elements found in the document or -1 in case
3271 * of error.
3272 */
3273 long
xmlXPathOrderDocElems(xmlDocPtr doc)3274 xmlXPathOrderDocElems(xmlDocPtr doc) {
3275 ptrdiff_t count = 0;
3276 xmlNodePtr cur;
3277
3278 if (doc == NULL)
3279 return(-1);
3280 cur = doc->children;
3281 while (cur != NULL) {
3282 if (cur->type == XML_ELEMENT_NODE) {
3283 cur->content = (void *) (-(++count));
3284 if (cur->children != NULL) {
3285 cur = cur->children;
3286 continue;
3287 }
3288 }
3289 if (cur->next != NULL) {
3290 cur = cur->next;
3291 continue;
3292 }
3293 do {
3294 cur = cur->parent;
3295 if (cur == NULL)
3296 break;
3297 if (cur == (xmlNodePtr) doc) {
3298 cur = NULL;
3299 break;
3300 }
3301 if (cur->next != NULL) {
3302 cur = cur->next;
3303 break;
3304 }
3305 } while (cur != NULL);
3306 }
3307 return((long) count);
3308 }
3309
3310 /**
3311 * xmlXPathCmpNodes:
3312 * @node1: the first node
3313 * @node2: the second node
3314 *
3315 * Compare two nodes w.r.t document order
3316 *
3317 * Returns -2 in case of error 1 if first point < second point, 0 if
3318 * it's the same node, -1 otherwise
3319 */
3320 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3321 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3322 int depth1, depth2;
3323 int attr1 = 0, attr2 = 0;
3324 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3325 xmlNodePtr cur, root;
3326
3327 if ((node1 == NULL) || (node2 == NULL))
3328 return(-2);
3329 /*
3330 * a couple of optimizations which will avoid computations in most cases
3331 */
3332 if (node1 == node2) /* trivial case */
3333 return(0);
3334 if (node1->type == XML_ATTRIBUTE_NODE) {
3335 attr1 = 1;
3336 attrNode1 = node1;
3337 node1 = node1->parent;
3338 }
3339 if (node2->type == XML_ATTRIBUTE_NODE) {
3340 attr2 = 1;
3341 attrNode2 = node2;
3342 node2 = node2->parent;
3343 }
3344 if (node1 == node2) {
3345 if (attr1 == attr2) {
3346 /* not required, but we keep attributes in order */
3347 if (attr1 != 0) {
3348 cur = attrNode2->prev;
3349 while (cur != NULL) {
3350 if (cur == attrNode1)
3351 return (1);
3352 cur = cur->prev;
3353 }
3354 return (-1);
3355 }
3356 return(0);
3357 }
3358 if (attr2 == 1)
3359 return(1);
3360 return(-1);
3361 }
3362 if ((node1->type == XML_NAMESPACE_DECL) ||
3363 (node2->type == XML_NAMESPACE_DECL))
3364 return(1);
3365 if (node1 == node2->prev)
3366 return(1);
3367 if (node1 == node2->next)
3368 return(-1);
3369
3370 /*
3371 * Speedup using document order if available.
3372 */
3373 if ((node1->type == XML_ELEMENT_NODE) &&
3374 (node2->type == XML_ELEMENT_NODE) &&
3375 (0 > (ptrdiff_t) node1->content) &&
3376 (0 > (ptrdiff_t) node2->content) &&
3377 (node1->doc == node2->doc)) {
3378 ptrdiff_t l1, l2;
3379
3380 l1 = -((ptrdiff_t) node1->content);
3381 l2 = -((ptrdiff_t) node2->content);
3382 if (l1 < l2)
3383 return(1);
3384 if (l1 > l2)
3385 return(-1);
3386 }
3387
3388 /*
3389 * compute depth to root
3390 */
3391 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3392 if (cur->parent == node1)
3393 return(1);
3394 depth2++;
3395 }
3396 root = cur;
3397 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3398 if (cur->parent == node2)
3399 return(-1);
3400 depth1++;
3401 }
3402 /*
3403 * Distinct document (or distinct entities :-( ) case.
3404 */
3405 if (root != cur) {
3406 return(-2);
3407 }
3408 /*
3409 * get the nearest common ancestor.
3410 */
3411 while (depth1 > depth2) {
3412 depth1--;
3413 node1 = node1->parent;
3414 }
3415 while (depth2 > depth1) {
3416 depth2--;
3417 node2 = node2->parent;
3418 }
3419 while (node1->parent != node2->parent) {
3420 node1 = node1->parent;
3421 node2 = node2->parent;
3422 /* should not happen but just in case ... */
3423 if ((node1 == NULL) || (node2 == NULL))
3424 return(-2);
3425 }
3426 /*
3427 * Find who's first.
3428 */
3429 if (node1 == node2->prev)
3430 return(1);
3431 if (node1 == node2->next)
3432 return(-1);
3433 /*
3434 * Speedup using document order if available.
3435 */
3436 if ((node1->type == XML_ELEMENT_NODE) &&
3437 (node2->type == XML_ELEMENT_NODE) &&
3438 (0 > (ptrdiff_t) node1->content) &&
3439 (0 > (ptrdiff_t) node2->content) &&
3440 (node1->doc == node2->doc)) {
3441 ptrdiff_t l1, l2;
3442
3443 l1 = -((ptrdiff_t) node1->content);
3444 l2 = -((ptrdiff_t) node2->content);
3445 if (l1 < l2)
3446 return(1);
3447 if (l1 > l2)
3448 return(-1);
3449 }
3450
3451 for (cur = node1->next;cur != NULL;cur = cur->next)
3452 if (cur == node2)
3453 return(1);
3454 return(-1); /* assume there is no sibling list corruption */
3455 }
3456
3457 /**
3458 * xmlXPathNodeSetSort:
3459 * @set: the node set
3460 *
3461 * Sort the node set in document order
3462 */
3463 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3464 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3465 #ifndef WITH_TIM_SORT
3466 int i, j, incr, len;
3467 xmlNodePtr tmp;
3468 #endif
3469
3470 if (set == NULL)
3471 return;
3472
3473 #ifndef WITH_TIM_SORT
3474 /*
3475 * Use the old Shell's sort implementation to sort the node-set
3476 * Timsort ought to be quite faster
3477 */
3478 len = set->nodeNr;
3479 for (incr = len / 2; incr > 0; incr /= 2) {
3480 for (i = incr; i < len; i++) {
3481 j = i - incr;
3482 while (j >= 0) {
3483 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3484 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3485 set->nodeTab[j + incr]) == -1)
3486 #else
3487 if (xmlXPathCmpNodes(set->nodeTab[j],
3488 set->nodeTab[j + incr]) == -1)
3489 #endif
3490 {
3491 tmp = set->nodeTab[j];
3492 set->nodeTab[j] = set->nodeTab[j + incr];
3493 set->nodeTab[j + incr] = tmp;
3494 j -= incr;
3495 } else
3496 break;
3497 }
3498 }
3499 }
3500 #else /* WITH_TIM_SORT */
3501 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3502 #endif /* WITH_TIM_SORT */
3503 }
3504
3505 #define XML_NODESET_DEFAULT 10
3506 /**
3507 * xmlXPathNodeSetDupNs:
3508 * @node: the parent node of the namespace XPath node
3509 * @ns: the libxml namespace declaration node.
3510 *
3511 * Namespace node in libxml don't match the XPath semantic. In a node set
3512 * the namespace nodes are duplicated and the next pointer is set to the
3513 * parent node in the XPath semantic.
3514 *
3515 * Returns the newly created object.
3516 */
3517 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3518 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3519 xmlNsPtr cur;
3520
3521 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3522 return(NULL);
3523 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3524 return((xmlNodePtr) ns);
3525
3526 /*
3527 * Allocate a new Namespace and fill the fields.
3528 */
3529 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3530 if (cur == NULL) {
3531 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3532 return(NULL);
3533 }
3534 memset(cur, 0, sizeof(xmlNs));
3535 cur->type = XML_NAMESPACE_DECL;
3536 if (ns->href != NULL)
3537 cur->href = xmlStrdup(ns->href);
3538 if (ns->prefix != NULL)
3539 cur->prefix = xmlStrdup(ns->prefix);
3540 cur->next = (xmlNsPtr) node;
3541 return((xmlNodePtr) cur);
3542 }
3543
3544 /**
3545 * xmlXPathNodeSetFreeNs:
3546 * @ns: the XPath namespace node found in a nodeset.
3547 *
3548 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3549 * the namespace nodes are duplicated and the next pointer is set to the
3550 * parent node in the XPath semantic. Check if such a node needs to be freed
3551 */
3552 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3553 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3554 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3555 return;
3556
3557 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3558 if (ns->href != NULL)
3559 xmlFree((xmlChar *)ns->href);
3560 if (ns->prefix != NULL)
3561 xmlFree((xmlChar *)ns->prefix);
3562 xmlFree(ns);
3563 }
3564 }
3565
3566 /**
3567 * xmlXPathNodeSetCreate:
3568 * @val: an initial xmlNodePtr, or NULL
3569 *
3570 * Create a new xmlNodeSetPtr of type double and of value @val
3571 *
3572 * Returns the newly created object.
3573 */
3574 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3575 xmlXPathNodeSetCreate(xmlNodePtr val) {
3576 xmlNodeSetPtr ret;
3577
3578 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3579 if (ret == NULL) {
3580 xmlXPathErrMemory(NULL, "creating nodeset\n");
3581 return(NULL);
3582 }
3583 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3584 if (val != NULL) {
3585 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3586 sizeof(xmlNodePtr));
3587 if (ret->nodeTab == NULL) {
3588 xmlXPathErrMemory(NULL, "creating nodeset\n");
3589 xmlFree(ret);
3590 return(NULL);
3591 }
3592 memset(ret->nodeTab, 0 ,
3593 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3594 ret->nodeMax = XML_NODESET_DEFAULT;
3595 if (val->type == XML_NAMESPACE_DECL) {
3596 xmlNsPtr ns = (xmlNsPtr) val;
3597
3598 /* TODO: Check memory error. */
3599 ret->nodeTab[ret->nodeNr++] =
3600 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3601 } else
3602 ret->nodeTab[ret->nodeNr++] = val;
3603 }
3604 return(ret);
3605 }
3606
3607 /**
3608 * xmlXPathNodeSetContains:
3609 * @cur: the node-set
3610 * @val: the node
3611 *
3612 * checks whether @cur contains @val
3613 *
3614 * Returns true (1) if @cur contains @val, false (0) otherwise
3615 */
3616 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3617 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3618 int i;
3619
3620 if ((cur == NULL) || (val == NULL)) return(0);
3621 if (val->type == XML_NAMESPACE_DECL) {
3622 for (i = 0; i < cur->nodeNr; i++) {
3623 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3624 xmlNsPtr ns1, ns2;
3625
3626 ns1 = (xmlNsPtr) val;
3627 ns2 = (xmlNsPtr) cur->nodeTab[i];
3628 if (ns1 == ns2)
3629 return(1);
3630 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3631 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3632 return(1);
3633 }
3634 }
3635 } else {
3636 for (i = 0; i < cur->nodeNr; i++) {
3637 if (cur->nodeTab[i] == val)
3638 return(1);
3639 }
3640 }
3641 return(0);
3642 }
3643
3644 /**
3645 * xmlXPathNodeSetAddNs:
3646 * @cur: the initial node set
3647 * @node: the hosting node
3648 * @ns: a the namespace node
3649 *
3650 * add a new namespace node to an existing NodeSet
3651 *
3652 * Returns 0 in case of success and -1 in case of error
3653 */
3654 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3655 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3656 int i;
3657
3658
3659 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3660 (ns->type != XML_NAMESPACE_DECL) ||
3661 (node->type != XML_ELEMENT_NODE))
3662 return(-1);
3663
3664 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3665 /*
3666 * prevent duplicates
3667 */
3668 for (i = 0;i < cur->nodeNr;i++) {
3669 if ((cur->nodeTab[i] != NULL) &&
3670 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3671 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3672 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3673 return(0);
3674 }
3675
3676 /*
3677 * grow the nodeTab if needed
3678 */
3679 if (cur->nodeMax == 0) {
3680 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3681 sizeof(xmlNodePtr));
3682 if (cur->nodeTab == NULL) {
3683 xmlXPathErrMemory(NULL, "growing nodeset\n");
3684 return(-1);
3685 }
3686 memset(cur->nodeTab, 0 ,
3687 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3688 cur->nodeMax = XML_NODESET_DEFAULT;
3689 } else if (cur->nodeNr == cur->nodeMax) {
3690 xmlNodePtr *temp;
3691
3692 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3693 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3694 return(-1);
3695 }
3696 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3697 sizeof(xmlNodePtr));
3698 if (temp == NULL) {
3699 xmlXPathErrMemory(NULL, "growing nodeset\n");
3700 return(-1);
3701 }
3702 cur->nodeMax *= 2;
3703 cur->nodeTab = temp;
3704 }
3705 /* TODO: Check memory error. */
3706 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3707 return(0);
3708 }
3709
3710 /**
3711 * xmlXPathNodeSetAdd:
3712 * @cur: the initial node set
3713 * @val: a new xmlNodePtr
3714 *
3715 * add a new xmlNodePtr to an existing NodeSet
3716 *
3717 * Returns 0 in case of success, and -1 in case of error
3718 */
3719 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3720 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3721 int i;
3722
3723 if ((cur == NULL) || (val == NULL)) return(-1);
3724
3725 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3726 /*
3727 * prevent duplicates
3728 */
3729 for (i = 0;i < cur->nodeNr;i++)
3730 if (cur->nodeTab[i] == val) return(0);
3731
3732 /*
3733 * grow the nodeTab if needed
3734 */
3735 if (cur->nodeMax == 0) {
3736 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3737 sizeof(xmlNodePtr));
3738 if (cur->nodeTab == NULL) {
3739 xmlXPathErrMemory(NULL, "growing nodeset\n");
3740 return(-1);
3741 }
3742 memset(cur->nodeTab, 0 ,
3743 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3744 cur->nodeMax = XML_NODESET_DEFAULT;
3745 } else if (cur->nodeNr == cur->nodeMax) {
3746 xmlNodePtr *temp;
3747
3748 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3749 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3750 return(-1);
3751 }
3752 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3753 sizeof(xmlNodePtr));
3754 if (temp == NULL) {
3755 xmlXPathErrMemory(NULL, "growing nodeset\n");
3756 return(-1);
3757 }
3758 cur->nodeMax *= 2;
3759 cur->nodeTab = temp;
3760 }
3761 if (val->type == XML_NAMESPACE_DECL) {
3762 xmlNsPtr ns = (xmlNsPtr) val;
3763
3764 /* TODO: Check memory error. */
3765 cur->nodeTab[cur->nodeNr++] =
3766 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3767 } else
3768 cur->nodeTab[cur->nodeNr++] = val;
3769 return(0);
3770 }
3771
3772 /**
3773 * xmlXPathNodeSetAddUnique:
3774 * @cur: the initial node set
3775 * @val: a new xmlNodePtr
3776 *
3777 * add a new xmlNodePtr to an existing NodeSet, optimized version
3778 * when we are sure the node is not already in the set.
3779 *
3780 * Returns 0 in case of success and -1 in case of failure
3781 */
3782 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3783 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3784 if ((cur == NULL) || (val == NULL)) return(-1);
3785
3786 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3787 /*
3788 * grow the nodeTab if needed
3789 */
3790 if (cur->nodeMax == 0) {
3791 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792 sizeof(xmlNodePtr));
3793 if (cur->nodeTab == NULL) {
3794 xmlXPathErrMemory(NULL, "growing nodeset\n");
3795 return(-1);
3796 }
3797 memset(cur->nodeTab, 0 ,
3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799 cur->nodeMax = XML_NODESET_DEFAULT;
3800 } else if (cur->nodeNr == cur->nodeMax) {
3801 xmlNodePtr *temp;
3802
3803 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3804 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3805 return(-1);
3806 }
3807 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3808 sizeof(xmlNodePtr));
3809 if (temp == NULL) {
3810 xmlXPathErrMemory(NULL, "growing nodeset\n");
3811 return(-1);
3812 }
3813 cur->nodeTab = temp;
3814 cur->nodeMax *= 2;
3815 }
3816 if (val->type == XML_NAMESPACE_DECL) {
3817 xmlNsPtr ns = (xmlNsPtr) val;
3818
3819 /* TODO: Check memory error. */
3820 cur->nodeTab[cur->nodeNr++] =
3821 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3822 } else
3823 cur->nodeTab[cur->nodeNr++] = val;
3824 return(0);
3825 }
3826
3827 /**
3828 * xmlXPathNodeSetMerge:
3829 * @val1: the first NodeSet or NULL
3830 * @val2: the second NodeSet
3831 *
3832 * Merges two nodesets, all nodes from @val2 are added to @val1
3833 * if @val1 is NULL, a new set is created and copied from @val2
3834 *
3835 * Returns @val1 once extended or NULL in case of error.
3836 */
3837 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3838 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3839 int i, j, initNr, skip;
3840 xmlNodePtr n1, n2;
3841
3842 if (val2 == NULL) return(val1);
3843 if (val1 == NULL) {
3844 val1 = xmlXPathNodeSetCreate(NULL);
3845 if (val1 == NULL)
3846 return (NULL);
3847 #if 0
3848 /*
3849 * TODO: The optimization won't work in every case, since
3850 * those nasty namespace nodes need to be added with
3851 * xmlXPathNodeSetDupNs() to the set; thus a pure
3852 * memcpy is not possible.
3853 * If there was a flag on the nodesetval, indicating that
3854 * some temporary nodes are in, that would be helpful.
3855 */
3856 /*
3857 * Optimization: Create an equally sized node-set
3858 * and memcpy the content.
3859 */
3860 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3861 if (val1 == NULL)
3862 return(NULL);
3863 if (val2->nodeNr != 0) {
3864 if (val2->nodeNr == 1)
3865 *(val1->nodeTab) = *(val2->nodeTab);
3866 else {
3867 memcpy(val1->nodeTab, val2->nodeTab,
3868 val2->nodeNr * sizeof(xmlNodePtr));
3869 }
3870 val1->nodeNr = val2->nodeNr;
3871 }
3872 return(val1);
3873 #endif
3874 }
3875
3876 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3877 initNr = val1->nodeNr;
3878
3879 for (i = 0;i < val2->nodeNr;i++) {
3880 n2 = val2->nodeTab[i];
3881 /*
3882 * check against duplicates
3883 */
3884 skip = 0;
3885 for (j = 0; j < initNr; j++) {
3886 n1 = val1->nodeTab[j];
3887 if (n1 == n2) {
3888 skip = 1;
3889 break;
3890 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3891 (n2->type == XML_NAMESPACE_DECL)) {
3892 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3893 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3894 ((xmlNsPtr) n2)->prefix)))
3895 {
3896 skip = 1;
3897 break;
3898 }
3899 }
3900 }
3901 if (skip)
3902 continue;
3903
3904 /*
3905 * grow the nodeTab if needed
3906 */
3907 if (val1->nodeMax == 0) {
3908 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3909 sizeof(xmlNodePtr));
3910 if (val1->nodeTab == NULL) {
3911 xmlXPathErrMemory(NULL, "merging nodeset\n");
3912 return(NULL);
3913 }
3914 memset(val1->nodeTab, 0 ,
3915 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3916 val1->nodeMax = XML_NODESET_DEFAULT;
3917 } else if (val1->nodeNr == val1->nodeMax) {
3918 xmlNodePtr *temp;
3919
3920 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3921 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3922 return(NULL);
3923 }
3924 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3925 sizeof(xmlNodePtr));
3926 if (temp == NULL) {
3927 xmlXPathErrMemory(NULL, "merging nodeset\n");
3928 return(NULL);
3929 }
3930 val1->nodeTab = temp;
3931 val1->nodeMax *= 2;
3932 }
3933 if (n2->type == XML_NAMESPACE_DECL) {
3934 xmlNsPtr ns = (xmlNsPtr) n2;
3935
3936 /* TODO: Check memory error. */
3937 val1->nodeTab[val1->nodeNr++] =
3938 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3939 } else
3940 val1->nodeTab[val1->nodeNr++] = n2;
3941 }
3942
3943 return(val1);
3944 }
3945
3946
3947 /**
3948 * xmlXPathNodeSetMergeAndClear:
3949 * @set1: the first NodeSet or NULL
3950 * @set2: the second NodeSet
3951 *
3952 * Merges two nodesets, all nodes from @set2 are added to @set1.
3953 * Checks for duplicate nodes. Clears set2.
3954 *
3955 * Returns @set1 once extended or NULL in case of error.
3956 */
3957 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3958 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3959 {
3960 {
3961 int i, j, initNbSet1;
3962 xmlNodePtr n1, n2;
3963
3964 initNbSet1 = set1->nodeNr;
3965 for (i = 0;i < set2->nodeNr;i++) {
3966 n2 = set2->nodeTab[i];
3967 /*
3968 * Skip duplicates.
3969 */
3970 for (j = 0; j < initNbSet1; j++) {
3971 n1 = set1->nodeTab[j];
3972 if (n1 == n2) {
3973 goto skip_node;
3974 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3975 (n2->type == XML_NAMESPACE_DECL))
3976 {
3977 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3978 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3979 ((xmlNsPtr) n2)->prefix)))
3980 {
3981 /*
3982 * Free the namespace node.
3983 */
3984 set2->nodeTab[i] = NULL;
3985 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3986 goto skip_node;
3987 }
3988 }
3989 }
3990 /*
3991 * grow the nodeTab if needed
3992 */
3993 if (set1->nodeMax == 0) {
3994 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3995 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3996 if (set1->nodeTab == NULL) {
3997 xmlXPathErrMemory(NULL, "merging nodeset\n");
3998 return(NULL);
3999 }
4000 memset(set1->nodeTab, 0,
4001 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4002 set1->nodeMax = XML_NODESET_DEFAULT;
4003 } else if (set1->nodeNr >= set1->nodeMax) {
4004 xmlNodePtr *temp;
4005
4006 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4007 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4008 return(NULL);
4009 }
4010 temp = (xmlNodePtr *) xmlRealloc(
4011 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4012 if (temp == NULL) {
4013 xmlXPathErrMemory(NULL, "merging nodeset\n");
4014 return(NULL);
4015 }
4016 set1->nodeTab = temp;
4017 set1->nodeMax *= 2;
4018 }
4019 set1->nodeTab[set1->nodeNr++] = n2;
4020 skip_node:
4021 {}
4022 }
4023 }
4024 set2->nodeNr = 0;
4025 return(set1);
4026 }
4027
4028 /**
4029 * xmlXPathNodeSetMergeAndClearNoDupls:
4030 * @set1: the first NodeSet or NULL
4031 * @set2: the second NodeSet
4032 *
4033 * Merges two nodesets, all nodes from @set2 are added to @set1.
4034 * Doesn't check for duplicate nodes. Clears set2.
4035 *
4036 * Returns @set1 once extended or NULL in case of error.
4037 */
4038 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)4039 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4040 {
4041 {
4042 int i;
4043 xmlNodePtr n2;
4044
4045 for (i = 0;i < set2->nodeNr;i++) {
4046 n2 = set2->nodeTab[i];
4047 if (set1->nodeMax == 0) {
4048 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4049 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4050 if (set1->nodeTab == NULL) {
4051 xmlXPathErrMemory(NULL, "merging nodeset\n");
4052 return(NULL);
4053 }
4054 memset(set1->nodeTab, 0,
4055 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4056 set1->nodeMax = XML_NODESET_DEFAULT;
4057 } else if (set1->nodeNr >= set1->nodeMax) {
4058 xmlNodePtr *temp;
4059
4060 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4061 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4062 return(NULL);
4063 }
4064 temp = (xmlNodePtr *) xmlRealloc(
4065 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4066 if (temp == NULL) {
4067 xmlXPathErrMemory(NULL, "merging nodeset\n");
4068 return(NULL);
4069 }
4070 set1->nodeTab = temp;
4071 set1->nodeMax *= 2;
4072 }
4073 set1->nodeTab[set1->nodeNr++] = n2;
4074 }
4075 }
4076 set2->nodeNr = 0;
4077 return(set1);
4078 }
4079
4080 /**
4081 * xmlXPathNodeSetDel:
4082 * @cur: the initial node set
4083 * @val: an xmlNodePtr
4084 *
4085 * Removes an xmlNodePtr from an existing NodeSet
4086 */
4087 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4088 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4089 int i;
4090
4091 if (cur == NULL) return;
4092 if (val == NULL) return;
4093
4094 /*
4095 * find node in nodeTab
4096 */
4097 for (i = 0;i < cur->nodeNr;i++)
4098 if (cur->nodeTab[i] == val) break;
4099
4100 if (i >= cur->nodeNr) { /* not found */
4101 #ifdef DEBUG
4102 xmlGenericError(xmlGenericErrorContext,
4103 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4104 val->name);
4105 #endif
4106 return;
4107 }
4108 if ((cur->nodeTab[i] != NULL) &&
4109 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4110 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4111 cur->nodeNr--;
4112 for (;i < cur->nodeNr;i++)
4113 cur->nodeTab[i] = cur->nodeTab[i + 1];
4114 cur->nodeTab[cur->nodeNr] = NULL;
4115 }
4116
4117 /**
4118 * xmlXPathNodeSetRemove:
4119 * @cur: the initial node set
4120 * @val: the index to remove
4121 *
4122 * Removes an entry from an existing NodeSet list.
4123 */
4124 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4125 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4126 if (cur == NULL) return;
4127 if (val >= cur->nodeNr) return;
4128 if ((cur->nodeTab[val] != NULL) &&
4129 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4130 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4131 cur->nodeNr--;
4132 for (;val < cur->nodeNr;val++)
4133 cur->nodeTab[val] = cur->nodeTab[val + 1];
4134 cur->nodeTab[cur->nodeNr] = NULL;
4135 }
4136
4137 /**
4138 * xmlXPathFreeNodeSet:
4139 * @obj: the xmlNodeSetPtr to free
4140 *
4141 * Free the NodeSet compound (not the actual nodes !).
4142 */
4143 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4144 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4145 if (obj == NULL) return;
4146 if (obj->nodeTab != NULL) {
4147 int i;
4148
4149 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4150 for (i = 0;i < obj->nodeNr;i++)
4151 if ((obj->nodeTab[i] != NULL) &&
4152 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4153 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4154 xmlFree(obj->nodeTab);
4155 }
4156 xmlFree(obj);
4157 }
4158
4159 /**
4160 * xmlXPathNodeSetClearFromPos:
4161 * @set: the node set to be cleared
4162 * @pos: the start position to clear from
4163 *
4164 * Clears the list from temporary XPath objects (e.g. namespace nodes
4165 * are feed) starting with the entry at @pos, but does *not* free the list
4166 * itself. Sets the length of the list to @pos.
4167 */
4168 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4169 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4170 {
4171 if ((set == NULL) || (pos >= set->nodeNr))
4172 return;
4173 else if ((hasNsNodes)) {
4174 int i;
4175 xmlNodePtr node;
4176
4177 for (i = pos; i < set->nodeNr; i++) {
4178 node = set->nodeTab[i];
4179 if ((node != NULL) &&
4180 (node->type == XML_NAMESPACE_DECL))
4181 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4182 }
4183 }
4184 set->nodeNr = pos;
4185 }
4186
4187 /**
4188 * xmlXPathNodeSetClear:
4189 * @set: the node set to clear
4190 *
4191 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4192 * are feed), but does *not* free the list itself. Sets the length of the
4193 * list to 0.
4194 */
4195 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4196 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4197 {
4198 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4199 }
4200
4201 /**
4202 * xmlXPathNodeSetKeepLast:
4203 * @set: the node set to be cleared
4204 *
4205 * Move the last node to the first position and clear temporary XPath objects
4206 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4207 * to 1.
4208 */
4209 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4210 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4211 {
4212 int i;
4213 xmlNodePtr node;
4214
4215 if ((set == NULL) || (set->nodeNr <= 1))
4216 return;
4217 for (i = 0; i < set->nodeNr - 1; i++) {
4218 node = set->nodeTab[i];
4219 if ((node != NULL) &&
4220 (node->type == XML_NAMESPACE_DECL))
4221 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4222 }
4223 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4224 set->nodeNr = 1;
4225 }
4226
4227 /**
4228 * xmlXPathFreeValueTree:
4229 * @obj: the xmlNodeSetPtr to free
4230 *
4231 * Free the NodeSet compound and the actual tree, this is different
4232 * from xmlXPathFreeNodeSet()
4233 */
4234 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4235 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4236 int i;
4237
4238 if (obj == NULL) return;
4239
4240 if (obj->nodeTab != NULL) {
4241 for (i = 0;i < obj->nodeNr;i++) {
4242 if (obj->nodeTab[i] != NULL) {
4243 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4244 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4245 } else {
4246 xmlFreeNodeList(obj->nodeTab[i]);
4247 }
4248 }
4249 }
4250 xmlFree(obj->nodeTab);
4251 }
4252 xmlFree(obj);
4253 }
4254
4255 #if defined(DEBUG) || defined(DEBUG_STEP)
4256 /**
4257 * xmlGenericErrorContextNodeSet:
4258 * @output: a FILE * for the output
4259 * @obj: the xmlNodeSetPtr to display
4260 *
4261 * Quick display of a NodeSet
4262 */
4263 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4264 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4265 int i;
4266
4267 if (output == NULL) output = xmlGenericErrorContext;
4268 if (obj == NULL) {
4269 fprintf(output, "NodeSet == NULL !\n");
4270 return;
4271 }
4272 if (obj->nodeNr == 0) {
4273 fprintf(output, "NodeSet is empty\n");
4274 return;
4275 }
4276 if (obj->nodeTab == NULL) {
4277 fprintf(output, " nodeTab == NULL !\n");
4278 return;
4279 }
4280 for (i = 0; i < obj->nodeNr; i++) {
4281 if (obj->nodeTab[i] == NULL) {
4282 fprintf(output, " NULL !\n");
4283 return;
4284 }
4285 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4286 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4287 fprintf(output, " /");
4288 else if (obj->nodeTab[i]->name == NULL)
4289 fprintf(output, " noname!");
4290 else fprintf(output, " %s", obj->nodeTab[i]->name);
4291 }
4292 fprintf(output, "\n");
4293 }
4294 #endif
4295
4296 /**
4297 * xmlXPathNewNodeSet:
4298 * @val: the NodePtr value
4299 *
4300 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4301 * it with the single Node @val
4302 *
4303 * Returns the newly created object.
4304 */
4305 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4306 xmlXPathNewNodeSet(xmlNodePtr val) {
4307 xmlXPathObjectPtr ret;
4308
4309 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4310 if (ret == NULL) {
4311 xmlXPathErrMemory(NULL, "creating nodeset\n");
4312 return(NULL);
4313 }
4314 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4315 ret->type = XPATH_NODESET;
4316 ret->boolval = 0;
4317 /* TODO: Check memory error. */
4318 ret->nodesetval = xmlXPathNodeSetCreate(val);
4319 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4320 #ifdef XP_DEBUG_OBJ_USAGE
4321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322 #endif
4323 return(ret);
4324 }
4325
4326 /**
4327 * xmlXPathNewValueTree:
4328 * @val: the NodePtr value
4329 *
4330 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4331 * it with the tree root @val
4332 *
4333 * Returns the newly created object.
4334 */
4335 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4336 xmlXPathNewValueTree(xmlNodePtr val) {
4337 xmlXPathObjectPtr ret;
4338
4339 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4340 if (ret == NULL) {
4341 xmlXPathErrMemory(NULL, "creating result value tree\n");
4342 return(NULL);
4343 }
4344 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4345 ret->type = XPATH_XSLT_TREE;
4346 ret->boolval = 1;
4347 ret->user = (void *) val;
4348 ret->nodesetval = xmlXPathNodeSetCreate(val);
4349 #ifdef XP_DEBUG_OBJ_USAGE
4350 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4351 #endif
4352 return(ret);
4353 }
4354
4355 /**
4356 * xmlXPathNewNodeSetList:
4357 * @val: an existing NodeSet
4358 *
4359 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4360 * it with the Nodeset @val
4361 *
4362 * Returns the newly created object.
4363 */
4364 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4365 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4366 {
4367 xmlXPathObjectPtr ret;
4368 int i;
4369
4370 if (val == NULL)
4371 ret = NULL;
4372 else if (val->nodeTab == NULL)
4373 ret = xmlXPathNewNodeSet(NULL);
4374 else {
4375 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4376 if (ret) {
4377 for (i = 1; i < val->nodeNr; ++i) {
4378 /* TODO: Propagate memory error. */
4379 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4380 < 0) break;
4381 }
4382 }
4383 }
4384
4385 return (ret);
4386 }
4387
4388 /**
4389 * xmlXPathWrapNodeSet:
4390 * @val: the NodePtr value
4391 *
4392 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4393 *
4394 * Returns the newly created object.
4395 */
4396 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4397 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4398 xmlXPathObjectPtr ret;
4399
4400 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4401 if (ret == NULL) {
4402 xmlXPathErrMemory(NULL, "creating node set object\n");
4403 return(NULL);
4404 }
4405 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4406 ret->type = XPATH_NODESET;
4407 ret->nodesetval = val;
4408 #ifdef XP_DEBUG_OBJ_USAGE
4409 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4410 #endif
4411 return(ret);
4412 }
4413
4414 /**
4415 * xmlXPathFreeNodeSetList:
4416 * @obj: an existing NodeSetList object
4417 *
4418 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4419 * the list contrary to xmlXPathFreeObject().
4420 */
4421 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4422 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4423 if (obj == NULL) return;
4424 #ifdef XP_DEBUG_OBJ_USAGE
4425 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4426 #endif
4427 xmlFree(obj);
4428 }
4429
4430 /**
4431 * xmlXPathDifference:
4432 * @nodes1: a node-set
4433 * @nodes2: a node-set
4434 *
4435 * Implements the EXSLT - Sets difference() function:
4436 * node-set set:difference (node-set, node-set)
4437 *
4438 * Returns the difference between the two node sets, or nodes1 if
4439 * nodes2 is empty
4440 */
4441 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4442 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4443 xmlNodeSetPtr ret;
4444 int i, l1;
4445 xmlNodePtr cur;
4446
4447 if (xmlXPathNodeSetIsEmpty(nodes2))
4448 return(nodes1);
4449
4450 /* TODO: Check memory error. */
4451 ret = xmlXPathNodeSetCreate(NULL);
4452 if (xmlXPathNodeSetIsEmpty(nodes1))
4453 return(ret);
4454
4455 l1 = xmlXPathNodeSetGetLength(nodes1);
4456
4457 for (i = 0; i < l1; i++) {
4458 cur = xmlXPathNodeSetItem(nodes1, i);
4459 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4460 /* TODO: Propagate memory error. */
4461 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4462 break;
4463 }
4464 }
4465 return(ret);
4466 }
4467
4468 /**
4469 * xmlXPathIntersection:
4470 * @nodes1: a node-set
4471 * @nodes2: a node-set
4472 *
4473 * Implements the EXSLT - Sets intersection() function:
4474 * node-set set:intersection (node-set, node-set)
4475 *
4476 * Returns a node set comprising the nodes that are within both the
4477 * node sets passed as arguments
4478 */
4479 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4480 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4481 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4482 int i, l1;
4483 xmlNodePtr cur;
4484
4485 if (ret == NULL)
4486 return(ret);
4487 if (xmlXPathNodeSetIsEmpty(nodes1))
4488 return(ret);
4489 if (xmlXPathNodeSetIsEmpty(nodes2))
4490 return(ret);
4491
4492 l1 = xmlXPathNodeSetGetLength(nodes1);
4493
4494 for (i = 0; i < l1; i++) {
4495 cur = xmlXPathNodeSetItem(nodes1, i);
4496 if (xmlXPathNodeSetContains(nodes2, cur)) {
4497 /* TODO: Propagate memory error. */
4498 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4499 break;
4500 }
4501 }
4502 return(ret);
4503 }
4504
4505 /**
4506 * xmlXPathDistinctSorted:
4507 * @nodes: a node-set, sorted by document order
4508 *
4509 * Implements the EXSLT - Sets distinct() function:
4510 * node-set set:distinct (node-set)
4511 *
4512 * Returns a subset of the nodes contained in @nodes, or @nodes if
4513 * it is empty
4514 */
4515 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4516 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4517 xmlNodeSetPtr ret;
4518 xmlHashTablePtr hash;
4519 int i, l;
4520 xmlChar * strval;
4521 xmlNodePtr cur;
4522
4523 if (xmlXPathNodeSetIsEmpty(nodes))
4524 return(nodes);
4525
4526 ret = xmlXPathNodeSetCreate(NULL);
4527 if (ret == NULL)
4528 return(ret);
4529 l = xmlXPathNodeSetGetLength(nodes);
4530 hash = xmlHashCreate (l);
4531 for (i = 0; i < l; i++) {
4532 cur = xmlXPathNodeSetItem(nodes, i);
4533 strval = xmlXPathCastNodeToString(cur);
4534 if (xmlHashLookup(hash, strval) == NULL) {
4535 xmlHashAddEntry(hash, strval, strval);
4536 /* TODO: Propagate memory error. */
4537 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4538 break;
4539 } else {
4540 xmlFree(strval);
4541 }
4542 }
4543 xmlHashFree(hash, xmlHashDefaultDeallocator);
4544 return(ret);
4545 }
4546
4547 /**
4548 * xmlXPathDistinct:
4549 * @nodes: a node-set
4550 *
4551 * Implements the EXSLT - Sets distinct() function:
4552 * node-set set:distinct (node-set)
4553 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4554 * is called with the sorted node-set
4555 *
4556 * Returns a subset of the nodes contained in @nodes, or @nodes if
4557 * it is empty
4558 */
4559 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4560 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4561 if (xmlXPathNodeSetIsEmpty(nodes))
4562 return(nodes);
4563
4564 xmlXPathNodeSetSort(nodes);
4565 return(xmlXPathDistinctSorted(nodes));
4566 }
4567
4568 /**
4569 * xmlXPathHasSameNodes:
4570 * @nodes1: a node-set
4571 * @nodes2: a node-set
4572 *
4573 * Implements the EXSLT - Sets has-same-nodes function:
4574 * boolean set:has-same-node(node-set, node-set)
4575 *
4576 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4577 * otherwise
4578 */
4579 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4580 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4581 int i, l;
4582 xmlNodePtr cur;
4583
4584 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4585 xmlXPathNodeSetIsEmpty(nodes2))
4586 return(0);
4587
4588 l = xmlXPathNodeSetGetLength(nodes1);
4589 for (i = 0; i < l; i++) {
4590 cur = xmlXPathNodeSetItem(nodes1, i);
4591 if (xmlXPathNodeSetContains(nodes2, cur))
4592 return(1);
4593 }
4594 return(0);
4595 }
4596
4597 /**
4598 * xmlXPathNodeLeadingSorted:
4599 * @nodes: a node-set, sorted by document order
4600 * @node: a node
4601 *
4602 * Implements the EXSLT - Sets leading() function:
4603 * node-set set:leading (node-set, node-set)
4604 *
4605 * Returns the nodes in @nodes that precede @node in document order,
4606 * @nodes if @node is NULL or an empty node-set if @nodes
4607 * doesn't contain @node
4608 */
4609 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4610 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4611 int i, l;
4612 xmlNodePtr cur;
4613 xmlNodeSetPtr ret;
4614
4615 if (node == NULL)
4616 return(nodes);
4617
4618 ret = xmlXPathNodeSetCreate(NULL);
4619 if (ret == NULL)
4620 return(ret);
4621 if (xmlXPathNodeSetIsEmpty(nodes) ||
4622 (!xmlXPathNodeSetContains(nodes, node)))
4623 return(ret);
4624
4625 l = xmlXPathNodeSetGetLength(nodes);
4626 for (i = 0; i < l; i++) {
4627 cur = xmlXPathNodeSetItem(nodes, i);
4628 if (cur == node)
4629 break;
4630 /* TODO: Propagate memory error. */
4631 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4632 break;
4633 }
4634 return(ret);
4635 }
4636
4637 /**
4638 * xmlXPathNodeLeading:
4639 * @nodes: a node-set
4640 * @node: a node
4641 *
4642 * Implements the EXSLT - Sets leading() function:
4643 * node-set set:leading (node-set, node-set)
4644 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4645 * is called.
4646 *
4647 * Returns the nodes in @nodes that precede @node in document order,
4648 * @nodes if @node is NULL or an empty node-set if @nodes
4649 * doesn't contain @node
4650 */
4651 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4652 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653 xmlXPathNodeSetSort(nodes);
4654 return(xmlXPathNodeLeadingSorted(nodes, node));
4655 }
4656
4657 /**
4658 * xmlXPathLeadingSorted:
4659 * @nodes1: a node-set, sorted by document order
4660 * @nodes2: a node-set, sorted by document order
4661 *
4662 * Implements the EXSLT - Sets leading() function:
4663 * node-set set:leading (node-set, node-set)
4664 *
4665 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4666 * in document order, @nodes1 if @nodes2 is NULL or empty or
4667 * an empty node-set if @nodes1 doesn't contain @nodes2
4668 */
4669 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4670 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4671 if (xmlXPathNodeSetIsEmpty(nodes2))
4672 return(nodes1);
4673 return(xmlXPathNodeLeadingSorted(nodes1,
4674 xmlXPathNodeSetItem(nodes2, 1)));
4675 }
4676
4677 /**
4678 * xmlXPathLeading:
4679 * @nodes1: a node-set
4680 * @nodes2: a node-set
4681 *
4682 * Implements the EXSLT - Sets leading() function:
4683 * node-set set:leading (node-set, node-set)
4684 * @nodes1 and @nodes2 are sorted by document order, then
4685 * #exslSetsLeadingSorted is called.
4686 *
4687 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4688 * in document order, @nodes1 if @nodes2 is NULL or empty or
4689 * an empty node-set if @nodes1 doesn't contain @nodes2
4690 */
4691 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4692 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4693 if (xmlXPathNodeSetIsEmpty(nodes2))
4694 return(nodes1);
4695 if (xmlXPathNodeSetIsEmpty(nodes1))
4696 return(xmlXPathNodeSetCreate(NULL));
4697 xmlXPathNodeSetSort(nodes1);
4698 xmlXPathNodeSetSort(nodes2);
4699 return(xmlXPathNodeLeadingSorted(nodes1,
4700 xmlXPathNodeSetItem(nodes2, 1)));
4701 }
4702
4703 /**
4704 * xmlXPathNodeTrailingSorted:
4705 * @nodes: a node-set, sorted by document order
4706 * @node: a node
4707 *
4708 * Implements the EXSLT - Sets trailing() function:
4709 * node-set set:trailing (node-set, node-set)
4710 *
4711 * Returns the nodes in @nodes that follow @node in document order,
4712 * @nodes if @node is NULL or an empty node-set if @nodes
4713 * doesn't contain @node
4714 */
4715 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4716 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4717 int i, l;
4718 xmlNodePtr cur;
4719 xmlNodeSetPtr ret;
4720
4721 if (node == NULL)
4722 return(nodes);
4723
4724 ret = xmlXPathNodeSetCreate(NULL);
4725 if (ret == NULL)
4726 return(ret);
4727 if (xmlXPathNodeSetIsEmpty(nodes) ||
4728 (!xmlXPathNodeSetContains(nodes, node)))
4729 return(ret);
4730
4731 l = xmlXPathNodeSetGetLength(nodes);
4732 for (i = l - 1; i >= 0; i--) {
4733 cur = xmlXPathNodeSetItem(nodes, i);
4734 if (cur == node)
4735 break;
4736 /* TODO: Propagate memory error. */
4737 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4738 break;
4739 }
4740 xmlXPathNodeSetSort(ret); /* bug 413451 */
4741 return(ret);
4742 }
4743
4744 /**
4745 * xmlXPathNodeTrailing:
4746 * @nodes: a node-set
4747 * @node: a node
4748 *
4749 * Implements the EXSLT - Sets trailing() function:
4750 * node-set set:trailing (node-set, node-set)
4751 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4752 * is called.
4753 *
4754 * Returns the nodes in @nodes that follow @node in document order,
4755 * @nodes if @node is NULL or an empty node-set if @nodes
4756 * doesn't contain @node
4757 */
4758 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4759 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4760 xmlXPathNodeSetSort(nodes);
4761 return(xmlXPathNodeTrailingSorted(nodes, node));
4762 }
4763
4764 /**
4765 * xmlXPathTrailingSorted:
4766 * @nodes1: a node-set, sorted by document order
4767 * @nodes2: a node-set, sorted by document order
4768 *
4769 * Implements the EXSLT - Sets trailing() function:
4770 * node-set set:trailing (node-set, node-set)
4771 *
4772 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4773 * in document order, @nodes1 if @nodes2 is NULL or empty or
4774 * an empty node-set if @nodes1 doesn't contain @nodes2
4775 */
4776 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4777 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4778 if (xmlXPathNodeSetIsEmpty(nodes2))
4779 return(nodes1);
4780 return(xmlXPathNodeTrailingSorted(nodes1,
4781 xmlXPathNodeSetItem(nodes2, 0)));
4782 }
4783
4784 /**
4785 * xmlXPathTrailing:
4786 * @nodes1: a node-set
4787 * @nodes2: a node-set
4788 *
4789 * Implements the EXSLT - Sets trailing() function:
4790 * node-set set:trailing (node-set, node-set)
4791 * @nodes1 and @nodes2 are sorted by document order, then
4792 * #xmlXPathTrailingSorted is called.
4793 *
4794 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4795 * in document order, @nodes1 if @nodes2 is NULL or empty or
4796 * an empty node-set if @nodes1 doesn't contain @nodes2
4797 */
4798 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4799 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4800 if (xmlXPathNodeSetIsEmpty(nodes2))
4801 return(nodes1);
4802 if (xmlXPathNodeSetIsEmpty(nodes1))
4803 return(xmlXPathNodeSetCreate(NULL));
4804 xmlXPathNodeSetSort(nodes1);
4805 xmlXPathNodeSetSort(nodes2);
4806 return(xmlXPathNodeTrailingSorted(nodes1,
4807 xmlXPathNodeSetItem(nodes2, 0)));
4808 }
4809
4810 /************************************************************************
4811 * *
4812 * Routines to handle extra functions *
4813 * *
4814 ************************************************************************/
4815
4816 /**
4817 * xmlXPathRegisterFunc:
4818 * @ctxt: the XPath context
4819 * @name: the function name
4820 * @f: the function implementation or NULL
4821 *
4822 * Register a new function. If @f is NULL it unregisters the function
4823 *
4824 * Returns 0 in case of success, -1 in case of error
4825 */
4826 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4827 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4828 xmlXPathFunction f) {
4829 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4830 }
4831
4832 /**
4833 * xmlXPathRegisterFuncNS:
4834 * @ctxt: the XPath context
4835 * @name: the function name
4836 * @ns_uri: the function namespace URI
4837 * @f: the function implementation or NULL
4838 *
4839 * Register a new function. If @f is NULL it unregisters the function
4840 *
4841 * Returns 0 in case of success, -1 in case of error
4842 */
4843 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4844 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4845 const xmlChar *ns_uri, xmlXPathFunction f) {
4846 if (ctxt == NULL)
4847 return(-1);
4848 if (name == NULL)
4849 return(-1);
4850
4851 if (ctxt->funcHash == NULL)
4852 ctxt->funcHash = xmlHashCreate(0);
4853 if (ctxt->funcHash == NULL)
4854 return(-1);
4855 if (f == NULL)
4856 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4857 XML_IGNORE_PEDANTIC_WARNINGS
4858 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4859 XML_POP_WARNINGS
4860 }
4861
4862 /**
4863 * xmlXPathRegisterFuncLookup:
4864 * @ctxt: the XPath context
4865 * @f: the lookup function
4866 * @funcCtxt: the lookup data
4867 *
4868 * Registers an external mechanism to do function lookup.
4869 */
4870 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4871 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4872 xmlXPathFuncLookupFunc f,
4873 void *funcCtxt) {
4874 if (ctxt == NULL)
4875 return;
4876 ctxt->funcLookupFunc = f;
4877 ctxt->funcLookupData = funcCtxt;
4878 }
4879
4880 /**
4881 * xmlXPathFunctionLookup:
4882 * @ctxt: the XPath context
4883 * @name: the function name
4884 *
4885 * Search in the Function array of the context for the given
4886 * function.
4887 *
4888 * Returns the xmlXPathFunction or NULL if not found
4889 */
4890 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4891 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4892 if (ctxt == NULL)
4893 return (NULL);
4894
4895 if (ctxt->funcLookupFunc != NULL) {
4896 xmlXPathFunction ret;
4897 xmlXPathFuncLookupFunc f;
4898
4899 f = ctxt->funcLookupFunc;
4900 ret = f(ctxt->funcLookupData, name, NULL);
4901 if (ret != NULL)
4902 return(ret);
4903 }
4904 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4905 }
4906
4907 /**
4908 * xmlXPathFunctionLookupNS:
4909 * @ctxt: the XPath context
4910 * @name: the function name
4911 * @ns_uri: the function namespace URI
4912 *
4913 * Search in the Function array of the context for the given
4914 * function.
4915 *
4916 * Returns the xmlXPathFunction or NULL if not found
4917 */
4918 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4919 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4920 const xmlChar *ns_uri) {
4921 xmlXPathFunction ret;
4922
4923 if (ctxt == NULL)
4924 return(NULL);
4925 if (name == NULL)
4926 return(NULL);
4927
4928 if (ctxt->funcLookupFunc != NULL) {
4929 xmlXPathFuncLookupFunc f;
4930
4931 f = ctxt->funcLookupFunc;
4932 ret = f(ctxt->funcLookupData, name, ns_uri);
4933 if (ret != NULL)
4934 return(ret);
4935 }
4936
4937 if (ctxt->funcHash == NULL)
4938 return(NULL);
4939
4940 XML_IGNORE_PEDANTIC_WARNINGS
4941 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4942 XML_POP_WARNINGS
4943 return(ret);
4944 }
4945
4946 /**
4947 * xmlXPathRegisteredFuncsCleanup:
4948 * @ctxt: the XPath context
4949 *
4950 * Cleanup the XPath context data associated to registered functions
4951 */
4952 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4953 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4954 if (ctxt == NULL)
4955 return;
4956
4957 xmlHashFree(ctxt->funcHash, NULL);
4958 ctxt->funcHash = NULL;
4959 }
4960
4961 /************************************************************************
4962 * *
4963 * Routines to handle Variables *
4964 * *
4965 ************************************************************************/
4966
4967 /**
4968 * xmlXPathRegisterVariable:
4969 * @ctxt: the XPath context
4970 * @name: the variable name
4971 * @value: the variable value or NULL
4972 *
4973 * Register a new variable value. If @value is NULL it unregisters
4974 * the variable
4975 *
4976 * Returns 0 in case of success, -1 in case of error
4977 */
4978 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4979 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4980 xmlXPathObjectPtr value) {
4981 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4982 }
4983
4984 /**
4985 * xmlXPathRegisterVariableNS:
4986 * @ctxt: the XPath context
4987 * @name: the variable name
4988 * @ns_uri: the variable namespace URI
4989 * @value: the variable value or NULL
4990 *
4991 * Register a new variable value. If @value is NULL it unregisters
4992 * the variable
4993 *
4994 * Returns 0 in case of success, -1 in case of error
4995 */
4996 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4997 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4998 const xmlChar *ns_uri,
4999 xmlXPathObjectPtr value) {
5000 if (ctxt == NULL)
5001 return(-1);
5002 if (name == NULL)
5003 return(-1);
5004
5005 if (ctxt->varHash == NULL)
5006 ctxt->varHash = xmlHashCreate(0);
5007 if (ctxt->varHash == NULL)
5008 return(-1);
5009 if (value == NULL)
5010 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5011 xmlXPathFreeObjectEntry));
5012 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5013 (void *) value, xmlXPathFreeObjectEntry));
5014 }
5015
5016 /**
5017 * xmlXPathRegisterVariableLookup:
5018 * @ctxt: the XPath context
5019 * @f: the lookup function
5020 * @data: the lookup data
5021 *
5022 * register an external mechanism to do variable lookup
5023 */
5024 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5025 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5026 xmlXPathVariableLookupFunc f, void *data) {
5027 if (ctxt == NULL)
5028 return;
5029 ctxt->varLookupFunc = f;
5030 ctxt->varLookupData = data;
5031 }
5032
5033 /**
5034 * xmlXPathVariableLookup:
5035 * @ctxt: the XPath context
5036 * @name: the variable name
5037 *
5038 * Search in the Variable array of the context for the given
5039 * variable value.
5040 *
5041 * Returns a copy of the value or NULL if not found
5042 */
5043 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5044 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5045 if (ctxt == NULL)
5046 return(NULL);
5047
5048 if (ctxt->varLookupFunc != NULL) {
5049 xmlXPathObjectPtr ret;
5050
5051 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5052 (ctxt->varLookupData, name, NULL);
5053 return(ret);
5054 }
5055 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5056 }
5057
5058 /**
5059 * xmlXPathVariableLookupNS:
5060 * @ctxt: the XPath context
5061 * @name: the variable name
5062 * @ns_uri: the variable namespace URI
5063 *
5064 * Search in the Variable array of the context for the given
5065 * variable value.
5066 *
5067 * Returns the a copy of the value or NULL if not found
5068 */
5069 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5070 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5071 const xmlChar *ns_uri) {
5072 if (ctxt == NULL)
5073 return(NULL);
5074
5075 if (ctxt->varLookupFunc != NULL) {
5076 xmlXPathObjectPtr ret;
5077
5078 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5079 (ctxt->varLookupData, name, ns_uri);
5080 if (ret != NULL) return(ret);
5081 }
5082
5083 if (ctxt->varHash == NULL)
5084 return(NULL);
5085 if (name == NULL)
5086 return(NULL);
5087
5088 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5089 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5090 }
5091
5092 /**
5093 * xmlXPathRegisteredVariablesCleanup:
5094 * @ctxt: the XPath context
5095 *
5096 * Cleanup the XPath context data associated to registered variables
5097 */
5098 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5099 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5100 if (ctxt == NULL)
5101 return;
5102
5103 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5104 ctxt->varHash = NULL;
5105 }
5106
5107 /**
5108 * xmlXPathRegisterNs:
5109 * @ctxt: the XPath context
5110 * @prefix: the namespace prefix cannot be NULL or empty string
5111 * @ns_uri: the namespace name
5112 *
5113 * Register a new namespace. If @ns_uri is NULL it unregisters
5114 * the namespace
5115 *
5116 * Returns 0 in case of success, -1 in case of error
5117 */
5118 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5119 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5120 const xmlChar *ns_uri) {
5121 if (ctxt == NULL)
5122 return(-1);
5123 if (prefix == NULL)
5124 return(-1);
5125 if (prefix[0] == 0)
5126 return(-1);
5127
5128 if (ctxt->nsHash == NULL)
5129 ctxt->nsHash = xmlHashCreate(10);
5130 if (ctxt->nsHash == NULL)
5131 return(-1);
5132 if (ns_uri == NULL)
5133 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5134 xmlHashDefaultDeallocator));
5135 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5136 xmlHashDefaultDeallocator));
5137 }
5138
5139 /**
5140 * xmlXPathNsLookup:
5141 * @ctxt: the XPath context
5142 * @prefix: the namespace prefix value
5143 *
5144 * Search in the namespace declaration array of the context for the given
5145 * namespace name associated to the given prefix
5146 *
5147 * Returns the value or NULL if not found
5148 */
5149 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5150 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5151 if (ctxt == NULL)
5152 return(NULL);
5153 if (prefix == NULL)
5154 return(NULL);
5155
5156 #ifdef XML_XML_NAMESPACE
5157 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5158 return(XML_XML_NAMESPACE);
5159 #endif
5160
5161 if (ctxt->namespaces != NULL) {
5162 int i;
5163
5164 for (i = 0;i < ctxt->nsNr;i++) {
5165 if ((ctxt->namespaces[i] != NULL) &&
5166 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5167 return(ctxt->namespaces[i]->href);
5168 }
5169 }
5170
5171 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5172 }
5173
5174 /**
5175 * xmlXPathRegisteredNsCleanup:
5176 * @ctxt: the XPath context
5177 *
5178 * Cleanup the XPath context data associated to registered variables
5179 */
5180 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5181 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5182 if (ctxt == NULL)
5183 return;
5184
5185 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5186 ctxt->nsHash = NULL;
5187 }
5188
5189 /************************************************************************
5190 * *
5191 * Routines to handle Values *
5192 * *
5193 ************************************************************************/
5194
5195 /* Allocations are terrible, one needs to optimize all this !!! */
5196
5197 /**
5198 * xmlXPathNewFloat:
5199 * @val: the double value
5200 *
5201 * Create a new xmlXPathObjectPtr of type double and of value @val
5202 *
5203 * Returns the newly created object.
5204 */
5205 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5206 xmlXPathNewFloat(double val) {
5207 xmlXPathObjectPtr ret;
5208
5209 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5210 if (ret == NULL) {
5211 xmlXPathErrMemory(NULL, "creating float object\n");
5212 return(NULL);
5213 }
5214 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5215 ret->type = XPATH_NUMBER;
5216 ret->floatval = val;
5217 #ifdef XP_DEBUG_OBJ_USAGE
5218 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5219 #endif
5220 return(ret);
5221 }
5222
5223 /**
5224 * xmlXPathNewBoolean:
5225 * @val: the boolean value
5226 *
5227 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5228 *
5229 * Returns the newly created object.
5230 */
5231 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5232 xmlXPathNewBoolean(int val) {
5233 xmlXPathObjectPtr ret;
5234
5235 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5236 if (ret == NULL) {
5237 xmlXPathErrMemory(NULL, "creating boolean object\n");
5238 return(NULL);
5239 }
5240 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5241 ret->type = XPATH_BOOLEAN;
5242 ret->boolval = (val != 0);
5243 #ifdef XP_DEBUG_OBJ_USAGE
5244 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5245 #endif
5246 return(ret);
5247 }
5248
5249 /**
5250 * xmlXPathNewString:
5251 * @val: the xmlChar * value
5252 *
5253 * Create a new xmlXPathObjectPtr of type string and of value @val
5254 *
5255 * Returns the newly created object.
5256 */
5257 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5258 xmlXPathNewString(const xmlChar *val) {
5259 xmlXPathObjectPtr ret;
5260
5261 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262 if (ret == NULL) {
5263 xmlXPathErrMemory(NULL, "creating string object\n");
5264 return(NULL);
5265 }
5266 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5267 ret->type = XPATH_STRING;
5268 if (val != NULL)
5269 ret->stringval = xmlStrdup(val);
5270 else
5271 ret->stringval = xmlStrdup((const xmlChar *)"");
5272 #ifdef XP_DEBUG_OBJ_USAGE
5273 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5274 #endif
5275 return(ret);
5276 }
5277
5278 /**
5279 * xmlXPathWrapString:
5280 * @val: the xmlChar * value
5281 *
5282 * Wraps the @val string into an XPath object.
5283 *
5284 * Returns the newly created object.
5285 */
5286 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5287 xmlXPathWrapString (xmlChar *val) {
5288 xmlXPathObjectPtr ret;
5289
5290 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5291 if (ret == NULL) {
5292 xmlXPathErrMemory(NULL, "creating string object\n");
5293 return(NULL);
5294 }
5295 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5296 ret->type = XPATH_STRING;
5297 ret->stringval = val;
5298 #ifdef XP_DEBUG_OBJ_USAGE
5299 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5300 #endif
5301 return(ret);
5302 }
5303
5304 /**
5305 * xmlXPathNewCString:
5306 * @val: the char * value
5307 *
5308 * Create a new xmlXPathObjectPtr of type string and of value @val
5309 *
5310 * Returns the newly created object.
5311 */
5312 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5313 xmlXPathNewCString(const char *val) {
5314 xmlXPathObjectPtr ret;
5315
5316 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5317 if (ret == NULL) {
5318 xmlXPathErrMemory(NULL, "creating string object\n");
5319 return(NULL);
5320 }
5321 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5322 ret->type = XPATH_STRING;
5323 ret->stringval = xmlStrdup(BAD_CAST val);
5324 #ifdef XP_DEBUG_OBJ_USAGE
5325 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5326 #endif
5327 return(ret);
5328 }
5329
5330 /**
5331 * xmlXPathWrapCString:
5332 * @val: the char * value
5333 *
5334 * Wraps a string into an XPath object.
5335 *
5336 * Returns the newly created object.
5337 */
5338 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5339 xmlXPathWrapCString (char * val) {
5340 return(xmlXPathWrapString((xmlChar *)(val)));
5341 }
5342
5343 /**
5344 * xmlXPathWrapExternal:
5345 * @val: the user data
5346 *
5347 * Wraps the @val data into an XPath object.
5348 *
5349 * Returns the newly created object.
5350 */
5351 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5352 xmlXPathWrapExternal (void *val) {
5353 xmlXPathObjectPtr ret;
5354
5355 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5356 if (ret == NULL) {
5357 xmlXPathErrMemory(NULL, "creating user object\n");
5358 return(NULL);
5359 }
5360 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5361 ret->type = XPATH_USERS;
5362 ret->user = val;
5363 #ifdef XP_DEBUG_OBJ_USAGE
5364 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5365 #endif
5366 return(ret);
5367 }
5368
5369 /**
5370 * xmlXPathObjectCopy:
5371 * @val: the original object
5372 *
5373 * allocate a new copy of a given object
5374 *
5375 * Returns the newly created object.
5376 */
5377 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5378 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5379 xmlXPathObjectPtr ret;
5380
5381 if (val == NULL)
5382 return(NULL);
5383
5384 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5385 if (ret == NULL) {
5386 xmlXPathErrMemory(NULL, "copying object\n");
5387 return(NULL);
5388 }
5389 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5390 #ifdef XP_DEBUG_OBJ_USAGE
5391 xmlXPathDebugObjUsageRequested(NULL, val->type);
5392 #endif
5393 switch (val->type) {
5394 case XPATH_BOOLEAN:
5395 case XPATH_NUMBER:
5396 #ifdef LIBXML_XPTR_LOCS_ENABLED
5397 case XPATH_POINT:
5398 case XPATH_RANGE:
5399 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5400 break;
5401 case XPATH_STRING:
5402 ret->stringval = xmlStrdup(val->stringval);
5403 break;
5404 case XPATH_XSLT_TREE:
5405 #if 0
5406 /*
5407 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5408 this previous handling is no longer correct, and can cause some serious
5409 problems (ref. bug 145547)
5410 */
5411 if ((val->nodesetval != NULL) &&
5412 (val->nodesetval->nodeTab != NULL)) {
5413 xmlNodePtr cur, tmp;
5414 xmlDocPtr top;
5415
5416 ret->boolval = 1;
5417 top = xmlNewDoc(NULL);
5418 top->name = (char *)
5419 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5420 ret->user = top;
5421 if (top != NULL) {
5422 top->doc = top;
5423 cur = val->nodesetval->nodeTab[0]->children;
5424 while (cur != NULL) {
5425 tmp = xmlDocCopyNode(cur, top, 1);
5426 xmlAddChild((xmlNodePtr) top, tmp);
5427 cur = cur->next;
5428 }
5429 }
5430
5431 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5432 } else
5433 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5434 /* Deallocate the copied tree value */
5435 break;
5436 #endif
5437 case XPATH_NODESET:
5438 /* TODO: Check memory error. */
5439 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5440 /* Do not deallocate the copied tree value */
5441 ret->boolval = 0;
5442 break;
5443 #ifdef LIBXML_XPTR_LOCS_ENABLED
5444 case XPATH_LOCATIONSET:
5445 {
5446 xmlLocationSetPtr loc = val->user;
5447 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5448 break;
5449 }
5450 #endif
5451 case XPATH_USERS:
5452 ret->user = val->user;
5453 break;
5454 case XPATH_UNDEFINED:
5455 xmlGenericError(xmlGenericErrorContext,
5456 "xmlXPathObjectCopy: unsupported type %d\n",
5457 val->type);
5458 break;
5459 }
5460 return(ret);
5461 }
5462
5463 /**
5464 * xmlXPathFreeObject:
5465 * @obj: the object to free
5466 *
5467 * Free up an xmlXPathObjectPtr object.
5468 */
5469 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5470 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5471 if (obj == NULL) return;
5472 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5473 if (obj->boolval) {
5474 #if 0
5475 if (obj->user != NULL) {
5476 xmlXPathFreeNodeSet(obj->nodesetval);
5477 xmlFreeNodeList((xmlNodePtr) obj->user);
5478 } else
5479 #endif
5480 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5481 if (obj->nodesetval != NULL)
5482 xmlXPathFreeValueTree(obj->nodesetval);
5483 } else {
5484 if (obj->nodesetval != NULL)
5485 xmlXPathFreeNodeSet(obj->nodesetval);
5486 }
5487 #ifdef LIBXML_XPTR_LOCS_ENABLED
5488 } else if (obj->type == XPATH_LOCATIONSET) {
5489 if (obj->user != NULL)
5490 xmlXPtrFreeLocationSet(obj->user);
5491 #endif
5492 } else if (obj->type == XPATH_STRING) {
5493 if (obj->stringval != NULL)
5494 xmlFree(obj->stringval);
5495 }
5496 #ifdef XP_DEBUG_OBJ_USAGE
5497 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498 #endif
5499 xmlFree(obj);
5500 }
5501
5502 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5503 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5504 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5505 }
5506
5507 /**
5508 * xmlXPathReleaseObject:
5509 * @obj: the xmlXPathObjectPtr to free or to cache
5510 *
5511 * Depending on the state of the cache this frees the given
5512 * XPath object or stores it in the cache.
5513 */
5514 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5515 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5516 {
5517 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5518 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5519 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5520
5521 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5522
5523 if (obj == NULL)
5524 return;
5525 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5526 xmlXPathFreeObject(obj);
5527 } else {
5528 xmlXPathContextCachePtr cache =
5529 (xmlXPathContextCachePtr) ctxt->cache;
5530
5531 switch (obj->type) {
5532 case XPATH_NODESET:
5533 case XPATH_XSLT_TREE:
5534 if (obj->nodesetval != NULL) {
5535 if (obj->boolval) {
5536 /*
5537 * It looks like the @boolval is used for
5538 * evaluation if this an XSLT Result Tree Fragment.
5539 * TODO: Check if this assumption is correct.
5540 */
5541 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5542 xmlXPathFreeValueTree(obj->nodesetval);
5543 obj->nodesetval = NULL;
5544 } else if ((obj->nodesetval->nodeMax <= 40) &&
5545 (XP_CACHE_WANTS(cache->nodesetObjs,
5546 cache->maxNodeset)))
5547 {
5548 XP_CACHE_ADD(cache->nodesetObjs, obj);
5549 goto obj_cached;
5550 } else {
5551 xmlXPathFreeNodeSet(obj->nodesetval);
5552 obj->nodesetval = NULL;
5553 }
5554 }
5555 break;
5556 case XPATH_STRING:
5557 if (obj->stringval != NULL)
5558 xmlFree(obj->stringval);
5559
5560 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5561 XP_CACHE_ADD(cache->stringObjs, obj);
5562 goto obj_cached;
5563 }
5564 break;
5565 case XPATH_BOOLEAN:
5566 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5567 XP_CACHE_ADD(cache->booleanObjs, obj);
5568 goto obj_cached;
5569 }
5570 break;
5571 case XPATH_NUMBER:
5572 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5573 XP_CACHE_ADD(cache->numberObjs, obj);
5574 goto obj_cached;
5575 }
5576 break;
5577 #ifdef LIBXML_XPTR_LOCS_ENABLED
5578 case XPATH_LOCATIONSET:
5579 if (obj->user != NULL) {
5580 xmlXPtrFreeLocationSet(obj->user);
5581 }
5582 goto free_obj;
5583 #endif
5584 default:
5585 goto free_obj;
5586 }
5587
5588 /*
5589 * Fallback to adding to the misc-objects slot.
5590 */
5591 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5592 XP_CACHE_ADD(cache->miscObjs, obj);
5593 } else
5594 goto free_obj;
5595
5596 obj_cached:
5597
5598 #ifdef XP_DEBUG_OBJ_USAGE
5599 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5600 #endif
5601
5602 if (obj->nodesetval != NULL) {
5603 xmlNodeSetPtr tmpset = obj->nodesetval;
5604
5605 /*
5606 * TODO: Due to those nasty ns-nodes, we need to traverse
5607 * the list and free the ns-nodes.
5608 * URGENT TODO: Check if it's actually slowing things down.
5609 * Maybe we shouldn't try to preserve the list.
5610 */
5611 if (tmpset->nodeNr > 1) {
5612 int i;
5613 xmlNodePtr node;
5614
5615 for (i = 0; i < tmpset->nodeNr; i++) {
5616 node = tmpset->nodeTab[i];
5617 if ((node != NULL) &&
5618 (node->type == XML_NAMESPACE_DECL))
5619 {
5620 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5621 }
5622 }
5623 } else if (tmpset->nodeNr == 1) {
5624 if ((tmpset->nodeTab[0] != NULL) &&
5625 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5626 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5627 }
5628 tmpset->nodeNr = 0;
5629 memset(obj, 0, sizeof(xmlXPathObject));
5630 obj->nodesetval = tmpset;
5631 } else
5632 memset(obj, 0, sizeof(xmlXPathObject));
5633
5634 return;
5635
5636 free_obj:
5637 /*
5638 * Cache is full; free the object.
5639 */
5640 if (obj->nodesetval != NULL)
5641 xmlXPathFreeNodeSet(obj->nodesetval);
5642 #ifdef XP_DEBUG_OBJ_USAGE
5643 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5644 #endif
5645 xmlFree(obj);
5646 }
5647 return;
5648 }
5649
5650
5651 /************************************************************************
5652 * *
5653 * Type Casting Routines *
5654 * *
5655 ************************************************************************/
5656
5657 /**
5658 * xmlXPathCastBooleanToString:
5659 * @val: a boolean
5660 *
5661 * Converts a boolean to its string value.
5662 *
5663 * Returns a newly allocated string.
5664 */
5665 xmlChar *
xmlXPathCastBooleanToString(int val)5666 xmlXPathCastBooleanToString (int val) {
5667 xmlChar *ret;
5668 if (val)
5669 ret = xmlStrdup((const xmlChar *) "true");
5670 else
5671 ret = xmlStrdup((const xmlChar *) "false");
5672 return(ret);
5673 }
5674
5675 /**
5676 * xmlXPathCastNumberToString:
5677 * @val: a number
5678 *
5679 * Converts a number to its string value.
5680 *
5681 * Returns a newly allocated string.
5682 */
5683 xmlChar *
xmlXPathCastNumberToString(double val)5684 xmlXPathCastNumberToString (double val) {
5685 xmlChar *ret;
5686 switch (xmlXPathIsInf(val)) {
5687 case 1:
5688 ret = xmlStrdup((const xmlChar *) "Infinity");
5689 break;
5690 case -1:
5691 ret = xmlStrdup((const xmlChar *) "-Infinity");
5692 break;
5693 default:
5694 if (xmlXPathIsNaN(val)) {
5695 ret = xmlStrdup((const xmlChar *) "NaN");
5696 } else if (val == 0) {
5697 /* Omit sign for negative zero. */
5698 ret = xmlStrdup((const xmlChar *) "0");
5699 } else {
5700 /* could be improved */
5701 char buf[100];
5702 xmlXPathFormatNumber(val, buf, 99);
5703 buf[99] = 0;
5704 ret = xmlStrdup((const xmlChar *) buf);
5705 }
5706 }
5707 return(ret);
5708 }
5709
5710 /**
5711 * xmlXPathCastNodeToString:
5712 * @node: a node
5713 *
5714 * Converts a node to its string value.
5715 *
5716 * Returns a newly allocated string.
5717 */
5718 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5719 xmlXPathCastNodeToString (xmlNodePtr node) {
5720 xmlChar *ret;
5721 if ((ret = xmlNodeGetContent(node)) == NULL)
5722 ret = xmlStrdup((const xmlChar *) "");
5723 return(ret);
5724 }
5725
5726 /**
5727 * xmlXPathCastNodeSetToString:
5728 * @ns: a node-set
5729 *
5730 * Converts a node-set to its string value.
5731 *
5732 * Returns a newly allocated string.
5733 */
5734 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5735 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5736 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5737 return(xmlStrdup((const xmlChar *) ""));
5738
5739 if (ns->nodeNr > 1)
5740 xmlXPathNodeSetSort(ns);
5741 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5742 }
5743
5744 /**
5745 * xmlXPathCastToString:
5746 * @val: an XPath object
5747 *
5748 * Converts an existing object to its string() equivalent
5749 *
5750 * Returns the allocated string value of the object, NULL in case of error.
5751 * It's up to the caller to free the string memory with xmlFree().
5752 */
5753 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5754 xmlXPathCastToString(xmlXPathObjectPtr val) {
5755 xmlChar *ret = NULL;
5756
5757 if (val == NULL)
5758 return(xmlStrdup((const xmlChar *) ""));
5759 switch (val->type) {
5760 case XPATH_UNDEFINED:
5761 #ifdef DEBUG_EXPR
5762 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5763 #endif
5764 ret = xmlStrdup((const xmlChar *) "");
5765 break;
5766 case XPATH_NODESET:
5767 case XPATH_XSLT_TREE:
5768 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5769 break;
5770 case XPATH_STRING:
5771 return(xmlStrdup(val->stringval));
5772 case XPATH_BOOLEAN:
5773 ret = xmlXPathCastBooleanToString(val->boolval);
5774 break;
5775 case XPATH_NUMBER: {
5776 ret = xmlXPathCastNumberToString(val->floatval);
5777 break;
5778 }
5779 case XPATH_USERS:
5780 #ifdef LIBXML_XPTR_LOCS_ENABLED
5781 case XPATH_POINT:
5782 case XPATH_RANGE:
5783 case XPATH_LOCATIONSET:
5784 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5785 TODO
5786 ret = xmlStrdup((const xmlChar *) "");
5787 break;
5788 }
5789 return(ret);
5790 }
5791
5792 /**
5793 * xmlXPathConvertString:
5794 * @val: an XPath object
5795 *
5796 * Converts an existing object to its string() equivalent
5797 *
5798 * Returns the new object, the old one is freed (or the operation
5799 * is done directly on @val)
5800 */
5801 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5802 xmlXPathConvertString(xmlXPathObjectPtr val) {
5803 xmlChar *res = NULL;
5804
5805 if (val == NULL)
5806 return(xmlXPathNewCString(""));
5807
5808 switch (val->type) {
5809 case XPATH_UNDEFINED:
5810 #ifdef DEBUG_EXPR
5811 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5812 #endif
5813 break;
5814 case XPATH_NODESET:
5815 case XPATH_XSLT_TREE:
5816 res = xmlXPathCastNodeSetToString(val->nodesetval);
5817 break;
5818 case XPATH_STRING:
5819 return(val);
5820 case XPATH_BOOLEAN:
5821 res = xmlXPathCastBooleanToString(val->boolval);
5822 break;
5823 case XPATH_NUMBER:
5824 res = xmlXPathCastNumberToString(val->floatval);
5825 break;
5826 case XPATH_USERS:
5827 #ifdef LIBXML_XPTR_LOCS_ENABLED
5828 case XPATH_POINT:
5829 case XPATH_RANGE:
5830 case XPATH_LOCATIONSET:
5831 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5832 TODO;
5833 break;
5834 }
5835 xmlXPathFreeObject(val);
5836 if (res == NULL)
5837 return(xmlXPathNewCString(""));
5838 return(xmlXPathWrapString(res));
5839 }
5840
5841 /**
5842 * xmlXPathCastBooleanToNumber:
5843 * @val: a boolean
5844 *
5845 * Converts a boolean to its number value
5846 *
5847 * Returns the number value
5848 */
5849 double
xmlXPathCastBooleanToNumber(int val)5850 xmlXPathCastBooleanToNumber(int val) {
5851 if (val)
5852 return(1.0);
5853 return(0.0);
5854 }
5855
5856 /**
5857 * xmlXPathCastStringToNumber:
5858 * @val: a string
5859 *
5860 * Converts a string to its number value
5861 *
5862 * Returns the number value
5863 */
5864 double
xmlXPathCastStringToNumber(const xmlChar * val)5865 xmlXPathCastStringToNumber(const xmlChar * val) {
5866 return(xmlXPathStringEvalNumber(val));
5867 }
5868
5869 /**
5870 * xmlXPathCastNodeToNumber:
5871 * @node: a node
5872 *
5873 * Converts a node to its number value
5874 *
5875 * Returns the number value
5876 */
5877 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5878 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5879 xmlChar *strval;
5880 double ret;
5881
5882 if (node == NULL)
5883 return(xmlXPathNAN);
5884 strval = xmlXPathCastNodeToString(node);
5885 if (strval == NULL)
5886 return(xmlXPathNAN);
5887 ret = xmlXPathCastStringToNumber(strval);
5888 xmlFree(strval);
5889
5890 return(ret);
5891 }
5892
5893 /**
5894 * xmlXPathCastNodeSetToNumber:
5895 * @ns: a node-set
5896 *
5897 * Converts a node-set to its number value
5898 *
5899 * Returns the number value
5900 */
5901 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5902 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5903 xmlChar *str;
5904 double ret;
5905
5906 if (ns == NULL)
5907 return(xmlXPathNAN);
5908 str = xmlXPathCastNodeSetToString(ns);
5909 ret = xmlXPathCastStringToNumber(str);
5910 xmlFree(str);
5911 return(ret);
5912 }
5913
5914 /**
5915 * xmlXPathCastToNumber:
5916 * @val: an XPath object
5917 *
5918 * Converts an XPath object to its number value
5919 *
5920 * Returns the number value
5921 */
5922 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5923 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5924 double ret = 0.0;
5925
5926 if (val == NULL)
5927 return(xmlXPathNAN);
5928 switch (val->type) {
5929 case XPATH_UNDEFINED:
5930 #ifdef DEBUG_EXPR
5931 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5932 #endif
5933 ret = xmlXPathNAN;
5934 break;
5935 case XPATH_NODESET:
5936 case XPATH_XSLT_TREE:
5937 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5938 break;
5939 case XPATH_STRING:
5940 ret = xmlXPathCastStringToNumber(val->stringval);
5941 break;
5942 case XPATH_NUMBER:
5943 ret = val->floatval;
5944 break;
5945 case XPATH_BOOLEAN:
5946 ret = xmlXPathCastBooleanToNumber(val->boolval);
5947 break;
5948 case XPATH_USERS:
5949 #ifdef LIBXML_XPTR_LOCS_ENABLED
5950 case XPATH_POINT:
5951 case XPATH_RANGE:
5952 case XPATH_LOCATIONSET:
5953 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5954 TODO;
5955 ret = xmlXPathNAN;
5956 break;
5957 }
5958 return(ret);
5959 }
5960
5961 /**
5962 * xmlXPathConvertNumber:
5963 * @val: an XPath object
5964 *
5965 * Converts an existing object to its number() equivalent
5966 *
5967 * Returns the new object, the old one is freed (or the operation
5968 * is done directly on @val)
5969 */
5970 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5971 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5972 xmlXPathObjectPtr ret;
5973
5974 if (val == NULL)
5975 return(xmlXPathNewFloat(0.0));
5976 if (val->type == XPATH_NUMBER)
5977 return(val);
5978 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5979 xmlXPathFreeObject(val);
5980 return(ret);
5981 }
5982
5983 /**
5984 * xmlXPathCastNumberToBoolean:
5985 * @val: a number
5986 *
5987 * Converts a number to its boolean value
5988 *
5989 * Returns the boolean value
5990 */
5991 int
xmlXPathCastNumberToBoolean(double val)5992 xmlXPathCastNumberToBoolean (double val) {
5993 if (xmlXPathIsNaN(val) || (val == 0.0))
5994 return(0);
5995 return(1);
5996 }
5997
5998 /**
5999 * xmlXPathCastStringToBoolean:
6000 * @val: a string
6001 *
6002 * Converts a string to its boolean value
6003 *
6004 * Returns the boolean value
6005 */
6006 int
xmlXPathCastStringToBoolean(const xmlChar * val)6007 xmlXPathCastStringToBoolean (const xmlChar *val) {
6008 if ((val == NULL) || (xmlStrlen(val) == 0))
6009 return(0);
6010 return(1);
6011 }
6012
6013 /**
6014 * xmlXPathCastNodeSetToBoolean:
6015 * @ns: a node-set
6016 *
6017 * Converts a node-set to its boolean value
6018 *
6019 * Returns the boolean value
6020 */
6021 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6022 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6023 if ((ns == NULL) || (ns->nodeNr == 0))
6024 return(0);
6025 return(1);
6026 }
6027
6028 /**
6029 * xmlXPathCastToBoolean:
6030 * @val: an XPath object
6031 *
6032 * Converts an XPath object to its boolean value
6033 *
6034 * Returns the boolean value
6035 */
6036 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6037 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6038 int ret = 0;
6039
6040 if (val == NULL)
6041 return(0);
6042 switch (val->type) {
6043 case XPATH_UNDEFINED:
6044 #ifdef DEBUG_EXPR
6045 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6046 #endif
6047 ret = 0;
6048 break;
6049 case XPATH_NODESET:
6050 case XPATH_XSLT_TREE:
6051 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6052 break;
6053 case XPATH_STRING:
6054 ret = xmlXPathCastStringToBoolean(val->stringval);
6055 break;
6056 case XPATH_NUMBER:
6057 ret = xmlXPathCastNumberToBoolean(val->floatval);
6058 break;
6059 case XPATH_BOOLEAN:
6060 ret = val->boolval;
6061 break;
6062 case XPATH_USERS:
6063 #ifdef LIBXML_XPTR_LOCS_ENABLED
6064 case XPATH_POINT:
6065 case XPATH_RANGE:
6066 case XPATH_LOCATIONSET:
6067 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6068 TODO;
6069 ret = 0;
6070 break;
6071 }
6072 return(ret);
6073 }
6074
6075
6076 /**
6077 * xmlXPathConvertBoolean:
6078 * @val: an XPath object
6079 *
6080 * Converts an existing object to its boolean() equivalent
6081 *
6082 * Returns the new object, the old one is freed (or the operation
6083 * is done directly on @val)
6084 */
6085 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6086 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6087 xmlXPathObjectPtr ret;
6088
6089 if (val == NULL)
6090 return(xmlXPathNewBoolean(0));
6091 if (val->type == XPATH_BOOLEAN)
6092 return(val);
6093 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6094 xmlXPathFreeObject(val);
6095 return(ret);
6096 }
6097
6098 /************************************************************************
6099 * *
6100 * Routines to handle XPath contexts *
6101 * *
6102 ************************************************************************/
6103
6104 /**
6105 * xmlXPathNewContext:
6106 * @doc: the XML document
6107 *
6108 * Create a new xmlXPathContext
6109 *
6110 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6111 */
6112 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6113 xmlXPathNewContext(xmlDocPtr doc) {
6114 xmlXPathContextPtr ret;
6115
6116 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6117 if (ret == NULL) {
6118 xmlXPathErrMemory(NULL, "creating context\n");
6119 return(NULL);
6120 }
6121 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6122 ret->doc = doc;
6123 ret->node = NULL;
6124
6125 ret->varHash = NULL;
6126
6127 ret->nb_types = 0;
6128 ret->max_types = 0;
6129 ret->types = NULL;
6130
6131 ret->funcHash = xmlHashCreate(0);
6132
6133 ret->nb_axis = 0;
6134 ret->max_axis = 0;
6135 ret->axis = NULL;
6136
6137 ret->nsHash = NULL;
6138 ret->user = NULL;
6139
6140 ret->contextSize = -1;
6141 ret->proximityPosition = -1;
6142
6143 #ifdef XP_DEFAULT_CACHE_ON
6144 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6145 xmlXPathFreeContext(ret);
6146 return(NULL);
6147 }
6148 #endif
6149
6150 xmlXPathRegisterAllFunctions(ret);
6151
6152 return(ret);
6153 }
6154
6155 /**
6156 * xmlXPathFreeContext:
6157 * @ctxt: the context to free
6158 *
6159 * Free up an xmlXPathContext
6160 */
6161 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6162 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6163 if (ctxt == NULL) return;
6164
6165 if (ctxt->cache != NULL)
6166 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6167 xmlXPathRegisteredNsCleanup(ctxt);
6168 xmlXPathRegisteredFuncsCleanup(ctxt);
6169 xmlXPathRegisteredVariablesCleanup(ctxt);
6170 xmlResetError(&ctxt->lastError);
6171 xmlFree(ctxt);
6172 }
6173
6174 /************************************************************************
6175 * *
6176 * Routines to handle XPath parser contexts *
6177 * *
6178 ************************************************************************/
6179
6180 #define CHECK_CTXT(ctxt) \
6181 if (ctxt == NULL) { \
6182 __xmlRaiseError(NULL, NULL, NULL, \
6183 NULL, NULL, XML_FROM_XPATH, \
6184 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6185 __FILE__, __LINE__, \
6186 NULL, NULL, NULL, 0, 0, \
6187 "NULL context pointer\n"); \
6188 return(NULL); \
6189 } \
6190
6191 #define CHECK_CTXT_NEG(ctxt) \
6192 if (ctxt == NULL) { \
6193 __xmlRaiseError(NULL, NULL, NULL, \
6194 NULL, NULL, XML_FROM_XPATH, \
6195 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6196 __FILE__, __LINE__, \
6197 NULL, NULL, NULL, 0, 0, \
6198 "NULL context pointer\n"); \
6199 return(-1); \
6200 } \
6201
6202
6203 #define CHECK_CONTEXT(ctxt) \
6204 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6205 (ctxt->doc->children == NULL)) { \
6206 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6207 return(NULL); \
6208 }
6209
6210
6211 /**
6212 * xmlXPathNewParserContext:
6213 * @str: the XPath expression
6214 * @ctxt: the XPath context
6215 *
6216 * Create a new xmlXPathParserContext
6217 *
6218 * Returns the xmlXPathParserContext just allocated.
6219 */
6220 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6221 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6222 xmlXPathParserContextPtr ret;
6223
6224 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6225 if (ret == NULL) {
6226 xmlXPathErrMemory(ctxt, "creating parser context\n");
6227 return(NULL);
6228 }
6229 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6230 ret->cur = ret->base = str;
6231 ret->context = ctxt;
6232
6233 ret->comp = xmlXPathNewCompExpr();
6234 if (ret->comp == NULL) {
6235 xmlFree(ret->valueTab);
6236 xmlFree(ret);
6237 return(NULL);
6238 }
6239 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6240 ret->comp->dict = ctxt->dict;
6241 xmlDictReference(ret->comp->dict);
6242 }
6243
6244 return(ret);
6245 }
6246
6247 /**
6248 * xmlXPathCompParserContext:
6249 * @comp: the XPath compiled expression
6250 * @ctxt: the XPath context
6251 *
6252 * Create a new xmlXPathParserContext when processing a compiled expression
6253 *
6254 * Returns the xmlXPathParserContext just allocated.
6255 */
6256 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6257 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6258 xmlXPathParserContextPtr ret;
6259
6260 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6261 if (ret == NULL) {
6262 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6263 return(NULL);
6264 }
6265 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6266
6267 /* Allocate the value stack */
6268 ret->valueTab = (xmlXPathObjectPtr *)
6269 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6270 if (ret->valueTab == NULL) {
6271 xmlFree(ret);
6272 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6273 return(NULL);
6274 }
6275 ret->valueNr = 0;
6276 ret->valueMax = 10;
6277 ret->value = NULL;
6278 ret->valueFrame = 0;
6279
6280 ret->context = ctxt;
6281 ret->comp = comp;
6282
6283 return(ret);
6284 }
6285
6286 /**
6287 * xmlXPathFreeParserContext:
6288 * @ctxt: the context to free
6289 *
6290 * Free up an xmlXPathParserContext
6291 */
6292 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6293 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6294 int i;
6295
6296 if (ctxt->valueTab != NULL) {
6297 for (i = 0; i < ctxt->valueNr; i++) {
6298 if (ctxt->context)
6299 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6300 else
6301 xmlXPathFreeObject(ctxt->valueTab[i]);
6302 }
6303 xmlFree(ctxt->valueTab);
6304 }
6305 if (ctxt->comp != NULL) {
6306 #ifdef XPATH_STREAMING
6307 if (ctxt->comp->stream != NULL) {
6308 xmlFreePatternList(ctxt->comp->stream);
6309 ctxt->comp->stream = NULL;
6310 }
6311 #endif
6312 xmlXPathFreeCompExpr(ctxt->comp);
6313 }
6314 xmlFree(ctxt);
6315 }
6316
6317 /************************************************************************
6318 * *
6319 * The implicit core function library *
6320 * *
6321 ************************************************************************/
6322
6323 /**
6324 * xmlXPathNodeValHash:
6325 * @node: a node pointer
6326 *
6327 * Function computing the beginning of the string value of the node,
6328 * used to speed up comparisons
6329 *
6330 * Returns an int usable as a hash
6331 */
6332 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6333 xmlXPathNodeValHash(xmlNodePtr node) {
6334 int len = 2;
6335 const xmlChar * string = NULL;
6336 xmlNodePtr tmp = NULL;
6337 unsigned int ret = 0;
6338
6339 if (node == NULL)
6340 return(0);
6341
6342 if (node->type == XML_DOCUMENT_NODE) {
6343 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6344 if (tmp == NULL)
6345 node = node->children;
6346 else
6347 node = tmp;
6348
6349 if (node == NULL)
6350 return(0);
6351 }
6352
6353 switch (node->type) {
6354 case XML_COMMENT_NODE:
6355 case XML_PI_NODE:
6356 case XML_CDATA_SECTION_NODE:
6357 case XML_TEXT_NODE:
6358 string = node->content;
6359 if (string == NULL)
6360 return(0);
6361 if (string[0] == 0)
6362 return(0);
6363 return(((unsigned int) string[0]) +
6364 (((unsigned int) string[1]) << 8));
6365 case XML_NAMESPACE_DECL:
6366 string = ((xmlNsPtr)node)->href;
6367 if (string == NULL)
6368 return(0);
6369 if (string[0] == 0)
6370 return(0);
6371 return(((unsigned int) string[0]) +
6372 (((unsigned int) string[1]) << 8));
6373 case XML_ATTRIBUTE_NODE:
6374 tmp = ((xmlAttrPtr) node)->children;
6375 break;
6376 case XML_ELEMENT_NODE:
6377 tmp = node->children;
6378 break;
6379 default:
6380 return(0);
6381 }
6382 while (tmp != NULL) {
6383 switch (tmp->type) {
6384 case XML_CDATA_SECTION_NODE:
6385 case XML_TEXT_NODE:
6386 string = tmp->content;
6387 break;
6388 default:
6389 string = NULL;
6390 break;
6391 }
6392 if ((string != NULL) && (string[0] != 0)) {
6393 if (len == 1) {
6394 return(ret + (((unsigned int) string[0]) << 8));
6395 }
6396 if (string[1] == 0) {
6397 len = 1;
6398 ret = (unsigned int) string[0];
6399 } else {
6400 return(((unsigned int) string[0]) +
6401 (((unsigned int) string[1]) << 8));
6402 }
6403 }
6404 /*
6405 * Skip to next node
6406 */
6407 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6408 if (tmp->children->type != XML_ENTITY_DECL) {
6409 tmp = tmp->children;
6410 continue;
6411 }
6412 }
6413 if (tmp == node)
6414 break;
6415
6416 if (tmp->next != NULL) {
6417 tmp = tmp->next;
6418 continue;
6419 }
6420
6421 do {
6422 tmp = tmp->parent;
6423 if (tmp == NULL)
6424 break;
6425 if (tmp == node) {
6426 tmp = NULL;
6427 break;
6428 }
6429 if (tmp->next != NULL) {
6430 tmp = tmp->next;
6431 break;
6432 }
6433 } while (tmp != NULL);
6434 }
6435 return(ret);
6436 }
6437
6438 /**
6439 * xmlXPathStringHash:
6440 * @string: a string
6441 *
6442 * Function computing the beginning of the string value of the node,
6443 * used to speed up comparisons
6444 *
6445 * Returns an int usable as a hash
6446 */
6447 static unsigned int
xmlXPathStringHash(const xmlChar * string)6448 xmlXPathStringHash(const xmlChar * string) {
6449 if (string == NULL)
6450 return((unsigned int) 0);
6451 if (string[0] == 0)
6452 return(0);
6453 return(((unsigned int) string[0]) +
6454 (((unsigned int) string[1]) << 8));
6455 }
6456
6457 /**
6458 * xmlXPathCompareNodeSetFloat:
6459 * @ctxt: the XPath Parser context
6460 * @inf: less than (1) or greater than (0)
6461 * @strict: is the comparison strict
6462 * @arg: the node set
6463 * @f: the value
6464 *
6465 * Implement the compare operation between a nodeset and a number
6466 * @ns < @val (1, 1, ...
6467 * @ns <= @val (1, 0, ...
6468 * @ns > @val (0, 1, ...
6469 * @ns >= @val (0, 0, ...
6470 *
6471 * If one object to be compared is a node-set and the other is a number,
6472 * then the comparison will be true if and only if there is a node in the
6473 * node-set such that the result of performing the comparison on the number
6474 * to be compared and on the result of converting the string-value of that
6475 * node to a number using the number function is true.
6476 *
6477 * Returns 0 or 1 depending on the results of the test.
6478 */
6479 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6480 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6481 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6482 int i, ret = 0;
6483 xmlNodeSetPtr ns;
6484 xmlChar *str2;
6485
6486 if ((f == NULL) || (arg == NULL) ||
6487 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6488 xmlXPathReleaseObject(ctxt->context, arg);
6489 xmlXPathReleaseObject(ctxt->context, f);
6490 return(0);
6491 }
6492 ns = arg->nodesetval;
6493 if (ns != NULL) {
6494 for (i = 0;i < ns->nodeNr;i++) {
6495 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6496 if (str2 != NULL) {
6497 valuePush(ctxt,
6498 xmlXPathCacheNewString(ctxt->context, str2));
6499 xmlFree(str2);
6500 xmlXPathNumberFunction(ctxt, 1);
6501 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6502 ret = xmlXPathCompareValues(ctxt, inf, strict);
6503 if (ret)
6504 break;
6505 }
6506 }
6507 }
6508 xmlXPathReleaseObject(ctxt->context, arg);
6509 xmlXPathReleaseObject(ctxt->context, f);
6510 return(ret);
6511 }
6512
6513 /**
6514 * xmlXPathCompareNodeSetString:
6515 * @ctxt: the XPath Parser context
6516 * @inf: less than (1) or greater than (0)
6517 * @strict: is the comparison strict
6518 * @arg: the node set
6519 * @s: the value
6520 *
6521 * Implement the compare operation between a nodeset and a string
6522 * @ns < @val (1, 1, ...
6523 * @ns <= @val (1, 0, ...
6524 * @ns > @val (0, 1, ...
6525 * @ns >= @val (0, 0, ...
6526 *
6527 * If one object to be compared is a node-set and the other is a string,
6528 * then the comparison will be true if and only if there is a node in
6529 * the node-set such that the result of performing the comparison on the
6530 * string-value of the node and the other string is true.
6531 *
6532 * Returns 0 or 1 depending on the results of the test.
6533 */
6534 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6535 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6536 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6537 int i, ret = 0;
6538 xmlNodeSetPtr ns;
6539 xmlChar *str2;
6540
6541 if ((s == NULL) || (arg == NULL) ||
6542 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6543 xmlXPathReleaseObject(ctxt->context, arg);
6544 xmlXPathReleaseObject(ctxt->context, s);
6545 return(0);
6546 }
6547 ns = arg->nodesetval;
6548 if (ns != NULL) {
6549 for (i = 0;i < ns->nodeNr;i++) {
6550 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6551 if (str2 != NULL) {
6552 valuePush(ctxt,
6553 xmlXPathCacheNewString(ctxt->context, str2));
6554 xmlFree(str2);
6555 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6556 ret = xmlXPathCompareValues(ctxt, inf, strict);
6557 if (ret)
6558 break;
6559 }
6560 }
6561 }
6562 xmlXPathReleaseObject(ctxt->context, arg);
6563 xmlXPathReleaseObject(ctxt->context, s);
6564 return(ret);
6565 }
6566
6567 /**
6568 * xmlXPathCompareNodeSets:
6569 * @inf: less than (1) or greater than (0)
6570 * @strict: is the comparison strict
6571 * @arg1: the first node set object
6572 * @arg2: the second node set object
6573 *
6574 * Implement the compare operation on nodesets:
6575 *
6576 * If both objects to be compared are node-sets, then the comparison
6577 * will be true if and only if there is a node in the first node-set
6578 * and a node in the second node-set such that the result of performing
6579 * the comparison on the string-values of the two nodes is true.
6580 * ....
6581 * When neither object to be compared is a node-set and the operator
6582 * is <=, <, >= or >, then the objects are compared by converting both
6583 * objects to numbers and comparing the numbers according to IEEE 754.
6584 * ....
6585 * The number function converts its argument to a number as follows:
6586 * - a string that consists of optional whitespace followed by an
6587 * optional minus sign followed by a Number followed by whitespace
6588 * is converted to the IEEE 754 number that is nearest (according
6589 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6590 * represented by the string; any other string is converted to NaN
6591 *
6592 * Conclusion all nodes need to be converted first to their string value
6593 * and then the comparison must be done when possible
6594 */
6595 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6596 xmlXPathCompareNodeSets(int inf, int strict,
6597 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6598 int i, j, init = 0;
6599 double val1;
6600 double *values2;
6601 int ret = 0;
6602 xmlNodeSetPtr ns1;
6603 xmlNodeSetPtr ns2;
6604
6605 if ((arg1 == NULL) ||
6606 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6607 xmlXPathFreeObject(arg2);
6608 return(0);
6609 }
6610 if ((arg2 == NULL) ||
6611 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6612 xmlXPathFreeObject(arg1);
6613 xmlXPathFreeObject(arg2);
6614 return(0);
6615 }
6616
6617 ns1 = arg1->nodesetval;
6618 ns2 = arg2->nodesetval;
6619
6620 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6621 xmlXPathFreeObject(arg1);
6622 xmlXPathFreeObject(arg2);
6623 return(0);
6624 }
6625 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6626 xmlXPathFreeObject(arg1);
6627 xmlXPathFreeObject(arg2);
6628 return(0);
6629 }
6630
6631 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6632 if (values2 == NULL) {
6633 /* TODO: Propagate memory error. */
6634 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6635 xmlXPathFreeObject(arg1);
6636 xmlXPathFreeObject(arg2);
6637 return(0);
6638 }
6639 for (i = 0;i < ns1->nodeNr;i++) {
6640 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6641 if (xmlXPathIsNaN(val1))
6642 continue;
6643 for (j = 0;j < ns2->nodeNr;j++) {
6644 if (init == 0) {
6645 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6646 }
6647 if (xmlXPathIsNaN(values2[j]))
6648 continue;
6649 if (inf && strict)
6650 ret = (val1 < values2[j]);
6651 else if (inf && !strict)
6652 ret = (val1 <= values2[j]);
6653 else if (!inf && strict)
6654 ret = (val1 > values2[j]);
6655 else if (!inf && !strict)
6656 ret = (val1 >= values2[j]);
6657 if (ret)
6658 break;
6659 }
6660 if (ret)
6661 break;
6662 init = 1;
6663 }
6664 xmlFree(values2);
6665 xmlXPathFreeObject(arg1);
6666 xmlXPathFreeObject(arg2);
6667 return(ret);
6668 }
6669
6670 /**
6671 * xmlXPathCompareNodeSetValue:
6672 * @ctxt: the XPath Parser context
6673 * @inf: less than (1) or greater than (0)
6674 * @strict: is the comparison strict
6675 * @arg: the node set
6676 * @val: the value
6677 *
6678 * Implement the compare operation between a nodeset and a value
6679 * @ns < @val (1, 1, ...
6680 * @ns <= @val (1, 0, ...
6681 * @ns > @val (0, 1, ...
6682 * @ns >= @val (0, 0, ...
6683 *
6684 * If one object to be compared is a node-set and the other is a boolean,
6685 * then the comparison will be true if and only if the result of performing
6686 * the comparison on the boolean and on the result of converting
6687 * the node-set to a boolean using the boolean function is true.
6688 *
6689 * Returns 0 or 1 depending on the results of the test.
6690 */
6691 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6692 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6693 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6694 if ((val == NULL) || (arg == NULL) ||
6695 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6696 return(0);
6697
6698 switch(val->type) {
6699 case XPATH_NUMBER:
6700 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6701 case XPATH_NODESET:
6702 case XPATH_XSLT_TREE:
6703 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6704 case XPATH_STRING:
6705 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6706 case XPATH_BOOLEAN:
6707 valuePush(ctxt, arg);
6708 xmlXPathBooleanFunction(ctxt, 1);
6709 valuePush(ctxt, val);
6710 return(xmlXPathCompareValues(ctxt, inf, strict));
6711 default:
6712 xmlGenericError(xmlGenericErrorContext,
6713 "xmlXPathCompareNodeSetValue: Can't compare node set "
6714 "and object of type %d\n",
6715 val->type);
6716 xmlXPathReleaseObject(ctxt->context, arg);
6717 xmlXPathReleaseObject(ctxt->context, val);
6718 XP_ERROR0(XPATH_INVALID_TYPE);
6719 }
6720 return(0);
6721 }
6722
6723 /**
6724 * xmlXPathEqualNodeSetString:
6725 * @arg: the nodeset object argument
6726 * @str: the string to compare to.
6727 * @neq: flag to show whether for '=' (0) or '!=' (1)
6728 *
6729 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6730 * If one object to be compared is a node-set and the other is a string,
6731 * then the comparison will be true if and only if there is a node in
6732 * the node-set such that the result of performing the comparison on the
6733 * string-value of the node and the other string is true.
6734 *
6735 * Returns 0 or 1 depending on the results of the test.
6736 */
6737 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6738 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6739 {
6740 int i;
6741 xmlNodeSetPtr ns;
6742 xmlChar *str2;
6743 unsigned int hash;
6744
6745 if ((str == NULL) || (arg == NULL) ||
6746 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6747 return (0);
6748 ns = arg->nodesetval;
6749 /*
6750 * A NULL nodeset compared with a string is always false
6751 * (since there is no node equal, and no node not equal)
6752 */
6753 if ((ns == NULL) || (ns->nodeNr <= 0) )
6754 return (0);
6755 hash = xmlXPathStringHash(str);
6756 for (i = 0; i < ns->nodeNr; i++) {
6757 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6758 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6759 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6760 xmlFree(str2);
6761 if (neq)
6762 continue;
6763 return (1);
6764 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6765 if (neq)
6766 continue;
6767 return (1);
6768 } else if (neq) {
6769 if (str2 != NULL)
6770 xmlFree(str2);
6771 return (1);
6772 }
6773 if (str2 != NULL)
6774 xmlFree(str2);
6775 } else if (neq)
6776 return (1);
6777 }
6778 return (0);
6779 }
6780
6781 /**
6782 * xmlXPathEqualNodeSetFloat:
6783 * @arg: the nodeset object argument
6784 * @f: the float to compare to
6785 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6786 *
6787 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6788 * If one object to be compared is a node-set and the other is a number,
6789 * then the comparison will be true if and only if there is a node in
6790 * the node-set such that the result of performing the comparison on the
6791 * number to be compared and on the result of converting the string-value
6792 * of that node to a number using the number function is true.
6793 *
6794 * Returns 0 or 1 depending on the results of the test.
6795 */
6796 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6797 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6798 xmlXPathObjectPtr arg, double f, int neq) {
6799 int i, ret=0;
6800 xmlNodeSetPtr ns;
6801 xmlChar *str2;
6802 xmlXPathObjectPtr val;
6803 double v;
6804
6805 if ((arg == NULL) ||
6806 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6807 return(0);
6808
6809 ns = arg->nodesetval;
6810 if (ns != NULL) {
6811 for (i=0;i<ns->nodeNr;i++) {
6812 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6813 if (str2 != NULL) {
6814 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6815 xmlFree(str2);
6816 xmlXPathNumberFunction(ctxt, 1);
6817 val = valuePop(ctxt);
6818 v = val->floatval;
6819 xmlXPathReleaseObject(ctxt->context, val);
6820 if (!xmlXPathIsNaN(v)) {
6821 if ((!neq) && (v==f)) {
6822 ret = 1;
6823 break;
6824 } else if ((neq) && (v!=f)) {
6825 ret = 1;
6826 break;
6827 }
6828 } else { /* NaN is unequal to any value */
6829 if (neq)
6830 ret = 1;
6831 }
6832 }
6833 }
6834 }
6835
6836 return(ret);
6837 }
6838
6839
6840 /**
6841 * xmlXPathEqualNodeSets:
6842 * @arg1: first nodeset object argument
6843 * @arg2: second nodeset object argument
6844 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6845 *
6846 * Implement the equal / not equal operation on XPath nodesets:
6847 * @arg1 == @arg2 or @arg1 != @arg2
6848 * If both objects to be compared are node-sets, then the comparison
6849 * will be true if and only if there is a node in the first node-set and
6850 * a node in the second node-set such that the result of performing the
6851 * comparison on the string-values of the two nodes is true.
6852 *
6853 * (needless to say, this is a costly operation)
6854 *
6855 * Returns 0 or 1 depending on the results of the test.
6856 */
6857 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6858 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6859 int i, j;
6860 unsigned int *hashs1;
6861 unsigned int *hashs2;
6862 xmlChar **values1;
6863 xmlChar **values2;
6864 int ret = 0;
6865 xmlNodeSetPtr ns1;
6866 xmlNodeSetPtr ns2;
6867
6868 if ((arg1 == NULL) ||
6869 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6870 return(0);
6871 if ((arg2 == NULL) ||
6872 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6873 return(0);
6874
6875 ns1 = arg1->nodesetval;
6876 ns2 = arg2->nodesetval;
6877
6878 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6879 return(0);
6880 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6881 return(0);
6882
6883 /*
6884 * for equal, check if there is a node pertaining to both sets
6885 */
6886 if (neq == 0)
6887 for (i = 0;i < ns1->nodeNr;i++)
6888 for (j = 0;j < ns2->nodeNr;j++)
6889 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6890 return(1);
6891
6892 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6893 if (values1 == NULL) {
6894 /* TODO: Propagate memory error. */
6895 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896 return(0);
6897 }
6898 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6899 if (hashs1 == NULL) {
6900 /* TODO: Propagate memory error. */
6901 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6902 xmlFree(values1);
6903 return(0);
6904 }
6905 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6906 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6907 if (values2 == NULL) {
6908 /* TODO: Propagate memory error. */
6909 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910 xmlFree(hashs1);
6911 xmlFree(values1);
6912 return(0);
6913 }
6914 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6915 if (hashs2 == NULL) {
6916 /* TODO: Propagate memory error. */
6917 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918 xmlFree(hashs1);
6919 xmlFree(values1);
6920 xmlFree(values2);
6921 return(0);
6922 }
6923 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6924 for (i = 0;i < ns1->nodeNr;i++) {
6925 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6926 for (j = 0;j < ns2->nodeNr;j++) {
6927 if (i == 0)
6928 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6929 if (hashs1[i] != hashs2[j]) {
6930 if (neq) {
6931 ret = 1;
6932 break;
6933 }
6934 }
6935 else {
6936 if (values1[i] == NULL)
6937 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6938 if (values2[j] == NULL)
6939 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6940 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6941 if (ret)
6942 break;
6943 }
6944 }
6945 if (ret)
6946 break;
6947 }
6948 for (i = 0;i < ns1->nodeNr;i++)
6949 if (values1[i] != NULL)
6950 xmlFree(values1[i]);
6951 for (j = 0;j < ns2->nodeNr;j++)
6952 if (values2[j] != NULL)
6953 xmlFree(values2[j]);
6954 xmlFree(values1);
6955 xmlFree(values2);
6956 xmlFree(hashs1);
6957 xmlFree(hashs2);
6958 return(ret);
6959 }
6960
6961 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6962 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6963 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6964 int ret = 0;
6965 /*
6966 *At this point we are assured neither arg1 nor arg2
6967 *is a nodeset, so we can just pick the appropriate routine.
6968 */
6969 switch (arg1->type) {
6970 case XPATH_UNDEFINED:
6971 #ifdef DEBUG_EXPR
6972 xmlGenericError(xmlGenericErrorContext,
6973 "Equal: undefined\n");
6974 #endif
6975 break;
6976 case XPATH_BOOLEAN:
6977 switch (arg2->type) {
6978 case XPATH_UNDEFINED:
6979 #ifdef DEBUG_EXPR
6980 xmlGenericError(xmlGenericErrorContext,
6981 "Equal: undefined\n");
6982 #endif
6983 break;
6984 case XPATH_BOOLEAN:
6985 #ifdef DEBUG_EXPR
6986 xmlGenericError(xmlGenericErrorContext,
6987 "Equal: %d boolean %d \n",
6988 arg1->boolval, arg2->boolval);
6989 #endif
6990 ret = (arg1->boolval == arg2->boolval);
6991 break;
6992 case XPATH_NUMBER:
6993 ret = (arg1->boolval ==
6994 xmlXPathCastNumberToBoolean(arg2->floatval));
6995 break;
6996 case XPATH_STRING:
6997 if ((arg2->stringval == NULL) ||
6998 (arg2->stringval[0] == 0)) ret = 0;
6999 else
7000 ret = 1;
7001 ret = (arg1->boolval == ret);
7002 break;
7003 case XPATH_USERS:
7004 #ifdef LIBXML_XPTR_LOCS_ENABLED
7005 case XPATH_POINT:
7006 case XPATH_RANGE:
7007 case XPATH_LOCATIONSET:
7008 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7009 TODO
7010 break;
7011 case XPATH_NODESET:
7012 case XPATH_XSLT_TREE:
7013 break;
7014 }
7015 break;
7016 case XPATH_NUMBER:
7017 switch (arg2->type) {
7018 case XPATH_UNDEFINED:
7019 #ifdef DEBUG_EXPR
7020 xmlGenericError(xmlGenericErrorContext,
7021 "Equal: undefined\n");
7022 #endif
7023 break;
7024 case XPATH_BOOLEAN:
7025 ret = (arg2->boolval==
7026 xmlXPathCastNumberToBoolean(arg1->floatval));
7027 break;
7028 case XPATH_STRING:
7029 valuePush(ctxt, arg2);
7030 xmlXPathNumberFunction(ctxt, 1);
7031 arg2 = valuePop(ctxt);
7032 /* Falls through. */
7033 case XPATH_NUMBER:
7034 /* Hand check NaN and Infinity equalities */
7035 if (xmlXPathIsNaN(arg1->floatval) ||
7036 xmlXPathIsNaN(arg2->floatval)) {
7037 ret = 0;
7038 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7039 if (xmlXPathIsInf(arg2->floatval) == 1)
7040 ret = 1;
7041 else
7042 ret = 0;
7043 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7044 if (xmlXPathIsInf(arg2->floatval) == -1)
7045 ret = 1;
7046 else
7047 ret = 0;
7048 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7049 if (xmlXPathIsInf(arg1->floatval) == 1)
7050 ret = 1;
7051 else
7052 ret = 0;
7053 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7054 if (xmlXPathIsInf(arg1->floatval) == -1)
7055 ret = 1;
7056 else
7057 ret = 0;
7058 } else {
7059 ret = (arg1->floatval == arg2->floatval);
7060 }
7061 break;
7062 case XPATH_USERS:
7063 #ifdef LIBXML_XPTR_LOCS_ENABLED
7064 case XPATH_POINT:
7065 case XPATH_RANGE:
7066 case XPATH_LOCATIONSET:
7067 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7068 TODO
7069 break;
7070 case XPATH_NODESET:
7071 case XPATH_XSLT_TREE:
7072 break;
7073 }
7074 break;
7075 case XPATH_STRING:
7076 switch (arg2->type) {
7077 case XPATH_UNDEFINED:
7078 #ifdef DEBUG_EXPR
7079 xmlGenericError(xmlGenericErrorContext,
7080 "Equal: undefined\n");
7081 #endif
7082 break;
7083 case XPATH_BOOLEAN:
7084 if ((arg1->stringval == NULL) ||
7085 (arg1->stringval[0] == 0)) ret = 0;
7086 else
7087 ret = 1;
7088 ret = (arg2->boolval == ret);
7089 break;
7090 case XPATH_STRING:
7091 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7092 break;
7093 case XPATH_NUMBER:
7094 valuePush(ctxt, arg1);
7095 xmlXPathNumberFunction(ctxt, 1);
7096 arg1 = valuePop(ctxt);
7097 /* Hand check NaN and Infinity equalities */
7098 if (xmlXPathIsNaN(arg1->floatval) ||
7099 xmlXPathIsNaN(arg2->floatval)) {
7100 ret = 0;
7101 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7102 if (xmlXPathIsInf(arg2->floatval) == 1)
7103 ret = 1;
7104 else
7105 ret = 0;
7106 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7107 if (xmlXPathIsInf(arg2->floatval) == -1)
7108 ret = 1;
7109 else
7110 ret = 0;
7111 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7112 if (xmlXPathIsInf(arg1->floatval) == 1)
7113 ret = 1;
7114 else
7115 ret = 0;
7116 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7117 if (xmlXPathIsInf(arg1->floatval) == -1)
7118 ret = 1;
7119 else
7120 ret = 0;
7121 } else {
7122 ret = (arg1->floatval == arg2->floatval);
7123 }
7124 break;
7125 case XPATH_USERS:
7126 #ifdef LIBXML_XPTR_LOCS_ENABLED
7127 case XPATH_POINT:
7128 case XPATH_RANGE:
7129 case XPATH_LOCATIONSET:
7130 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7131 TODO
7132 break;
7133 case XPATH_NODESET:
7134 case XPATH_XSLT_TREE:
7135 break;
7136 }
7137 break;
7138 case XPATH_USERS:
7139 #ifdef LIBXML_XPTR_LOCS_ENABLED
7140 case XPATH_POINT:
7141 case XPATH_RANGE:
7142 case XPATH_LOCATIONSET:
7143 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7144 TODO
7145 break;
7146 case XPATH_NODESET:
7147 case XPATH_XSLT_TREE:
7148 break;
7149 }
7150 xmlXPathReleaseObject(ctxt->context, arg1);
7151 xmlXPathReleaseObject(ctxt->context, arg2);
7152 return(ret);
7153 }
7154
7155 /**
7156 * xmlXPathEqualValues:
7157 * @ctxt: the XPath Parser context
7158 *
7159 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7160 *
7161 * Returns 0 or 1 depending on the results of the test.
7162 */
7163 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7164 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7165 xmlXPathObjectPtr arg1, arg2, argtmp;
7166 int ret = 0;
7167
7168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7169 arg2 = valuePop(ctxt);
7170 arg1 = valuePop(ctxt);
7171 if ((arg1 == NULL) || (arg2 == NULL)) {
7172 if (arg1 != NULL)
7173 xmlXPathReleaseObject(ctxt->context, arg1);
7174 else
7175 xmlXPathReleaseObject(ctxt->context, arg2);
7176 XP_ERROR0(XPATH_INVALID_OPERAND);
7177 }
7178
7179 if (arg1 == arg2) {
7180 #ifdef DEBUG_EXPR
7181 xmlGenericError(xmlGenericErrorContext,
7182 "Equal: by pointer\n");
7183 #endif
7184 xmlXPathFreeObject(arg1);
7185 return(1);
7186 }
7187
7188 /*
7189 *If either argument is a nodeset, it's a 'special case'
7190 */
7191 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7192 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7193 /*
7194 *Hack it to assure arg1 is the nodeset
7195 */
7196 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7197 argtmp = arg2;
7198 arg2 = arg1;
7199 arg1 = argtmp;
7200 }
7201 switch (arg2->type) {
7202 case XPATH_UNDEFINED:
7203 #ifdef DEBUG_EXPR
7204 xmlGenericError(xmlGenericErrorContext,
7205 "Equal: undefined\n");
7206 #endif
7207 break;
7208 case XPATH_NODESET:
7209 case XPATH_XSLT_TREE:
7210 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7211 break;
7212 case XPATH_BOOLEAN:
7213 if ((arg1->nodesetval == NULL) ||
7214 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7215 else
7216 ret = 1;
7217 ret = (ret == arg2->boolval);
7218 break;
7219 case XPATH_NUMBER:
7220 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7221 break;
7222 case XPATH_STRING:
7223 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7224 break;
7225 case XPATH_USERS:
7226 #ifdef LIBXML_XPTR_LOCS_ENABLED
7227 case XPATH_POINT:
7228 case XPATH_RANGE:
7229 case XPATH_LOCATIONSET:
7230 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7231 TODO
7232 break;
7233 }
7234 xmlXPathReleaseObject(ctxt->context, arg1);
7235 xmlXPathReleaseObject(ctxt->context, arg2);
7236 return(ret);
7237 }
7238
7239 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7240 }
7241
7242 /**
7243 * xmlXPathNotEqualValues:
7244 * @ctxt: the XPath Parser context
7245 *
7246 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7247 *
7248 * Returns 0 or 1 depending on the results of the test.
7249 */
7250 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7251 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7252 xmlXPathObjectPtr arg1, arg2, argtmp;
7253 int ret = 0;
7254
7255 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7256 arg2 = valuePop(ctxt);
7257 arg1 = valuePop(ctxt);
7258 if ((arg1 == NULL) || (arg2 == NULL)) {
7259 if (arg1 != NULL)
7260 xmlXPathReleaseObject(ctxt->context, arg1);
7261 else
7262 xmlXPathReleaseObject(ctxt->context, arg2);
7263 XP_ERROR0(XPATH_INVALID_OPERAND);
7264 }
7265
7266 if (arg1 == arg2) {
7267 #ifdef DEBUG_EXPR
7268 xmlGenericError(xmlGenericErrorContext,
7269 "NotEqual: by pointer\n");
7270 #endif
7271 xmlXPathReleaseObject(ctxt->context, arg1);
7272 return(0);
7273 }
7274
7275 /*
7276 *If either argument is a nodeset, it's a 'special case'
7277 */
7278 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7279 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7280 /*
7281 *Hack it to assure arg1 is the nodeset
7282 */
7283 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7284 argtmp = arg2;
7285 arg2 = arg1;
7286 arg1 = argtmp;
7287 }
7288 switch (arg2->type) {
7289 case XPATH_UNDEFINED:
7290 #ifdef DEBUG_EXPR
7291 xmlGenericError(xmlGenericErrorContext,
7292 "NotEqual: undefined\n");
7293 #endif
7294 break;
7295 case XPATH_NODESET:
7296 case XPATH_XSLT_TREE:
7297 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7298 break;
7299 case XPATH_BOOLEAN:
7300 if ((arg1->nodesetval == NULL) ||
7301 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7302 else
7303 ret = 1;
7304 ret = (ret != arg2->boolval);
7305 break;
7306 case XPATH_NUMBER:
7307 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7308 break;
7309 case XPATH_STRING:
7310 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7311 break;
7312 case XPATH_USERS:
7313 #ifdef LIBXML_XPTR_LOCS_ENABLED
7314 case XPATH_POINT:
7315 case XPATH_RANGE:
7316 case XPATH_LOCATIONSET:
7317 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7318 TODO
7319 break;
7320 }
7321 xmlXPathReleaseObject(ctxt->context, arg1);
7322 xmlXPathReleaseObject(ctxt->context, arg2);
7323 return(ret);
7324 }
7325
7326 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7327 }
7328
7329 /**
7330 * xmlXPathCompareValues:
7331 * @ctxt: the XPath Parser context
7332 * @inf: less than (1) or greater than (0)
7333 * @strict: is the comparison strict
7334 *
7335 * Implement the compare operation on XPath objects:
7336 * @arg1 < @arg2 (1, 1, ...
7337 * @arg1 <= @arg2 (1, 0, ...
7338 * @arg1 > @arg2 (0, 1, ...
7339 * @arg1 >= @arg2 (0, 0, ...
7340 *
7341 * When neither object to be compared is a node-set and the operator is
7342 * <=, <, >=, >, then the objects are compared by converted both objects
7343 * to numbers and comparing the numbers according to IEEE 754. The <
7344 * comparison will be true if and only if the first number is less than the
7345 * second number. The <= comparison will be true if and only if the first
7346 * number is less than or equal to the second number. The > comparison
7347 * will be true if and only if the first number is greater than the second
7348 * number. The >= comparison will be true if and only if the first number
7349 * is greater than or equal to the second number.
7350 *
7351 * Returns 1 if the comparison succeeded, 0 if it failed
7352 */
7353 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7354 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7355 int ret = 0, arg1i = 0, arg2i = 0;
7356 xmlXPathObjectPtr arg1, arg2;
7357
7358 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7359 arg2 = valuePop(ctxt);
7360 arg1 = valuePop(ctxt);
7361 if ((arg1 == NULL) || (arg2 == NULL)) {
7362 if (arg1 != NULL)
7363 xmlXPathReleaseObject(ctxt->context, arg1);
7364 else
7365 xmlXPathReleaseObject(ctxt->context, arg2);
7366 XP_ERROR0(XPATH_INVALID_OPERAND);
7367 }
7368
7369 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7370 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7371 /*
7372 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7373 * are not freed from within this routine; they will be freed from the
7374 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7375 */
7376 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7377 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7378 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7379 } else {
7380 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7381 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7382 arg1, arg2);
7383 } else {
7384 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7385 arg2, arg1);
7386 }
7387 }
7388 return(ret);
7389 }
7390
7391 if (arg1->type != XPATH_NUMBER) {
7392 valuePush(ctxt, arg1);
7393 xmlXPathNumberFunction(ctxt, 1);
7394 arg1 = valuePop(ctxt);
7395 }
7396 if (arg1->type != XPATH_NUMBER) {
7397 xmlXPathFreeObject(arg1);
7398 xmlXPathFreeObject(arg2);
7399 XP_ERROR0(XPATH_INVALID_OPERAND);
7400 }
7401 if (arg2->type != XPATH_NUMBER) {
7402 valuePush(ctxt, arg2);
7403 xmlXPathNumberFunction(ctxt, 1);
7404 arg2 = valuePop(ctxt);
7405 }
7406 if (arg2->type != XPATH_NUMBER) {
7407 xmlXPathReleaseObject(ctxt->context, arg1);
7408 xmlXPathReleaseObject(ctxt->context, arg2);
7409 XP_ERROR0(XPATH_INVALID_OPERAND);
7410 }
7411 /*
7412 * Add tests for infinity and nan
7413 * => feedback on 3.4 for Inf and NaN
7414 */
7415 /* Hand check NaN and Infinity comparisons */
7416 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7417 ret=0;
7418 } else {
7419 arg1i=xmlXPathIsInf(arg1->floatval);
7420 arg2i=xmlXPathIsInf(arg2->floatval);
7421 if (inf && strict) {
7422 if ((arg1i == -1 && arg2i != -1) ||
7423 (arg2i == 1 && arg1i != 1)) {
7424 ret = 1;
7425 } else if (arg1i == 0 && arg2i == 0) {
7426 ret = (arg1->floatval < arg2->floatval);
7427 } else {
7428 ret = 0;
7429 }
7430 }
7431 else if (inf && !strict) {
7432 if (arg1i == -1 || arg2i == 1) {
7433 ret = 1;
7434 } else if (arg1i == 0 && arg2i == 0) {
7435 ret = (arg1->floatval <= arg2->floatval);
7436 } else {
7437 ret = 0;
7438 }
7439 }
7440 else if (!inf && strict) {
7441 if ((arg1i == 1 && arg2i != 1) ||
7442 (arg2i == -1 && arg1i != -1)) {
7443 ret = 1;
7444 } else if (arg1i == 0 && arg2i == 0) {
7445 ret = (arg1->floatval > arg2->floatval);
7446 } else {
7447 ret = 0;
7448 }
7449 }
7450 else if (!inf && !strict) {
7451 if (arg1i == 1 || arg2i == -1) {
7452 ret = 1;
7453 } else if (arg1i == 0 && arg2i == 0) {
7454 ret = (arg1->floatval >= arg2->floatval);
7455 } else {
7456 ret = 0;
7457 }
7458 }
7459 }
7460 xmlXPathReleaseObject(ctxt->context, arg1);
7461 xmlXPathReleaseObject(ctxt->context, arg2);
7462 return(ret);
7463 }
7464
7465 /**
7466 * xmlXPathValueFlipSign:
7467 * @ctxt: the XPath Parser context
7468 *
7469 * Implement the unary - operation on an XPath object
7470 * The numeric operators convert their operands to numbers as if
7471 * by calling the number function.
7472 */
7473 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7474 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7475 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7476 CAST_TO_NUMBER;
7477 CHECK_TYPE(XPATH_NUMBER);
7478 ctxt->value->floatval = -ctxt->value->floatval;
7479 }
7480
7481 /**
7482 * xmlXPathAddValues:
7483 * @ctxt: the XPath Parser context
7484 *
7485 * Implement the add operation on XPath objects:
7486 * The numeric operators convert their operands to numbers as if
7487 * by calling the number function.
7488 */
7489 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7490 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7491 xmlXPathObjectPtr arg;
7492 double val;
7493
7494 arg = valuePop(ctxt);
7495 if (arg == NULL)
7496 XP_ERROR(XPATH_INVALID_OPERAND);
7497 val = xmlXPathCastToNumber(arg);
7498 xmlXPathReleaseObject(ctxt->context, arg);
7499 CAST_TO_NUMBER;
7500 CHECK_TYPE(XPATH_NUMBER);
7501 ctxt->value->floatval += val;
7502 }
7503
7504 /**
7505 * xmlXPathSubValues:
7506 * @ctxt: the XPath Parser context
7507 *
7508 * Implement the subtraction operation on XPath objects:
7509 * The numeric operators convert their operands to numbers as if
7510 * by calling the number function.
7511 */
7512 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7513 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7514 xmlXPathObjectPtr arg;
7515 double val;
7516
7517 arg = valuePop(ctxt);
7518 if (arg == NULL)
7519 XP_ERROR(XPATH_INVALID_OPERAND);
7520 val = xmlXPathCastToNumber(arg);
7521 xmlXPathReleaseObject(ctxt->context, arg);
7522 CAST_TO_NUMBER;
7523 CHECK_TYPE(XPATH_NUMBER);
7524 ctxt->value->floatval -= val;
7525 }
7526
7527 /**
7528 * xmlXPathMultValues:
7529 * @ctxt: the XPath Parser context
7530 *
7531 * Implement the multiply operation on XPath objects:
7532 * The numeric operators convert their operands to numbers as if
7533 * by calling the number function.
7534 */
7535 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7536 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7537 xmlXPathObjectPtr arg;
7538 double val;
7539
7540 arg = valuePop(ctxt);
7541 if (arg == NULL)
7542 XP_ERROR(XPATH_INVALID_OPERAND);
7543 val = xmlXPathCastToNumber(arg);
7544 xmlXPathReleaseObject(ctxt->context, arg);
7545 CAST_TO_NUMBER;
7546 CHECK_TYPE(XPATH_NUMBER);
7547 ctxt->value->floatval *= val;
7548 }
7549
7550 /**
7551 * xmlXPathDivValues:
7552 * @ctxt: the XPath Parser context
7553 *
7554 * Implement the div operation on XPath objects @arg1 / @arg2:
7555 * The numeric operators convert their operands to numbers as if
7556 * by calling the number function.
7557 */
7558 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7559 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7560 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7561 xmlXPathObjectPtr arg;
7562 double val;
7563
7564 arg = valuePop(ctxt);
7565 if (arg == NULL)
7566 XP_ERROR(XPATH_INVALID_OPERAND);
7567 val = xmlXPathCastToNumber(arg);
7568 xmlXPathReleaseObject(ctxt->context, arg);
7569 CAST_TO_NUMBER;
7570 CHECK_TYPE(XPATH_NUMBER);
7571 ctxt->value->floatval /= val;
7572 }
7573
7574 /**
7575 * xmlXPathModValues:
7576 * @ctxt: the XPath Parser context
7577 *
7578 * Implement the mod operation on XPath objects: @arg1 / @arg2
7579 * The numeric operators convert their operands to numbers as if
7580 * by calling the number function.
7581 */
7582 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7583 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7584 xmlXPathObjectPtr arg;
7585 double arg1, arg2;
7586
7587 arg = valuePop(ctxt);
7588 if (arg == NULL)
7589 XP_ERROR(XPATH_INVALID_OPERAND);
7590 arg2 = xmlXPathCastToNumber(arg);
7591 xmlXPathReleaseObject(ctxt->context, arg);
7592 CAST_TO_NUMBER;
7593 CHECK_TYPE(XPATH_NUMBER);
7594 arg1 = ctxt->value->floatval;
7595 if (arg2 == 0)
7596 ctxt->value->floatval = xmlXPathNAN;
7597 else {
7598 ctxt->value->floatval = fmod(arg1, arg2);
7599 }
7600 }
7601
7602 /************************************************************************
7603 * *
7604 * The traversal functions *
7605 * *
7606 ************************************************************************/
7607
7608 /*
7609 * A traversal function enumerates nodes along an axis.
7610 * Initially it must be called with NULL, and it indicates
7611 * termination on the axis by returning NULL.
7612 */
7613 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7614 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7615
7616 /*
7617 * xmlXPathTraversalFunctionExt:
7618 * A traversal function enumerates nodes along an axis.
7619 * Initially it must be called with NULL, and it indicates
7620 * termination on the axis by returning NULL.
7621 * The context node of the traversal is specified via @contextNode.
7622 */
7623 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7624 (xmlNodePtr cur, xmlNodePtr contextNode);
7625
7626 /*
7627 * xmlXPathNodeSetMergeFunction:
7628 * Used for merging node sets in xmlXPathCollectAndTest().
7629 */
7630 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7631 (xmlNodeSetPtr, xmlNodeSetPtr);
7632
7633
7634 /**
7635 * xmlXPathNextSelf:
7636 * @ctxt: the XPath Parser context
7637 * @cur: the current node in the traversal
7638 *
7639 * Traversal function for the "self" direction
7640 * The self axis contains just the context node itself
7641 *
7642 * Returns the next element following that axis
7643 */
7644 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7645 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7646 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7647 if (cur == NULL)
7648 return(ctxt->context->node);
7649 return(NULL);
7650 }
7651
7652 /**
7653 * xmlXPathNextChild:
7654 * @ctxt: the XPath Parser context
7655 * @cur: the current node in the traversal
7656 *
7657 * Traversal function for the "child" direction
7658 * The child axis contains the children of the context node in document order.
7659 *
7660 * Returns the next element following that axis
7661 */
7662 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7663 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7664 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7665 if (cur == NULL) {
7666 if (ctxt->context->node == NULL) return(NULL);
7667 switch (ctxt->context->node->type) {
7668 case XML_ELEMENT_NODE:
7669 case XML_TEXT_NODE:
7670 case XML_CDATA_SECTION_NODE:
7671 case XML_ENTITY_REF_NODE:
7672 case XML_ENTITY_NODE:
7673 case XML_PI_NODE:
7674 case XML_COMMENT_NODE:
7675 case XML_NOTATION_NODE:
7676 case XML_DTD_NODE:
7677 return(ctxt->context->node->children);
7678 case XML_DOCUMENT_NODE:
7679 case XML_DOCUMENT_TYPE_NODE:
7680 case XML_DOCUMENT_FRAG_NODE:
7681 case XML_HTML_DOCUMENT_NODE:
7682 return(((xmlDocPtr) ctxt->context->node)->children);
7683 case XML_ELEMENT_DECL:
7684 case XML_ATTRIBUTE_DECL:
7685 case XML_ENTITY_DECL:
7686 case XML_ATTRIBUTE_NODE:
7687 case XML_NAMESPACE_DECL:
7688 case XML_XINCLUDE_START:
7689 case XML_XINCLUDE_END:
7690 return(NULL);
7691 }
7692 return(NULL);
7693 }
7694 if ((cur->type == XML_DOCUMENT_NODE) ||
7695 (cur->type == XML_HTML_DOCUMENT_NODE))
7696 return(NULL);
7697 return(cur->next);
7698 }
7699
7700 /**
7701 * xmlXPathNextChildElement:
7702 * @ctxt: the XPath Parser context
7703 * @cur: the current node in the traversal
7704 *
7705 * Traversal function for the "child" direction and nodes of type element.
7706 * The child axis contains the children of the context node in document order.
7707 *
7708 * Returns the next element following that axis
7709 */
7710 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7711 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7712 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7713 if (cur == NULL) {
7714 cur = ctxt->context->node;
7715 if (cur == NULL) return(NULL);
7716 /*
7717 * Get the first element child.
7718 */
7719 switch (cur->type) {
7720 case XML_ELEMENT_NODE:
7721 case XML_DOCUMENT_FRAG_NODE:
7722 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7723 case XML_ENTITY_NODE:
7724 cur = cur->children;
7725 if (cur != NULL) {
7726 if (cur->type == XML_ELEMENT_NODE)
7727 return(cur);
7728 do {
7729 cur = cur->next;
7730 } while ((cur != NULL) &&
7731 (cur->type != XML_ELEMENT_NODE));
7732 return(cur);
7733 }
7734 return(NULL);
7735 case XML_DOCUMENT_NODE:
7736 case XML_HTML_DOCUMENT_NODE:
7737 return(xmlDocGetRootElement((xmlDocPtr) cur));
7738 default:
7739 return(NULL);
7740 }
7741 return(NULL);
7742 }
7743 /*
7744 * Get the next sibling element node.
7745 */
7746 switch (cur->type) {
7747 case XML_ELEMENT_NODE:
7748 case XML_TEXT_NODE:
7749 case XML_ENTITY_REF_NODE:
7750 case XML_ENTITY_NODE:
7751 case XML_CDATA_SECTION_NODE:
7752 case XML_PI_NODE:
7753 case XML_COMMENT_NODE:
7754 case XML_XINCLUDE_END:
7755 break;
7756 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7757 default:
7758 return(NULL);
7759 }
7760 if (cur->next != NULL) {
7761 if (cur->next->type == XML_ELEMENT_NODE)
7762 return(cur->next);
7763 cur = cur->next;
7764 do {
7765 cur = cur->next;
7766 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7767 return(cur);
7768 }
7769 return(NULL);
7770 }
7771
7772 #if 0
7773 /**
7774 * xmlXPathNextDescendantOrSelfElemParent:
7775 * @ctxt: the XPath Parser context
7776 * @cur: the current node in the traversal
7777 *
7778 * Traversal function for the "descendant-or-self" axis.
7779 * Additionally it returns only nodes which can be parents of
7780 * element nodes.
7781 *
7782 *
7783 * Returns the next element following that axis
7784 */
7785 static xmlNodePtr
7786 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7787 xmlNodePtr contextNode)
7788 {
7789 if (cur == NULL) {
7790 if (contextNode == NULL)
7791 return(NULL);
7792 switch (contextNode->type) {
7793 case XML_ELEMENT_NODE:
7794 case XML_XINCLUDE_START:
7795 case XML_DOCUMENT_FRAG_NODE:
7796 case XML_DOCUMENT_NODE:
7797 case XML_HTML_DOCUMENT_NODE:
7798 return(contextNode);
7799 default:
7800 return(NULL);
7801 }
7802 return(NULL);
7803 } else {
7804 xmlNodePtr start = cur;
7805
7806 while (cur != NULL) {
7807 switch (cur->type) {
7808 case XML_ELEMENT_NODE:
7809 /* TODO: OK to have XInclude here? */
7810 case XML_XINCLUDE_START:
7811 case XML_DOCUMENT_FRAG_NODE:
7812 if (cur != start)
7813 return(cur);
7814 if (cur->children != NULL) {
7815 cur = cur->children;
7816 continue;
7817 }
7818 break;
7819 /* Not sure if we need those here. */
7820 case XML_DOCUMENT_NODE:
7821 case XML_HTML_DOCUMENT_NODE:
7822 if (cur != start)
7823 return(cur);
7824 return(xmlDocGetRootElement((xmlDocPtr) cur));
7825 default:
7826 break;
7827 }
7828
7829 next_sibling:
7830 if ((cur == NULL) || (cur == contextNode))
7831 return(NULL);
7832 if (cur->next != NULL) {
7833 cur = cur->next;
7834 } else {
7835 cur = cur->parent;
7836 goto next_sibling;
7837 }
7838 }
7839 }
7840 return(NULL);
7841 }
7842 #endif
7843
7844 /**
7845 * xmlXPathNextDescendant:
7846 * @ctxt: the XPath Parser context
7847 * @cur: the current node in the traversal
7848 *
7849 * Traversal function for the "descendant" direction
7850 * the descendant axis contains the descendants of the context node in document
7851 * order; a descendant is a child or a child of a child and so on.
7852 *
7853 * Returns the next element following that axis
7854 */
7855 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7856 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7857 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7858 if (cur == NULL) {
7859 if (ctxt->context->node == NULL)
7860 return(NULL);
7861 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7862 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7863 return(NULL);
7864
7865 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7866 return(ctxt->context->doc->children);
7867 return(ctxt->context->node->children);
7868 }
7869
7870 if (cur->type == XML_NAMESPACE_DECL)
7871 return(NULL);
7872 if (cur->children != NULL) {
7873 /*
7874 * Do not descend on entities declarations
7875 */
7876 if (cur->children->type != XML_ENTITY_DECL) {
7877 cur = cur->children;
7878 /*
7879 * Skip DTDs
7880 */
7881 if (cur->type != XML_DTD_NODE)
7882 return(cur);
7883 }
7884 }
7885
7886 if (cur == ctxt->context->node) return(NULL);
7887
7888 while (cur->next != NULL) {
7889 cur = cur->next;
7890 if ((cur->type != XML_ENTITY_DECL) &&
7891 (cur->type != XML_DTD_NODE))
7892 return(cur);
7893 }
7894
7895 do {
7896 cur = cur->parent;
7897 if (cur == NULL) break;
7898 if (cur == ctxt->context->node) return(NULL);
7899 if (cur->next != NULL) {
7900 cur = cur->next;
7901 return(cur);
7902 }
7903 } while (cur != NULL);
7904 return(cur);
7905 }
7906
7907 /**
7908 * xmlXPathNextDescendantOrSelf:
7909 * @ctxt: the XPath Parser context
7910 * @cur: the current node in the traversal
7911 *
7912 * Traversal function for the "descendant-or-self" direction
7913 * the descendant-or-self axis contains the context node and the descendants
7914 * of the context node in document order; thus the context node is the first
7915 * node on the axis, and the first child of the context node is the second node
7916 * on the axis
7917 *
7918 * Returns the next element following that axis
7919 */
7920 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7921 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923 if (cur == NULL)
7924 return(ctxt->context->node);
7925
7926 if (ctxt->context->node == NULL)
7927 return(NULL);
7928 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7929 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7930 return(NULL);
7931
7932 return(xmlXPathNextDescendant(ctxt, cur));
7933 }
7934
7935 /**
7936 * xmlXPathNextParent:
7937 * @ctxt: the XPath Parser context
7938 * @cur: the current node in the traversal
7939 *
7940 * Traversal function for the "parent" direction
7941 * The parent axis contains the parent of the context node, if there is one.
7942 *
7943 * Returns the next element following that axis
7944 */
7945 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7946 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7947 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7948 /*
7949 * the parent of an attribute or namespace node is the element
7950 * to which the attribute or namespace node is attached
7951 * Namespace handling !!!
7952 */
7953 if (cur == NULL) {
7954 if (ctxt->context->node == NULL) return(NULL);
7955 switch (ctxt->context->node->type) {
7956 case XML_ELEMENT_NODE:
7957 case XML_TEXT_NODE:
7958 case XML_CDATA_SECTION_NODE:
7959 case XML_ENTITY_REF_NODE:
7960 case XML_ENTITY_NODE:
7961 case XML_PI_NODE:
7962 case XML_COMMENT_NODE:
7963 case XML_NOTATION_NODE:
7964 case XML_DTD_NODE:
7965 case XML_ELEMENT_DECL:
7966 case XML_ATTRIBUTE_DECL:
7967 case XML_XINCLUDE_START:
7968 case XML_XINCLUDE_END:
7969 case XML_ENTITY_DECL:
7970 if (ctxt->context->node->parent == NULL)
7971 return((xmlNodePtr) ctxt->context->doc);
7972 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7973 ((ctxt->context->node->parent->name[0] == ' ') ||
7974 (xmlStrEqual(ctxt->context->node->parent->name,
7975 BAD_CAST "fake node libxslt"))))
7976 return(NULL);
7977 return(ctxt->context->node->parent);
7978 case XML_ATTRIBUTE_NODE: {
7979 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7980
7981 return(att->parent);
7982 }
7983 case XML_DOCUMENT_NODE:
7984 case XML_DOCUMENT_TYPE_NODE:
7985 case XML_DOCUMENT_FRAG_NODE:
7986 case XML_HTML_DOCUMENT_NODE:
7987 return(NULL);
7988 case XML_NAMESPACE_DECL: {
7989 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7990
7991 if ((ns->next != NULL) &&
7992 (ns->next->type != XML_NAMESPACE_DECL))
7993 return((xmlNodePtr) ns->next);
7994 return(NULL);
7995 }
7996 }
7997 }
7998 return(NULL);
7999 }
8000
8001 /**
8002 * xmlXPathNextAncestor:
8003 * @ctxt: the XPath Parser context
8004 * @cur: the current node in the traversal
8005 *
8006 * Traversal function for the "ancestor" direction
8007 * the ancestor axis contains the ancestors of the context node; the ancestors
8008 * of the context node consist of the parent of context node and the parent's
8009 * parent and so on; the nodes are ordered in reverse document order; thus the
8010 * parent is the first node on the axis, and the parent's parent is the second
8011 * node on the axis
8012 *
8013 * Returns the next element following that axis
8014 */
8015 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8016 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8017 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8018 /*
8019 * the parent of an attribute or namespace node is the element
8020 * to which the attribute or namespace node is attached
8021 * !!!!!!!!!!!!!
8022 */
8023 if (cur == NULL) {
8024 if (ctxt->context->node == NULL) return(NULL);
8025 switch (ctxt->context->node->type) {
8026 case XML_ELEMENT_NODE:
8027 case XML_TEXT_NODE:
8028 case XML_CDATA_SECTION_NODE:
8029 case XML_ENTITY_REF_NODE:
8030 case XML_ENTITY_NODE:
8031 case XML_PI_NODE:
8032 case XML_COMMENT_NODE:
8033 case XML_DTD_NODE:
8034 case XML_ELEMENT_DECL:
8035 case XML_ATTRIBUTE_DECL:
8036 case XML_ENTITY_DECL:
8037 case XML_NOTATION_NODE:
8038 case XML_XINCLUDE_START:
8039 case XML_XINCLUDE_END:
8040 if (ctxt->context->node->parent == NULL)
8041 return((xmlNodePtr) ctxt->context->doc);
8042 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8043 ((ctxt->context->node->parent->name[0] == ' ') ||
8044 (xmlStrEqual(ctxt->context->node->parent->name,
8045 BAD_CAST "fake node libxslt"))))
8046 return(NULL);
8047 return(ctxt->context->node->parent);
8048 case XML_ATTRIBUTE_NODE: {
8049 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8050
8051 return(tmp->parent);
8052 }
8053 case XML_DOCUMENT_NODE:
8054 case XML_DOCUMENT_TYPE_NODE:
8055 case XML_DOCUMENT_FRAG_NODE:
8056 case XML_HTML_DOCUMENT_NODE:
8057 return(NULL);
8058 case XML_NAMESPACE_DECL: {
8059 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8060
8061 if ((ns->next != NULL) &&
8062 (ns->next->type != XML_NAMESPACE_DECL))
8063 return((xmlNodePtr) ns->next);
8064 /* Bad, how did that namespace end up here ? */
8065 return(NULL);
8066 }
8067 }
8068 return(NULL);
8069 }
8070 if (cur == ctxt->context->doc->children)
8071 return((xmlNodePtr) ctxt->context->doc);
8072 if (cur == (xmlNodePtr) ctxt->context->doc)
8073 return(NULL);
8074 switch (cur->type) {
8075 case XML_ELEMENT_NODE:
8076 case XML_TEXT_NODE:
8077 case XML_CDATA_SECTION_NODE:
8078 case XML_ENTITY_REF_NODE:
8079 case XML_ENTITY_NODE:
8080 case XML_PI_NODE:
8081 case XML_COMMENT_NODE:
8082 case XML_NOTATION_NODE:
8083 case XML_DTD_NODE:
8084 case XML_ELEMENT_DECL:
8085 case XML_ATTRIBUTE_DECL:
8086 case XML_ENTITY_DECL:
8087 case XML_XINCLUDE_START:
8088 case XML_XINCLUDE_END:
8089 if (cur->parent == NULL)
8090 return(NULL);
8091 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8092 ((cur->parent->name[0] == ' ') ||
8093 (xmlStrEqual(cur->parent->name,
8094 BAD_CAST "fake node libxslt"))))
8095 return(NULL);
8096 return(cur->parent);
8097 case XML_ATTRIBUTE_NODE: {
8098 xmlAttrPtr att = (xmlAttrPtr) cur;
8099
8100 return(att->parent);
8101 }
8102 case XML_NAMESPACE_DECL: {
8103 xmlNsPtr ns = (xmlNsPtr) cur;
8104
8105 if ((ns->next != NULL) &&
8106 (ns->next->type != XML_NAMESPACE_DECL))
8107 return((xmlNodePtr) ns->next);
8108 /* Bad, how did that namespace end up here ? */
8109 return(NULL);
8110 }
8111 case XML_DOCUMENT_NODE:
8112 case XML_DOCUMENT_TYPE_NODE:
8113 case XML_DOCUMENT_FRAG_NODE:
8114 case XML_HTML_DOCUMENT_NODE:
8115 return(NULL);
8116 }
8117 return(NULL);
8118 }
8119
8120 /**
8121 * xmlXPathNextAncestorOrSelf:
8122 * @ctxt: the XPath Parser context
8123 * @cur: the current node in the traversal
8124 *
8125 * Traversal function for the "ancestor-or-self" direction
8126 * he ancestor-or-self axis contains the context node and ancestors of
8127 * the context node in reverse document order; thus the context node is
8128 * the first node on the axis, and the context node's parent the second;
8129 * parent here is defined the same as with the parent axis.
8130 *
8131 * Returns the next element following that axis
8132 */
8133 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8134 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8135 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8136 if (cur == NULL)
8137 return(ctxt->context->node);
8138 return(xmlXPathNextAncestor(ctxt, cur));
8139 }
8140
8141 /**
8142 * xmlXPathNextFollowingSibling:
8143 * @ctxt: the XPath Parser context
8144 * @cur: the current node in the traversal
8145 *
8146 * Traversal function for the "following-sibling" direction
8147 * The following-sibling axis contains the following siblings of the context
8148 * node in document order.
8149 *
8150 * Returns the next element following that axis
8151 */
8152 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8153 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8157 return(NULL);
8158 if (cur == (xmlNodePtr) ctxt->context->doc)
8159 return(NULL);
8160 if (cur == NULL)
8161 return(ctxt->context->node->next);
8162 return(cur->next);
8163 }
8164
8165 /**
8166 * xmlXPathNextPrecedingSibling:
8167 * @ctxt: the XPath Parser context
8168 * @cur: the current node in the traversal
8169 *
8170 * Traversal function for the "preceding-sibling" direction
8171 * The preceding-sibling axis contains the preceding siblings of the context
8172 * node in reverse document order; the first preceding sibling is first on the
8173 * axis; the sibling preceding that node is the second on the axis and so on.
8174 *
8175 * Returns the next element following that axis
8176 */
8177 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8178 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8179 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8180 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8181 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8182 return(NULL);
8183 if (cur == (xmlNodePtr) ctxt->context->doc)
8184 return(NULL);
8185 if (cur == NULL)
8186 return(ctxt->context->node->prev);
8187 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8188 cur = cur->prev;
8189 if (cur == NULL)
8190 return(ctxt->context->node->prev);
8191 }
8192 return(cur->prev);
8193 }
8194
8195 /**
8196 * xmlXPathNextFollowing:
8197 * @ctxt: the XPath Parser context
8198 * @cur: the current node in the traversal
8199 *
8200 * Traversal function for the "following" direction
8201 * The following axis contains all nodes in the same document as the context
8202 * node that are after the context node in document order, excluding any
8203 * descendants and excluding attribute nodes and namespace nodes; the nodes
8204 * are ordered in document order
8205 *
8206 * Returns the next element following that axis
8207 */
8208 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8209 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8210 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8211 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8212 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8213 return(cur->children);
8214
8215 if (cur == NULL) {
8216 cur = ctxt->context->node;
8217 if (cur->type == XML_ATTRIBUTE_NODE) {
8218 cur = cur->parent;
8219 } else if (cur->type == XML_NAMESPACE_DECL) {
8220 xmlNsPtr ns = (xmlNsPtr) cur;
8221
8222 if ((ns->next == NULL) ||
8223 (ns->next->type == XML_NAMESPACE_DECL))
8224 return (NULL);
8225 cur = (xmlNodePtr) ns->next;
8226 }
8227 }
8228 if (cur == NULL) return(NULL) ; /* ERROR */
8229 if (cur->next != NULL) return(cur->next) ;
8230 do {
8231 cur = cur->parent;
8232 if (cur == NULL) break;
8233 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8234 if (cur->next != NULL) return(cur->next);
8235 } while (cur != NULL);
8236 return(cur);
8237 }
8238
8239 /*
8240 * xmlXPathIsAncestor:
8241 * @ancestor: the ancestor node
8242 * @node: the current node
8243 *
8244 * Check that @ancestor is a @node's ancestor
8245 *
8246 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8247 */
8248 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8249 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8250 if ((ancestor == NULL) || (node == NULL)) return(0);
8251 if (node->type == XML_NAMESPACE_DECL)
8252 return(0);
8253 if (ancestor->type == XML_NAMESPACE_DECL)
8254 return(0);
8255 /* nodes need to be in the same document */
8256 if (ancestor->doc != node->doc) return(0);
8257 /* avoid searching if ancestor or node is the root node */
8258 if (ancestor == (xmlNodePtr) node->doc) return(1);
8259 if (node == (xmlNodePtr) ancestor->doc) return(0);
8260 while (node->parent != NULL) {
8261 if (node->parent == ancestor)
8262 return(1);
8263 node = node->parent;
8264 }
8265 return(0);
8266 }
8267
8268 /**
8269 * xmlXPathNextPreceding:
8270 * @ctxt: the XPath Parser context
8271 * @cur: the current node in the traversal
8272 *
8273 * Traversal function for the "preceding" direction
8274 * the preceding axis contains all nodes in the same document as the context
8275 * node that are before the context node in document order, excluding any
8276 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8277 * ordered in reverse document order
8278 *
8279 * Returns the next element following that axis
8280 */
8281 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8282 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8283 {
8284 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8285 if (cur == NULL) {
8286 cur = ctxt->context->node;
8287 if (cur->type == XML_ATTRIBUTE_NODE) {
8288 cur = cur->parent;
8289 } else if (cur->type == XML_NAMESPACE_DECL) {
8290 xmlNsPtr ns = (xmlNsPtr) cur;
8291
8292 if ((ns->next == NULL) ||
8293 (ns->next->type == XML_NAMESPACE_DECL))
8294 return (NULL);
8295 cur = (xmlNodePtr) ns->next;
8296 }
8297 }
8298 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8299 return (NULL);
8300 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8301 cur = cur->prev;
8302 do {
8303 if (cur->prev != NULL) {
8304 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8305 return (cur);
8306 }
8307
8308 cur = cur->parent;
8309 if (cur == NULL)
8310 return (NULL);
8311 if (cur == ctxt->context->doc->children)
8312 return (NULL);
8313 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8314 return (cur);
8315 }
8316
8317 /**
8318 * xmlXPathNextPrecedingInternal:
8319 * @ctxt: the XPath Parser context
8320 * @cur: the current node in the traversal
8321 *
8322 * Traversal function for the "preceding" direction
8323 * the preceding axis contains all nodes in the same document as the context
8324 * node that are before the context node in document order, excluding any
8325 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8326 * ordered in reverse document order
8327 * This is a faster implementation but internal only since it requires a
8328 * state kept in the parser context: ctxt->ancestor.
8329 *
8330 * Returns the next element following that axis
8331 */
8332 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8333 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8334 xmlNodePtr cur)
8335 {
8336 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8337 if (cur == NULL) {
8338 cur = ctxt->context->node;
8339 if (cur == NULL)
8340 return (NULL);
8341 if (cur->type == XML_ATTRIBUTE_NODE) {
8342 cur = cur->parent;
8343 } else if (cur->type == XML_NAMESPACE_DECL) {
8344 xmlNsPtr ns = (xmlNsPtr) cur;
8345
8346 if ((ns->next == NULL) ||
8347 (ns->next->type == XML_NAMESPACE_DECL))
8348 return (NULL);
8349 cur = (xmlNodePtr) ns->next;
8350 }
8351 ctxt->ancestor = cur->parent;
8352 }
8353 if (cur->type == XML_NAMESPACE_DECL)
8354 return(NULL);
8355 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8356 cur = cur->prev;
8357 while (cur->prev == NULL) {
8358 cur = cur->parent;
8359 if (cur == NULL)
8360 return (NULL);
8361 if (cur == ctxt->context->doc->children)
8362 return (NULL);
8363 if (cur != ctxt->ancestor)
8364 return (cur);
8365 ctxt->ancestor = cur->parent;
8366 }
8367 cur = cur->prev;
8368 while (cur->last != NULL)
8369 cur = cur->last;
8370 return (cur);
8371 }
8372
8373 /**
8374 * xmlXPathNextNamespace:
8375 * @ctxt: the XPath Parser context
8376 * @cur: the current attribute in the traversal
8377 *
8378 * Traversal function for the "namespace" direction
8379 * the namespace axis contains the namespace nodes of the context node;
8380 * the order of nodes on this axis is implementation-defined; the axis will
8381 * be empty unless the context node is an element
8382 *
8383 * We keep the XML namespace node at the end of the list.
8384 *
8385 * Returns the next element following that axis
8386 */
8387 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8388 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8389 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8390 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8391 if (cur == NULL) {
8392 if (ctxt->context->tmpNsList != NULL)
8393 xmlFree(ctxt->context->tmpNsList);
8394 ctxt->context->tmpNsList =
8395 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8396 ctxt->context->tmpNsNr = 0;
8397 if (ctxt->context->tmpNsList != NULL) {
8398 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8399 ctxt->context->tmpNsNr++;
8400 }
8401 }
8402 return((xmlNodePtr) xmlXPathXMLNamespace);
8403 }
8404 if (ctxt->context->tmpNsNr > 0) {
8405 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8406 } else {
8407 if (ctxt->context->tmpNsList != NULL)
8408 xmlFree(ctxt->context->tmpNsList);
8409 ctxt->context->tmpNsList = NULL;
8410 return(NULL);
8411 }
8412 }
8413
8414 /**
8415 * xmlXPathNextAttribute:
8416 * @ctxt: the XPath Parser context
8417 * @cur: the current attribute in the traversal
8418 *
8419 * Traversal function for the "attribute" direction
8420 * TODO: support DTD inherited default attributes
8421 *
8422 * Returns the next element following that axis
8423 */
8424 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8425 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8426 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8427 if (ctxt->context->node == NULL)
8428 return(NULL);
8429 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8430 return(NULL);
8431 if (cur == NULL) {
8432 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8433 return(NULL);
8434 return((xmlNodePtr)ctxt->context->node->properties);
8435 }
8436 return((xmlNodePtr)cur->next);
8437 }
8438
8439 /************************************************************************
8440 * *
8441 * NodeTest Functions *
8442 * *
8443 ************************************************************************/
8444
8445 #define IS_FUNCTION 200
8446
8447
8448 /************************************************************************
8449 * *
8450 * Implicit tree core function library *
8451 * *
8452 ************************************************************************/
8453
8454 /**
8455 * xmlXPathRoot:
8456 * @ctxt: the XPath Parser context
8457 *
8458 * Initialize the context to the root of the document
8459 */
8460 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8461 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8462 if ((ctxt == NULL) || (ctxt->context == NULL))
8463 return;
8464 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8465 (xmlNodePtr) ctxt->context->doc));
8466 }
8467
8468 /************************************************************************
8469 * *
8470 * The explicit core function library *
8471 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8472 * *
8473 ************************************************************************/
8474
8475
8476 /**
8477 * xmlXPathLastFunction:
8478 * @ctxt: the XPath Parser context
8479 * @nargs: the number of arguments
8480 *
8481 * Implement the last() XPath function
8482 * number last()
8483 * The last function returns the number of nodes in the context node list.
8484 */
8485 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8486 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8487 CHECK_ARITY(0);
8488 if (ctxt->context->contextSize >= 0) {
8489 valuePush(ctxt,
8490 xmlXPathCacheNewFloat(ctxt->context,
8491 (double) ctxt->context->contextSize));
8492 #ifdef DEBUG_EXPR
8493 xmlGenericError(xmlGenericErrorContext,
8494 "last() : %d\n", ctxt->context->contextSize);
8495 #endif
8496 } else {
8497 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8498 }
8499 }
8500
8501 /**
8502 * xmlXPathPositionFunction:
8503 * @ctxt: the XPath Parser context
8504 * @nargs: the number of arguments
8505 *
8506 * Implement the position() XPath function
8507 * number position()
8508 * The position function returns the position of the context node in the
8509 * context node list. The first position is 1, and so the last position
8510 * will be equal to last().
8511 */
8512 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8513 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514 CHECK_ARITY(0);
8515 if (ctxt->context->proximityPosition >= 0) {
8516 valuePush(ctxt,
8517 xmlXPathCacheNewFloat(ctxt->context,
8518 (double) ctxt->context->proximityPosition));
8519 #ifdef DEBUG_EXPR
8520 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8521 ctxt->context->proximityPosition);
8522 #endif
8523 } else {
8524 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8525 }
8526 }
8527
8528 /**
8529 * xmlXPathCountFunction:
8530 * @ctxt: the XPath Parser context
8531 * @nargs: the number of arguments
8532 *
8533 * Implement the count() XPath function
8534 * number count(node-set)
8535 */
8536 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8537 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8538 xmlXPathObjectPtr cur;
8539
8540 CHECK_ARITY(1);
8541 if ((ctxt->value == NULL) ||
8542 ((ctxt->value->type != XPATH_NODESET) &&
8543 (ctxt->value->type != XPATH_XSLT_TREE)))
8544 XP_ERROR(XPATH_INVALID_TYPE);
8545 cur = valuePop(ctxt);
8546
8547 if ((cur == NULL) || (cur->nodesetval == NULL))
8548 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8549 else
8550 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8551 (double) cur->nodesetval->nodeNr));
8552 xmlXPathReleaseObject(ctxt->context, cur);
8553 }
8554
8555 /**
8556 * xmlXPathGetElementsByIds:
8557 * @doc: the document
8558 * @ids: a whitespace separated list of IDs
8559 *
8560 * Selects elements by their unique ID.
8561 *
8562 * Returns a node-set of selected elements.
8563 */
8564 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8565 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8566 xmlNodeSetPtr ret;
8567 const xmlChar *cur = ids;
8568 xmlChar *ID;
8569 xmlAttrPtr attr;
8570 xmlNodePtr elem = NULL;
8571
8572 if (ids == NULL) return(NULL);
8573
8574 ret = xmlXPathNodeSetCreate(NULL);
8575 if (ret == NULL)
8576 return(ret);
8577
8578 while (IS_BLANK_CH(*cur)) cur++;
8579 while (*cur != 0) {
8580 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8581 cur++;
8582
8583 ID = xmlStrndup(ids, cur - ids);
8584 if (ID != NULL) {
8585 /*
8586 * We used to check the fact that the value passed
8587 * was an NCName, but this generated much troubles for
8588 * me and Aleksey Sanin, people blatantly violated that
8589 * constraint, like Visa3D spec.
8590 * if (xmlValidateNCName(ID, 1) == 0)
8591 */
8592 attr = xmlGetID(doc, ID);
8593 if (attr != NULL) {
8594 if (attr->type == XML_ATTRIBUTE_NODE)
8595 elem = attr->parent;
8596 else if (attr->type == XML_ELEMENT_NODE)
8597 elem = (xmlNodePtr) attr;
8598 else
8599 elem = NULL;
8600 /* TODO: Check memory error. */
8601 if (elem != NULL)
8602 xmlXPathNodeSetAdd(ret, elem);
8603 }
8604 xmlFree(ID);
8605 }
8606
8607 while (IS_BLANK_CH(*cur)) cur++;
8608 ids = cur;
8609 }
8610 return(ret);
8611 }
8612
8613 /**
8614 * xmlXPathIdFunction:
8615 * @ctxt: the XPath Parser context
8616 * @nargs: the number of arguments
8617 *
8618 * Implement the id() XPath function
8619 * node-set id(object)
8620 * The id function selects elements by their unique ID
8621 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8622 * then the result is the union of the result of applying id to the
8623 * string value of each of the nodes in the argument node-set. When the
8624 * argument to id is of any other type, the argument is converted to a
8625 * string as if by a call to the string function; the string is split
8626 * into a whitespace-separated list of tokens (whitespace is any sequence
8627 * of characters matching the production S); the result is a node-set
8628 * containing the elements in the same document as the context node that
8629 * have a unique ID equal to any of the tokens in the list.
8630 */
8631 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8632 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8633 xmlChar *tokens;
8634 xmlNodeSetPtr ret;
8635 xmlXPathObjectPtr obj;
8636
8637 CHECK_ARITY(1);
8638 obj = valuePop(ctxt);
8639 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8640 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8641 xmlNodeSetPtr ns;
8642 int i;
8643
8644 /* TODO: Check memory error. */
8645 ret = xmlXPathNodeSetCreate(NULL);
8646
8647 if (obj->nodesetval != NULL) {
8648 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8649 tokens =
8650 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8651 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8652 /* TODO: Check memory error. */
8653 ret = xmlXPathNodeSetMerge(ret, ns);
8654 xmlXPathFreeNodeSet(ns);
8655 if (tokens != NULL)
8656 xmlFree(tokens);
8657 }
8658 }
8659 xmlXPathReleaseObject(ctxt->context, obj);
8660 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8661 return;
8662 }
8663 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8664 if (obj == NULL) return;
8665 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8666 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8667 xmlXPathReleaseObject(ctxt->context, obj);
8668 return;
8669 }
8670
8671 /**
8672 * xmlXPathLocalNameFunction:
8673 * @ctxt: the XPath Parser context
8674 * @nargs: the number of arguments
8675 *
8676 * Implement the local-name() XPath function
8677 * string local-name(node-set?)
8678 * The local-name function returns a string containing the local part
8679 * of the name of the node in the argument node-set that is first in
8680 * document order. If the node-set is empty or the first node has no
8681 * name, an empty string is returned. If the argument is omitted it
8682 * defaults to the context node.
8683 */
8684 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8685 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8686 xmlXPathObjectPtr cur;
8687
8688 if (ctxt == NULL) return;
8689
8690 if (nargs == 0) {
8691 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8692 ctxt->context->node));
8693 nargs = 1;
8694 }
8695
8696 CHECK_ARITY(1);
8697 if ((ctxt->value == NULL) ||
8698 ((ctxt->value->type != XPATH_NODESET) &&
8699 (ctxt->value->type != XPATH_XSLT_TREE)))
8700 XP_ERROR(XPATH_INVALID_TYPE);
8701 cur = valuePop(ctxt);
8702
8703 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8704 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8705 } else {
8706 int i = 0; /* Should be first in document order !!!!! */
8707 switch (cur->nodesetval->nodeTab[i]->type) {
8708 case XML_ELEMENT_NODE:
8709 case XML_ATTRIBUTE_NODE:
8710 case XML_PI_NODE:
8711 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8712 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713 else
8714 valuePush(ctxt,
8715 xmlXPathCacheNewString(ctxt->context,
8716 cur->nodesetval->nodeTab[i]->name));
8717 break;
8718 case XML_NAMESPACE_DECL:
8719 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8720 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8721 break;
8722 default:
8723 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8724 }
8725 }
8726 xmlXPathReleaseObject(ctxt->context, cur);
8727 }
8728
8729 /**
8730 * xmlXPathNamespaceURIFunction:
8731 * @ctxt: the XPath Parser context
8732 * @nargs: the number of arguments
8733 *
8734 * Implement the namespace-uri() XPath function
8735 * string namespace-uri(node-set?)
8736 * The namespace-uri function returns a string containing the
8737 * namespace URI of the expanded name of the node in the argument
8738 * node-set that is first in document order. If the node-set is empty,
8739 * the first node has no name, or the expanded name has no namespace
8740 * URI, an empty string is returned. If the argument is omitted it
8741 * defaults to the context node.
8742 */
8743 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8744 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8745 xmlXPathObjectPtr cur;
8746
8747 if (ctxt == NULL) return;
8748
8749 if (nargs == 0) {
8750 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8751 ctxt->context->node));
8752 nargs = 1;
8753 }
8754 CHECK_ARITY(1);
8755 if ((ctxt->value == NULL) ||
8756 ((ctxt->value->type != XPATH_NODESET) &&
8757 (ctxt->value->type != XPATH_XSLT_TREE)))
8758 XP_ERROR(XPATH_INVALID_TYPE);
8759 cur = valuePop(ctxt);
8760
8761 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763 } else {
8764 int i = 0; /* Should be first in document order !!!!! */
8765 switch (cur->nodesetval->nodeTab[i]->type) {
8766 case XML_ELEMENT_NODE:
8767 case XML_ATTRIBUTE_NODE:
8768 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8769 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8770 else
8771 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8772 cur->nodesetval->nodeTab[i]->ns->href));
8773 break;
8774 default:
8775 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8776 }
8777 }
8778 xmlXPathReleaseObject(ctxt->context, cur);
8779 }
8780
8781 /**
8782 * xmlXPathNameFunction:
8783 * @ctxt: the XPath Parser context
8784 * @nargs: the number of arguments
8785 *
8786 * Implement the name() XPath function
8787 * string name(node-set?)
8788 * The name function returns a string containing a QName representing
8789 * the name of the node in the argument node-set that is first in document
8790 * order. The QName must represent the name with respect to the namespace
8791 * declarations in effect on the node whose name is being represented.
8792 * Typically, this will be the form in which the name occurred in the XML
8793 * source. This need not be the case if there are namespace declarations
8794 * in effect on the node that associate multiple prefixes with the same
8795 * namespace. However, an implementation may include information about
8796 * the original prefix in its representation of nodes; in this case, an
8797 * implementation can ensure that the returned string is always the same
8798 * as the QName used in the XML source. If the argument it omitted it
8799 * defaults to the context node.
8800 * Libxml keep the original prefix so the "real qualified name" used is
8801 * returned.
8802 */
8803 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8804 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8805 {
8806 xmlXPathObjectPtr cur;
8807
8808 if (nargs == 0) {
8809 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8810 ctxt->context->node));
8811 nargs = 1;
8812 }
8813
8814 CHECK_ARITY(1);
8815 if ((ctxt->value == NULL) ||
8816 ((ctxt->value->type != XPATH_NODESET) &&
8817 (ctxt->value->type != XPATH_XSLT_TREE)))
8818 XP_ERROR(XPATH_INVALID_TYPE);
8819 cur = valuePop(ctxt);
8820
8821 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8822 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8823 } else {
8824 int i = 0; /* Should be first in document order !!!!! */
8825
8826 switch (cur->nodesetval->nodeTab[i]->type) {
8827 case XML_ELEMENT_NODE:
8828 case XML_ATTRIBUTE_NODE:
8829 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8830 valuePush(ctxt,
8831 xmlXPathCacheNewCString(ctxt->context, ""));
8832 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8833 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8834 valuePush(ctxt,
8835 xmlXPathCacheNewString(ctxt->context,
8836 cur->nodesetval->nodeTab[i]->name));
8837 } else {
8838 xmlChar *fullname;
8839
8840 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8841 cur->nodesetval->nodeTab[i]->ns->prefix,
8842 NULL, 0);
8843 if (fullname == cur->nodesetval->nodeTab[i]->name)
8844 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8845 if (fullname == NULL) {
8846 XP_ERROR(XPATH_MEMORY_ERROR);
8847 }
8848 valuePush(ctxt, xmlXPathCacheWrapString(
8849 ctxt->context, fullname));
8850 }
8851 break;
8852 default:
8853 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8854 cur->nodesetval->nodeTab[i]));
8855 xmlXPathLocalNameFunction(ctxt, 1);
8856 }
8857 }
8858 xmlXPathReleaseObject(ctxt->context, cur);
8859 }
8860
8861
8862 /**
8863 * xmlXPathStringFunction:
8864 * @ctxt: the XPath Parser context
8865 * @nargs: the number of arguments
8866 *
8867 * Implement the string() XPath function
8868 * string string(object?)
8869 * The string function converts an object to a string as follows:
8870 * - A node-set is converted to a string by returning the value of
8871 * the node in the node-set that is first in document order.
8872 * If the node-set is empty, an empty string is returned.
8873 * - A number is converted to a string as follows
8874 * + NaN is converted to the string NaN
8875 * + positive zero is converted to the string 0
8876 * + negative zero is converted to the string 0
8877 * + positive infinity is converted to the string Infinity
8878 * + negative infinity is converted to the string -Infinity
8879 * + if the number is an integer, the number is represented in
8880 * decimal form as a Number with no decimal point and no leading
8881 * zeros, preceded by a minus sign (-) if the number is negative
8882 * + otherwise, the number is represented in decimal form as a
8883 * Number including a decimal point with at least one digit
8884 * before the decimal point and at least one digit after the
8885 * decimal point, preceded by a minus sign (-) if the number
8886 * is negative; there must be no leading zeros before the decimal
8887 * point apart possibly from the one required digit immediately
8888 * before the decimal point; beyond the one required digit
8889 * after the decimal point there must be as many, but only as
8890 * many, more digits as are needed to uniquely distinguish the
8891 * number from all other IEEE 754 numeric values.
8892 * - The boolean false value is converted to the string false.
8893 * The boolean true value is converted to the string true.
8894 *
8895 * If the argument is omitted, it defaults to a node-set with the
8896 * context node as its only member.
8897 */
8898 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8899 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8900 xmlXPathObjectPtr cur;
8901
8902 if (ctxt == NULL) return;
8903 if (nargs == 0) {
8904 valuePush(ctxt,
8905 xmlXPathCacheWrapString(ctxt->context,
8906 xmlXPathCastNodeToString(ctxt->context->node)));
8907 return;
8908 }
8909
8910 CHECK_ARITY(1);
8911 cur = valuePop(ctxt);
8912 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8913 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8914 }
8915
8916 /**
8917 * xmlXPathStringLengthFunction:
8918 * @ctxt: the XPath Parser context
8919 * @nargs: the number of arguments
8920 *
8921 * Implement the string-length() XPath function
8922 * number string-length(string?)
8923 * The string-length returns the number of characters in the string
8924 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8925 * the context node converted to a string, in other words the value
8926 * of the context node.
8927 */
8928 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8929 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8930 xmlXPathObjectPtr cur;
8931
8932 if (nargs == 0) {
8933 if ((ctxt == NULL) || (ctxt->context == NULL))
8934 return;
8935 if (ctxt->context->node == NULL) {
8936 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8937 } else {
8938 xmlChar *content;
8939
8940 content = xmlXPathCastNodeToString(ctxt->context->node);
8941 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8942 xmlUTF8Strlen(content)));
8943 xmlFree(content);
8944 }
8945 return;
8946 }
8947 CHECK_ARITY(1);
8948 CAST_TO_STRING;
8949 CHECK_TYPE(XPATH_STRING);
8950 cur = valuePop(ctxt);
8951 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8952 xmlUTF8Strlen(cur->stringval)));
8953 xmlXPathReleaseObject(ctxt->context, cur);
8954 }
8955
8956 /**
8957 * xmlXPathConcatFunction:
8958 * @ctxt: the XPath Parser context
8959 * @nargs: the number of arguments
8960 *
8961 * Implement the concat() XPath function
8962 * string concat(string, string, string*)
8963 * The concat function returns the concatenation of its arguments.
8964 */
8965 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8966 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8967 xmlXPathObjectPtr cur, newobj;
8968 xmlChar *tmp;
8969
8970 if (ctxt == NULL) return;
8971 if (nargs < 2) {
8972 CHECK_ARITY(2);
8973 }
8974
8975 CAST_TO_STRING;
8976 cur = valuePop(ctxt);
8977 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8978 xmlXPathReleaseObject(ctxt->context, cur);
8979 return;
8980 }
8981 nargs--;
8982
8983 while (nargs > 0) {
8984 CAST_TO_STRING;
8985 newobj = valuePop(ctxt);
8986 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8987 xmlXPathReleaseObject(ctxt->context, newobj);
8988 xmlXPathReleaseObject(ctxt->context, cur);
8989 XP_ERROR(XPATH_INVALID_TYPE);
8990 }
8991 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8992 newobj->stringval = cur->stringval;
8993 cur->stringval = tmp;
8994 xmlXPathReleaseObject(ctxt->context, newobj);
8995 nargs--;
8996 }
8997 valuePush(ctxt, cur);
8998 }
8999
9000 /**
9001 * xmlXPathContainsFunction:
9002 * @ctxt: the XPath Parser context
9003 * @nargs: the number of arguments
9004 *
9005 * Implement the contains() XPath function
9006 * boolean contains(string, string)
9007 * The contains function returns true if the first argument string
9008 * contains the second argument string, and otherwise returns false.
9009 */
9010 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9011 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9012 xmlXPathObjectPtr hay, needle;
9013
9014 CHECK_ARITY(2);
9015 CAST_TO_STRING;
9016 CHECK_TYPE(XPATH_STRING);
9017 needle = valuePop(ctxt);
9018 CAST_TO_STRING;
9019 hay = valuePop(ctxt);
9020
9021 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9022 xmlXPathReleaseObject(ctxt->context, hay);
9023 xmlXPathReleaseObject(ctxt->context, needle);
9024 XP_ERROR(XPATH_INVALID_TYPE);
9025 }
9026 if (xmlStrstr(hay->stringval, needle->stringval))
9027 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9028 else
9029 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9030 xmlXPathReleaseObject(ctxt->context, hay);
9031 xmlXPathReleaseObject(ctxt->context, needle);
9032 }
9033
9034 /**
9035 * xmlXPathStartsWithFunction:
9036 * @ctxt: the XPath Parser context
9037 * @nargs: the number of arguments
9038 *
9039 * Implement the starts-with() XPath function
9040 * boolean starts-with(string, string)
9041 * The starts-with function returns true if the first argument string
9042 * starts with the second argument string, and otherwise returns false.
9043 */
9044 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9045 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9046 xmlXPathObjectPtr hay, needle;
9047 int n;
9048
9049 CHECK_ARITY(2);
9050 CAST_TO_STRING;
9051 CHECK_TYPE(XPATH_STRING);
9052 needle = valuePop(ctxt);
9053 CAST_TO_STRING;
9054 hay = valuePop(ctxt);
9055
9056 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9057 xmlXPathReleaseObject(ctxt->context, hay);
9058 xmlXPathReleaseObject(ctxt->context, needle);
9059 XP_ERROR(XPATH_INVALID_TYPE);
9060 }
9061 n = xmlStrlen(needle->stringval);
9062 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9063 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9064 else
9065 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9066 xmlXPathReleaseObject(ctxt->context, hay);
9067 xmlXPathReleaseObject(ctxt->context, needle);
9068 }
9069
9070 /**
9071 * xmlXPathSubstringFunction:
9072 * @ctxt: the XPath Parser context
9073 * @nargs: the number of arguments
9074 *
9075 * Implement the substring() XPath function
9076 * string substring(string, number, number?)
9077 * The substring function returns the substring of the first argument
9078 * starting at the position specified in the second argument with
9079 * length specified in the third argument. For example,
9080 * substring("12345",2,3) returns "234". If the third argument is not
9081 * specified, it returns the substring starting at the position specified
9082 * in the second argument and continuing to the end of the string. For
9083 * example, substring("12345",2) returns "2345". More precisely, each
9084 * character in the string (see [3.6 Strings]) is considered to have a
9085 * numeric position: the position of the first character is 1, the position
9086 * of the second character is 2 and so on. The returned substring contains
9087 * those characters for which the position of the character is greater than
9088 * or equal to the second argument and, if the third argument is specified,
9089 * less than the sum of the second and third arguments; the comparisons
9090 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9091 * - substring("12345", 1.5, 2.6) returns "234"
9092 * - substring("12345", 0, 3) returns "12"
9093 * - substring("12345", 0 div 0, 3) returns ""
9094 * - substring("12345", 1, 0 div 0) returns ""
9095 * - substring("12345", -42, 1 div 0) returns "12345"
9096 * - substring("12345", -1 div 0, 1 div 0) returns ""
9097 */
9098 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9099 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9100 xmlXPathObjectPtr str, start, len;
9101 double le=0, in;
9102 int i = 1, j = INT_MAX;
9103
9104 if (nargs < 2) {
9105 CHECK_ARITY(2);
9106 }
9107 if (nargs > 3) {
9108 CHECK_ARITY(3);
9109 }
9110 /*
9111 * take care of possible last (position) argument
9112 */
9113 if (nargs == 3) {
9114 CAST_TO_NUMBER;
9115 CHECK_TYPE(XPATH_NUMBER);
9116 len = valuePop(ctxt);
9117 le = len->floatval;
9118 xmlXPathReleaseObject(ctxt->context, len);
9119 }
9120
9121 CAST_TO_NUMBER;
9122 CHECK_TYPE(XPATH_NUMBER);
9123 start = valuePop(ctxt);
9124 in = start->floatval;
9125 xmlXPathReleaseObject(ctxt->context, start);
9126 CAST_TO_STRING;
9127 CHECK_TYPE(XPATH_STRING);
9128 str = valuePop(ctxt);
9129
9130 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9131 i = INT_MAX;
9132 } else if (in >= 1.0) {
9133 i = (int)in;
9134 if (in - floor(in) >= 0.5)
9135 i += 1;
9136 }
9137
9138 if (nargs == 3) {
9139 double rin, rle, end;
9140
9141 rin = floor(in);
9142 if (in - rin >= 0.5)
9143 rin += 1.0;
9144
9145 rle = floor(le);
9146 if (le - rle >= 0.5)
9147 rle += 1.0;
9148
9149 end = rin + rle;
9150 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9151 j = 1;
9152 } else if (end < INT_MAX) {
9153 j = (int)end;
9154 }
9155 }
9156
9157 if (i < j) {
9158 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9159 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9160 xmlFree(ret);
9161 } else {
9162 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9163 }
9164
9165 xmlXPathReleaseObject(ctxt->context, str);
9166 }
9167
9168 /**
9169 * xmlXPathSubstringBeforeFunction:
9170 * @ctxt: the XPath Parser context
9171 * @nargs: the number of arguments
9172 *
9173 * Implement the substring-before() XPath function
9174 * string substring-before(string, string)
9175 * The substring-before function returns the substring of the first
9176 * argument string that precedes the first occurrence of the second
9177 * argument string in the first argument string, or the empty string
9178 * if the first argument string does not contain the second argument
9179 * string. For example, substring-before("1999/04/01","/") returns 1999.
9180 */
9181 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9182 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9183 xmlXPathObjectPtr str;
9184 xmlXPathObjectPtr find;
9185 xmlBufPtr target;
9186 const xmlChar *point;
9187 int offset;
9188
9189 CHECK_ARITY(2);
9190 CAST_TO_STRING;
9191 find = valuePop(ctxt);
9192 CAST_TO_STRING;
9193 str = valuePop(ctxt);
9194
9195 target = xmlBufCreate();
9196 if (target) {
9197 point = xmlStrstr(str->stringval, find->stringval);
9198 if (point) {
9199 offset = (int)(point - str->stringval);
9200 xmlBufAdd(target, str->stringval, offset);
9201 }
9202 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9203 xmlBufContent(target)));
9204 xmlBufFree(target);
9205 }
9206 xmlXPathReleaseObject(ctxt->context, str);
9207 xmlXPathReleaseObject(ctxt->context, find);
9208 }
9209
9210 /**
9211 * xmlXPathSubstringAfterFunction:
9212 * @ctxt: the XPath Parser context
9213 * @nargs: the number of arguments
9214 *
9215 * Implement the substring-after() XPath function
9216 * string substring-after(string, string)
9217 * The substring-after function returns the substring of the first
9218 * argument string that follows the first occurrence of the second
9219 * argument string in the first argument string, or the empty stringi
9220 * if the first argument string does not contain the second argument
9221 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9222 * and substring-after("1999/04/01","19") returns 99/04/01.
9223 */
9224 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9225 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9226 xmlXPathObjectPtr str;
9227 xmlXPathObjectPtr find;
9228 xmlBufPtr target;
9229 const xmlChar *point;
9230 int offset;
9231
9232 CHECK_ARITY(2);
9233 CAST_TO_STRING;
9234 find = valuePop(ctxt);
9235 CAST_TO_STRING;
9236 str = valuePop(ctxt);
9237
9238 target = xmlBufCreate();
9239 if (target) {
9240 point = xmlStrstr(str->stringval, find->stringval);
9241 if (point) {
9242 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9243 xmlBufAdd(target, &str->stringval[offset],
9244 xmlStrlen(str->stringval) - offset);
9245 }
9246 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9247 xmlBufContent(target)));
9248 xmlBufFree(target);
9249 }
9250 xmlXPathReleaseObject(ctxt->context, str);
9251 xmlXPathReleaseObject(ctxt->context, find);
9252 }
9253
9254 /**
9255 * xmlXPathNormalizeFunction:
9256 * @ctxt: the XPath Parser context
9257 * @nargs: the number of arguments
9258 *
9259 * Implement the normalize-space() XPath function
9260 * string normalize-space(string?)
9261 * The normalize-space function returns the argument string with white
9262 * space normalized by stripping leading and trailing whitespace
9263 * and replacing sequences of whitespace characters by a single
9264 * space. Whitespace characters are the same allowed by the S production
9265 * in XML. If the argument is omitted, it defaults to the context
9266 * node converted to a string, in other words the value of the context node.
9267 */
9268 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9269 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9270 xmlChar *source, *target;
9271 int blank;
9272
9273 if (ctxt == NULL) return;
9274 if (nargs == 0) {
9275 /* Use current context node */
9276 valuePush(ctxt,
9277 xmlXPathCacheWrapString(ctxt->context,
9278 xmlXPathCastNodeToString(ctxt->context->node)));
9279 nargs = 1;
9280 }
9281
9282 CHECK_ARITY(1);
9283 CAST_TO_STRING;
9284 CHECK_TYPE(XPATH_STRING);
9285 source = ctxt->value->stringval;
9286 if (source == NULL)
9287 return;
9288 target = source;
9289
9290 /* Skip leading whitespaces */
9291 while (IS_BLANK_CH(*source))
9292 source++;
9293
9294 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9295 blank = 0;
9296 while (*source) {
9297 if (IS_BLANK_CH(*source)) {
9298 blank = 1;
9299 } else {
9300 if (blank) {
9301 *target++ = 0x20;
9302 blank = 0;
9303 }
9304 *target++ = *source;
9305 }
9306 source++;
9307 }
9308 *target = 0;
9309 }
9310
9311 /**
9312 * xmlXPathTranslateFunction:
9313 * @ctxt: the XPath Parser context
9314 * @nargs: the number of arguments
9315 *
9316 * Implement the translate() XPath function
9317 * string translate(string, string, string)
9318 * The translate function returns the first argument string with
9319 * occurrences of characters in the second argument string replaced
9320 * by the character at the corresponding position in the third argument
9321 * string. For example, translate("bar","abc","ABC") returns the string
9322 * BAr. If there is a character in the second argument string with no
9323 * character at a corresponding position in the third argument string
9324 * (because the second argument string is longer than the third argument
9325 * string), then occurrences of that character in the first argument
9326 * string are removed. For example, translate("--aaa--","abc-","ABC")
9327 * returns "AAA". If a character occurs more than once in second
9328 * argument string, then the first occurrence determines the replacement
9329 * character. If the third argument string is longer than the second
9330 * argument string, then excess characters are ignored.
9331 */
9332 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9333 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334 xmlXPathObjectPtr str;
9335 xmlXPathObjectPtr from;
9336 xmlXPathObjectPtr to;
9337 xmlBufPtr target;
9338 int offset, max;
9339 xmlChar ch;
9340 const xmlChar *point;
9341 xmlChar *cptr;
9342
9343 CHECK_ARITY(3);
9344
9345 CAST_TO_STRING;
9346 to = valuePop(ctxt);
9347 CAST_TO_STRING;
9348 from = valuePop(ctxt);
9349 CAST_TO_STRING;
9350 str = valuePop(ctxt);
9351
9352 target = xmlBufCreate();
9353 if (target) {
9354 max = xmlUTF8Strlen(to->stringval);
9355 for (cptr = str->stringval; (ch=*cptr); ) {
9356 offset = xmlUTF8Strloc(from->stringval, cptr);
9357 if (offset >= 0) {
9358 if (offset < max) {
9359 point = xmlUTF8Strpos(to->stringval, offset);
9360 if (point)
9361 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9362 }
9363 } else
9364 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9365
9366 /* Step to next character in input */
9367 cptr++;
9368 if ( ch & 0x80 ) {
9369 /* if not simple ascii, verify proper format */
9370 if ( (ch & 0xc0) != 0xc0 ) {
9371 xmlGenericError(xmlGenericErrorContext,
9372 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9373 /* not asserting an XPath error is probably better */
9374 break;
9375 }
9376 /* then skip over remaining bytes for this char */
9377 while ( (ch <<= 1) & 0x80 )
9378 if ( (*cptr++ & 0xc0) != 0x80 ) {
9379 xmlGenericError(xmlGenericErrorContext,
9380 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381 /* not asserting an XPath error is probably better */
9382 break;
9383 }
9384 if (ch & 0x80) /* must have had error encountered */
9385 break;
9386 }
9387 }
9388 }
9389 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9390 xmlBufContent(target)));
9391 xmlBufFree(target);
9392 xmlXPathReleaseObject(ctxt->context, str);
9393 xmlXPathReleaseObject(ctxt->context, from);
9394 xmlXPathReleaseObject(ctxt->context, to);
9395 }
9396
9397 /**
9398 * xmlXPathBooleanFunction:
9399 * @ctxt: the XPath Parser context
9400 * @nargs: the number of arguments
9401 *
9402 * Implement the boolean() XPath function
9403 * boolean boolean(object)
9404 * The boolean function converts its argument to a boolean as follows:
9405 * - a number is true if and only if it is neither positive or
9406 * negative zero nor NaN
9407 * - a node-set is true if and only if it is non-empty
9408 * - a string is true if and only if its length is non-zero
9409 */
9410 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9411 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412 xmlXPathObjectPtr cur;
9413
9414 CHECK_ARITY(1);
9415 cur = valuePop(ctxt);
9416 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9417 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9418 valuePush(ctxt, cur);
9419 }
9420
9421 /**
9422 * xmlXPathNotFunction:
9423 * @ctxt: the XPath Parser context
9424 * @nargs: the number of arguments
9425 *
9426 * Implement the not() XPath function
9427 * boolean not(boolean)
9428 * The not function returns true if its argument is false,
9429 * and false otherwise.
9430 */
9431 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9432 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9433 CHECK_ARITY(1);
9434 CAST_TO_BOOLEAN;
9435 CHECK_TYPE(XPATH_BOOLEAN);
9436 ctxt->value->boolval = ! ctxt->value->boolval;
9437 }
9438
9439 /**
9440 * xmlXPathTrueFunction:
9441 * @ctxt: the XPath Parser context
9442 * @nargs: the number of arguments
9443 *
9444 * Implement the true() XPath function
9445 * boolean true()
9446 */
9447 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9448 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9449 CHECK_ARITY(0);
9450 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9451 }
9452
9453 /**
9454 * xmlXPathFalseFunction:
9455 * @ctxt: the XPath Parser context
9456 * @nargs: the number of arguments
9457 *
9458 * Implement the false() XPath function
9459 * boolean false()
9460 */
9461 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9462 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463 CHECK_ARITY(0);
9464 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9465 }
9466
9467 /**
9468 * xmlXPathLangFunction:
9469 * @ctxt: the XPath Parser context
9470 * @nargs: the number of arguments
9471 *
9472 * Implement the lang() XPath function
9473 * boolean lang(string)
9474 * The lang function returns true or false depending on whether the
9475 * language of the context node as specified by xml:lang attributes
9476 * is the same as or is a sublanguage of the language specified by
9477 * the argument string. The language of the context node is determined
9478 * by the value of the xml:lang attribute on the context node, or, if
9479 * the context node has no xml:lang attribute, by the value of the
9480 * xml:lang attribute on the nearest ancestor of the context node that
9481 * has an xml:lang attribute. If there is no such attribute, then lang
9482 * returns false. If there is such an attribute, then lang returns
9483 * true if the attribute value is equal to the argument ignoring case,
9484 * or if there is some suffix starting with - such that the attribute
9485 * value is equal to the argument ignoring that suffix of the attribute
9486 * value and ignoring case.
9487 */
9488 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9489 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9490 xmlXPathObjectPtr val = NULL;
9491 const xmlChar *theLang = NULL;
9492 const xmlChar *lang;
9493 int ret = 0;
9494 int i;
9495
9496 CHECK_ARITY(1);
9497 CAST_TO_STRING;
9498 CHECK_TYPE(XPATH_STRING);
9499 val = valuePop(ctxt);
9500 lang = val->stringval;
9501 theLang = xmlNodeGetLang(ctxt->context->node);
9502 if ((theLang != NULL) && (lang != NULL)) {
9503 for (i = 0;lang[i] != 0;i++)
9504 if (toupper(lang[i]) != toupper(theLang[i]))
9505 goto not_equal;
9506 if ((theLang[i] == 0) || (theLang[i] == '-'))
9507 ret = 1;
9508 }
9509 not_equal:
9510 if (theLang != NULL)
9511 xmlFree((void *)theLang);
9512
9513 xmlXPathReleaseObject(ctxt->context, val);
9514 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9515 }
9516
9517 /**
9518 * xmlXPathNumberFunction:
9519 * @ctxt: the XPath Parser context
9520 * @nargs: the number of arguments
9521 *
9522 * Implement the number() XPath function
9523 * number number(object?)
9524 */
9525 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9526 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9527 xmlXPathObjectPtr cur;
9528 double res;
9529
9530 if (ctxt == NULL) return;
9531 if (nargs == 0) {
9532 if (ctxt->context->node == NULL) {
9533 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9534 } else {
9535 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9536
9537 res = xmlXPathStringEvalNumber(content);
9538 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9539 xmlFree(content);
9540 }
9541 return;
9542 }
9543
9544 CHECK_ARITY(1);
9545 cur = valuePop(ctxt);
9546 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9547 }
9548
9549 /**
9550 * xmlXPathSumFunction:
9551 * @ctxt: the XPath Parser context
9552 * @nargs: the number of arguments
9553 *
9554 * Implement the sum() XPath function
9555 * number sum(node-set)
9556 * The sum function returns the sum of the values of the nodes in
9557 * the argument node-set.
9558 */
9559 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9560 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561 xmlXPathObjectPtr cur;
9562 int i;
9563 double res = 0.0;
9564
9565 CHECK_ARITY(1);
9566 if ((ctxt->value == NULL) ||
9567 ((ctxt->value->type != XPATH_NODESET) &&
9568 (ctxt->value->type != XPATH_XSLT_TREE)))
9569 XP_ERROR(XPATH_INVALID_TYPE);
9570 cur = valuePop(ctxt);
9571
9572 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9573 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9574 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9575 }
9576 }
9577 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9578 xmlXPathReleaseObject(ctxt->context, cur);
9579 }
9580
9581 /**
9582 * xmlXPathFloorFunction:
9583 * @ctxt: the XPath Parser context
9584 * @nargs: the number of arguments
9585 *
9586 * Implement the floor() XPath function
9587 * number floor(number)
9588 * The floor function returns the largest (closest to positive infinity)
9589 * number that is not greater than the argument and that is an integer.
9590 */
9591 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9592 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593 CHECK_ARITY(1);
9594 CAST_TO_NUMBER;
9595 CHECK_TYPE(XPATH_NUMBER);
9596
9597 ctxt->value->floatval = floor(ctxt->value->floatval);
9598 }
9599
9600 /**
9601 * xmlXPathCeilingFunction:
9602 * @ctxt: the XPath Parser context
9603 * @nargs: the number of arguments
9604 *
9605 * Implement the ceiling() XPath function
9606 * number ceiling(number)
9607 * The ceiling function returns the smallest (closest to negative infinity)
9608 * number that is not less than the argument and that is an integer.
9609 */
9610 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9611 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612 CHECK_ARITY(1);
9613 CAST_TO_NUMBER;
9614 CHECK_TYPE(XPATH_NUMBER);
9615
9616 #ifdef _AIX
9617 /* Work around buggy ceil() function on AIX */
9618 ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9619 #else
9620 ctxt->value->floatval = ceil(ctxt->value->floatval);
9621 #endif
9622 }
9623
9624 /**
9625 * xmlXPathRoundFunction:
9626 * @ctxt: the XPath Parser context
9627 * @nargs: the number of arguments
9628 *
9629 * Implement the round() XPath function
9630 * number round(number)
9631 * The round function returns the number that is closest to the
9632 * argument and that is an integer. If there are two such numbers,
9633 * then the one that is closest to positive infinity is returned.
9634 */
9635 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9636 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9637 double f;
9638
9639 CHECK_ARITY(1);
9640 CAST_TO_NUMBER;
9641 CHECK_TYPE(XPATH_NUMBER);
9642
9643 f = ctxt->value->floatval;
9644
9645 if ((f >= -0.5) && (f < 0.5)) {
9646 /* Handles negative zero. */
9647 ctxt->value->floatval *= 0.0;
9648 }
9649 else {
9650 double rounded = floor(f);
9651 if (f - rounded >= 0.5)
9652 rounded += 1.0;
9653 ctxt->value->floatval = rounded;
9654 }
9655 }
9656
9657 /************************************************************************
9658 * *
9659 * The Parser *
9660 * *
9661 ************************************************************************/
9662
9663 /*
9664 * a few forward declarations since we use a recursive call based
9665 * implementation.
9666 */
9667 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9668 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9669 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9670 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9671 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9672 int qualified);
9673
9674 /**
9675 * xmlXPathCurrentChar:
9676 * @ctxt: the XPath parser context
9677 * @cur: pointer to the beginning of the char
9678 * @len: pointer to the length of the char read
9679 *
9680 * The current char value, if using UTF-8 this may actually span multiple
9681 * bytes in the input buffer.
9682 *
9683 * Returns the current char value and its length
9684 */
9685
9686 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9687 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9688 unsigned char c;
9689 unsigned int val;
9690 const xmlChar *cur;
9691
9692 if (ctxt == NULL)
9693 return(0);
9694 cur = ctxt->cur;
9695
9696 /*
9697 * We are supposed to handle UTF8, check it's valid
9698 * From rfc2044: encoding of the Unicode values on UTF-8:
9699 *
9700 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9701 * 0000 0000-0000 007F 0xxxxxxx
9702 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9703 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9704 *
9705 * Check for the 0x110000 limit too
9706 */
9707 c = *cur;
9708 if (c & 0x80) {
9709 if ((cur[1] & 0xc0) != 0x80)
9710 goto encoding_error;
9711 if ((c & 0xe0) == 0xe0) {
9712
9713 if ((cur[2] & 0xc0) != 0x80)
9714 goto encoding_error;
9715 if ((c & 0xf0) == 0xf0) {
9716 if (((c & 0xf8) != 0xf0) ||
9717 ((cur[3] & 0xc0) != 0x80))
9718 goto encoding_error;
9719 /* 4-byte code */
9720 *len = 4;
9721 val = (cur[0] & 0x7) << 18;
9722 val |= (cur[1] & 0x3f) << 12;
9723 val |= (cur[2] & 0x3f) << 6;
9724 val |= cur[3] & 0x3f;
9725 } else {
9726 /* 3-byte code */
9727 *len = 3;
9728 val = (cur[0] & 0xf) << 12;
9729 val |= (cur[1] & 0x3f) << 6;
9730 val |= cur[2] & 0x3f;
9731 }
9732 } else {
9733 /* 2-byte code */
9734 *len = 2;
9735 val = (cur[0] & 0x1f) << 6;
9736 val |= cur[1] & 0x3f;
9737 }
9738 if (!IS_CHAR(val)) {
9739 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9740 }
9741 return(val);
9742 } else {
9743 /* 1-byte code */
9744 *len = 1;
9745 return((int) *cur);
9746 }
9747 encoding_error:
9748 /*
9749 * If we detect an UTF8 error that probably means that the
9750 * input encoding didn't get properly advertised in the
9751 * declaration header. Report the error and switch the encoding
9752 * to ISO-Latin-1 (if you don't like this policy, just declare the
9753 * encoding !)
9754 */
9755 *len = 0;
9756 XP_ERROR0(XPATH_ENCODING_ERROR);
9757 }
9758
9759 /**
9760 * xmlXPathParseNCName:
9761 * @ctxt: the XPath Parser context
9762 *
9763 * parse an XML namespace non qualified name.
9764 *
9765 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9766 *
9767 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9768 * CombiningChar | Extender
9769 *
9770 * Returns the namespace name or NULL
9771 */
9772
9773 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9774 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9775 const xmlChar *in;
9776 xmlChar *ret;
9777 int count = 0;
9778
9779 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9780 /*
9781 * Accelerator for simple ASCII names
9782 */
9783 in = ctxt->cur;
9784 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9785 ((*in >= 0x41) && (*in <= 0x5A)) ||
9786 (*in == '_')) {
9787 in++;
9788 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9789 ((*in >= 0x41) && (*in <= 0x5A)) ||
9790 ((*in >= 0x30) && (*in <= 0x39)) ||
9791 (*in == '_') || (*in == '.') ||
9792 (*in == '-'))
9793 in++;
9794 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9795 (*in == '[') || (*in == ']') || (*in == ':') ||
9796 (*in == '@') || (*in == '*')) {
9797 count = in - ctxt->cur;
9798 if (count == 0)
9799 return(NULL);
9800 ret = xmlStrndup(ctxt->cur, count);
9801 ctxt->cur = in;
9802 return(ret);
9803 }
9804 }
9805 return(xmlXPathParseNameComplex(ctxt, 0));
9806 }
9807
9808
9809 /**
9810 * xmlXPathParseQName:
9811 * @ctxt: the XPath Parser context
9812 * @prefix: a xmlChar **
9813 *
9814 * parse an XML qualified name
9815 *
9816 * [NS 5] QName ::= (Prefix ':')? LocalPart
9817 *
9818 * [NS 6] Prefix ::= NCName
9819 *
9820 * [NS 7] LocalPart ::= NCName
9821 *
9822 * Returns the function returns the local part, and prefix is updated
9823 * to get the Prefix if any.
9824 */
9825
9826 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9827 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9828 xmlChar *ret = NULL;
9829
9830 *prefix = NULL;
9831 ret = xmlXPathParseNCName(ctxt);
9832 if (ret && CUR == ':') {
9833 *prefix = ret;
9834 NEXT;
9835 ret = xmlXPathParseNCName(ctxt);
9836 }
9837 return(ret);
9838 }
9839
9840 /**
9841 * xmlXPathParseName:
9842 * @ctxt: the XPath Parser context
9843 *
9844 * parse an XML name
9845 *
9846 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9847 * CombiningChar | Extender
9848 *
9849 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9850 *
9851 * Returns the namespace name or NULL
9852 */
9853
9854 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9855 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9856 const xmlChar *in;
9857 xmlChar *ret;
9858 size_t count = 0;
9859
9860 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9861 /*
9862 * Accelerator for simple ASCII names
9863 */
9864 in = ctxt->cur;
9865 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9866 ((*in >= 0x41) && (*in <= 0x5A)) ||
9867 (*in == '_') || (*in == ':')) {
9868 in++;
9869 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9870 ((*in >= 0x41) && (*in <= 0x5A)) ||
9871 ((*in >= 0x30) && (*in <= 0x39)) ||
9872 (*in == '_') || (*in == '-') ||
9873 (*in == ':') || (*in == '.'))
9874 in++;
9875 if ((*in > 0) && (*in < 0x80)) {
9876 count = in - ctxt->cur;
9877 if (count > XML_MAX_NAME_LENGTH) {
9878 ctxt->cur = in;
9879 XP_ERRORNULL(XPATH_EXPR_ERROR);
9880 }
9881 ret = xmlStrndup(ctxt->cur, count);
9882 ctxt->cur = in;
9883 return(ret);
9884 }
9885 }
9886 return(xmlXPathParseNameComplex(ctxt, 1));
9887 }
9888
9889 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9890 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9891 xmlChar buf[XML_MAX_NAMELEN + 5];
9892 int len = 0, l;
9893 int c;
9894
9895 /*
9896 * Handler for more complex cases
9897 */
9898 c = CUR_CHAR(l);
9899 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9900 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9901 (c == '*') || /* accelerators */
9902 (!IS_LETTER(c) && (c != '_') &&
9903 ((!qualified) || (c != ':')))) {
9904 return(NULL);
9905 }
9906
9907 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9908 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9909 (c == '.') || (c == '-') ||
9910 (c == '_') || ((qualified) && (c == ':')) ||
9911 (IS_COMBINING(c)) ||
9912 (IS_EXTENDER(c)))) {
9913 COPY_BUF(l,buf,len,c);
9914 NEXTL(l);
9915 c = CUR_CHAR(l);
9916 if (len >= XML_MAX_NAMELEN) {
9917 /*
9918 * Okay someone managed to make a huge name, so he's ready to pay
9919 * for the processing speed.
9920 */
9921 xmlChar *buffer;
9922 int max = len * 2;
9923
9924 if (len > XML_MAX_NAME_LENGTH) {
9925 XP_ERRORNULL(XPATH_EXPR_ERROR);
9926 }
9927 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9928 if (buffer == NULL) {
9929 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9930 }
9931 memcpy(buffer, buf, len);
9932 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9933 (c == '.') || (c == '-') ||
9934 (c == '_') || ((qualified) && (c == ':')) ||
9935 (IS_COMBINING(c)) ||
9936 (IS_EXTENDER(c))) {
9937 if (len + 10 > max) {
9938 xmlChar *tmp;
9939 if (max > XML_MAX_NAME_LENGTH) {
9940 xmlFree(buffer);
9941 XP_ERRORNULL(XPATH_EXPR_ERROR);
9942 }
9943 max *= 2;
9944 tmp = (xmlChar *) xmlRealloc(buffer,
9945 max * sizeof(xmlChar));
9946 if (tmp == NULL) {
9947 xmlFree(buffer);
9948 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9949 }
9950 buffer = tmp;
9951 }
9952 COPY_BUF(l,buffer,len,c);
9953 NEXTL(l);
9954 c = CUR_CHAR(l);
9955 }
9956 buffer[len] = 0;
9957 return(buffer);
9958 }
9959 }
9960 if (len == 0)
9961 return(NULL);
9962 return(xmlStrndup(buf, len));
9963 }
9964
9965 #define MAX_FRAC 20
9966
9967 /**
9968 * xmlXPathStringEvalNumber:
9969 * @str: A string to scan
9970 *
9971 * [30a] Float ::= Number ('e' Digits?)?
9972 *
9973 * [30] Number ::= Digits ('.' Digits?)?
9974 * | '.' Digits
9975 * [31] Digits ::= [0-9]+
9976 *
9977 * Compile a Number in the string
9978 * In complement of the Number expression, this function also handles
9979 * negative values : '-' Number.
9980 *
9981 * Returns the double value.
9982 */
9983 double
xmlXPathStringEvalNumber(const xmlChar * str)9984 xmlXPathStringEvalNumber(const xmlChar *str) {
9985 const xmlChar *cur = str;
9986 double ret;
9987 int ok = 0;
9988 int isneg = 0;
9989 int exponent = 0;
9990 int is_exponent_negative = 0;
9991 #ifdef __GNUC__
9992 unsigned long tmp = 0;
9993 double temp;
9994 #endif
9995 if (cur == NULL) return(0);
9996 while (IS_BLANK_CH(*cur)) cur++;
9997 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9998 return(xmlXPathNAN);
9999 }
10000 if (*cur == '-') {
10001 isneg = 1;
10002 cur++;
10003 }
10004
10005 #ifdef __GNUC__
10006 /*
10007 * tmp/temp is a workaround against a gcc compiler bug
10008 * http://veillard.com/gcc.bug
10009 */
10010 ret = 0;
10011 while ((*cur >= '0') && (*cur <= '9')) {
10012 ret = ret * 10;
10013 tmp = (*cur - '0');
10014 ok = 1;
10015 cur++;
10016 temp = (double) tmp;
10017 ret = ret + temp;
10018 }
10019 #else
10020 ret = 0;
10021 while ((*cur >= '0') && (*cur <= '9')) {
10022 ret = ret * 10 + (*cur - '0');
10023 ok = 1;
10024 cur++;
10025 }
10026 #endif
10027
10028 if (*cur == '.') {
10029 int v, frac = 0, max;
10030 double fraction = 0;
10031
10032 cur++;
10033 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10034 return(xmlXPathNAN);
10035 }
10036 while (*cur == '0') {
10037 frac = frac + 1;
10038 cur++;
10039 }
10040 max = frac + MAX_FRAC;
10041 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10042 v = (*cur - '0');
10043 fraction = fraction * 10 + v;
10044 frac = frac + 1;
10045 cur++;
10046 }
10047 fraction /= pow(10.0, frac);
10048 ret = ret + fraction;
10049 while ((*cur >= '0') && (*cur <= '9'))
10050 cur++;
10051 }
10052 if ((*cur == 'e') || (*cur == 'E')) {
10053 cur++;
10054 if (*cur == '-') {
10055 is_exponent_negative = 1;
10056 cur++;
10057 } else if (*cur == '+') {
10058 cur++;
10059 }
10060 while ((*cur >= '0') && (*cur <= '9')) {
10061 if (exponent < 1000000)
10062 exponent = exponent * 10 + (*cur - '0');
10063 cur++;
10064 }
10065 }
10066 while (IS_BLANK_CH(*cur)) cur++;
10067 if (*cur != 0) return(xmlXPathNAN);
10068 if (isneg) ret = -ret;
10069 if (is_exponent_negative) exponent = -exponent;
10070 ret *= pow(10.0, (double)exponent);
10071 return(ret);
10072 }
10073
10074 /**
10075 * xmlXPathCompNumber:
10076 * @ctxt: the XPath Parser context
10077 *
10078 * [30] Number ::= Digits ('.' Digits?)?
10079 * | '.' Digits
10080 * [31] Digits ::= [0-9]+
10081 *
10082 * Compile a Number, then push it on the stack
10083 *
10084 */
10085 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10086 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10087 {
10088 double ret = 0.0;
10089 int ok = 0;
10090 int exponent = 0;
10091 int is_exponent_negative = 0;
10092 xmlXPathObjectPtr num;
10093 #ifdef __GNUC__
10094 unsigned long tmp = 0;
10095 double temp;
10096 #endif
10097
10098 CHECK_ERROR;
10099 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10100 XP_ERROR(XPATH_NUMBER_ERROR);
10101 }
10102 #ifdef __GNUC__
10103 /*
10104 * tmp/temp is a workaround against a gcc compiler bug
10105 * http://veillard.com/gcc.bug
10106 */
10107 ret = 0;
10108 while ((CUR >= '0') && (CUR <= '9')) {
10109 ret = ret * 10;
10110 tmp = (CUR - '0');
10111 ok = 1;
10112 NEXT;
10113 temp = (double) tmp;
10114 ret = ret + temp;
10115 }
10116 #else
10117 ret = 0;
10118 while ((CUR >= '0') && (CUR <= '9')) {
10119 ret = ret * 10 + (CUR - '0');
10120 ok = 1;
10121 NEXT;
10122 }
10123 #endif
10124 if (CUR == '.') {
10125 int v, frac = 0, max;
10126 double fraction = 0;
10127
10128 NEXT;
10129 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10130 XP_ERROR(XPATH_NUMBER_ERROR);
10131 }
10132 while (CUR == '0') {
10133 frac = frac + 1;
10134 NEXT;
10135 }
10136 max = frac + MAX_FRAC;
10137 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10138 v = (CUR - '0');
10139 fraction = fraction * 10 + v;
10140 frac = frac + 1;
10141 NEXT;
10142 }
10143 fraction /= pow(10.0, frac);
10144 ret = ret + fraction;
10145 while ((CUR >= '0') && (CUR <= '9'))
10146 NEXT;
10147 }
10148 if ((CUR == 'e') || (CUR == 'E')) {
10149 NEXT;
10150 if (CUR == '-') {
10151 is_exponent_negative = 1;
10152 NEXT;
10153 } else if (CUR == '+') {
10154 NEXT;
10155 }
10156 while ((CUR >= '0') && (CUR <= '9')) {
10157 if (exponent < 1000000)
10158 exponent = exponent * 10 + (CUR - '0');
10159 NEXT;
10160 }
10161 if (is_exponent_negative)
10162 exponent = -exponent;
10163 ret *= pow(10.0, (double) exponent);
10164 }
10165 num = xmlXPathCacheNewFloat(ctxt->context, ret);
10166 if (num == NULL) {
10167 ctxt->error = XPATH_MEMORY_ERROR;
10168 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10169 NULL) == -1) {
10170 xmlXPathReleaseObject(ctxt->context, num);
10171 }
10172 }
10173
10174 /**
10175 * xmlXPathParseLiteral:
10176 * @ctxt: the XPath Parser context
10177 *
10178 * Parse a Literal
10179 *
10180 * [29] Literal ::= '"' [^"]* '"'
10181 * | "'" [^']* "'"
10182 *
10183 * Returns the value found or NULL in case of error
10184 */
10185 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10186 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10187 const xmlChar *q;
10188 xmlChar *ret = NULL;
10189
10190 if (CUR == '"') {
10191 NEXT;
10192 q = CUR_PTR;
10193 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10194 NEXT;
10195 if (!IS_CHAR_CH(CUR)) {
10196 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10197 } else {
10198 ret = xmlStrndup(q, CUR_PTR - q);
10199 NEXT;
10200 }
10201 } else if (CUR == '\'') {
10202 NEXT;
10203 q = CUR_PTR;
10204 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10205 NEXT;
10206 if (!IS_CHAR_CH(CUR)) {
10207 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10208 } else {
10209 ret = xmlStrndup(q, CUR_PTR - q);
10210 NEXT;
10211 }
10212 } else {
10213 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10214 }
10215 return(ret);
10216 }
10217
10218 /**
10219 * xmlXPathCompLiteral:
10220 * @ctxt: the XPath Parser context
10221 *
10222 * Parse a Literal and push it on the stack.
10223 *
10224 * [29] Literal ::= '"' [^"]* '"'
10225 * | "'" [^']* "'"
10226 *
10227 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10228 */
10229 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10230 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10231 const xmlChar *q;
10232 xmlChar *ret = NULL;
10233 xmlXPathObjectPtr lit;
10234
10235 if (CUR == '"') {
10236 NEXT;
10237 q = CUR_PTR;
10238 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10239 NEXT;
10240 if (!IS_CHAR_CH(CUR)) {
10241 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10242 } else {
10243 ret = xmlStrndup(q, CUR_PTR - q);
10244 NEXT;
10245 }
10246 } else if (CUR == '\'') {
10247 NEXT;
10248 q = CUR_PTR;
10249 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10250 NEXT;
10251 if (!IS_CHAR_CH(CUR)) {
10252 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10253 } else {
10254 ret = xmlStrndup(q, CUR_PTR - q);
10255 NEXT;
10256 }
10257 } else {
10258 XP_ERROR(XPATH_START_LITERAL_ERROR);
10259 }
10260 if (ret == NULL) return;
10261 lit = xmlXPathCacheNewString(ctxt->context, ret);
10262 if (lit == NULL) {
10263 ctxt->error = XPATH_MEMORY_ERROR;
10264 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10265 NULL) == -1) {
10266 xmlXPathReleaseObject(ctxt->context, lit);
10267 }
10268 xmlFree(ret);
10269 }
10270
10271 /**
10272 * xmlXPathCompVariableReference:
10273 * @ctxt: the XPath Parser context
10274 *
10275 * Parse a VariableReference, evaluate it and push it on the stack.
10276 *
10277 * The variable bindings consist of a mapping from variable names
10278 * to variable values. The value of a variable is an object, which can be
10279 * of any of the types that are possible for the value of an expression,
10280 * and may also be of additional types not specified here.
10281 *
10282 * Early evaluation is possible since:
10283 * The variable bindings [...] used to evaluate a subexpression are
10284 * always the same as those used to evaluate the containing expression.
10285 *
10286 * [36] VariableReference ::= '$' QName
10287 */
10288 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10289 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10290 xmlChar *name;
10291 xmlChar *prefix;
10292
10293 SKIP_BLANKS;
10294 if (CUR != '$') {
10295 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10296 }
10297 NEXT;
10298 name = xmlXPathParseQName(ctxt, &prefix);
10299 if (name == NULL) {
10300 xmlFree(prefix);
10301 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10302 }
10303 ctxt->comp->last = -1;
10304 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10305 xmlFree(prefix);
10306 xmlFree(name);
10307 }
10308 SKIP_BLANKS;
10309 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10310 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10311 }
10312 }
10313
10314 /**
10315 * xmlXPathIsNodeType:
10316 * @name: a name string
10317 *
10318 * Is the name given a NodeType one.
10319 *
10320 * [38] NodeType ::= 'comment'
10321 * | 'text'
10322 * | 'processing-instruction'
10323 * | 'node'
10324 *
10325 * Returns 1 if true 0 otherwise
10326 */
10327 int
xmlXPathIsNodeType(const xmlChar * name)10328 xmlXPathIsNodeType(const xmlChar *name) {
10329 if (name == NULL)
10330 return(0);
10331
10332 if (xmlStrEqual(name, BAD_CAST "node"))
10333 return(1);
10334 if (xmlStrEqual(name, BAD_CAST "text"))
10335 return(1);
10336 if (xmlStrEqual(name, BAD_CAST "comment"))
10337 return(1);
10338 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10339 return(1);
10340 return(0);
10341 }
10342
10343 /**
10344 * xmlXPathCompFunctionCall:
10345 * @ctxt: the XPath Parser context
10346 *
10347 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10348 * [17] Argument ::= Expr
10349 *
10350 * Compile a function call, the evaluation of all arguments are
10351 * pushed on the stack
10352 */
10353 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10354 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10355 xmlChar *name;
10356 xmlChar *prefix;
10357 int nbargs = 0;
10358 int sort = 1;
10359
10360 name = xmlXPathParseQName(ctxt, &prefix);
10361 if (name == NULL) {
10362 xmlFree(prefix);
10363 XP_ERROR(XPATH_EXPR_ERROR);
10364 }
10365 SKIP_BLANKS;
10366 #ifdef DEBUG_EXPR
10367 if (prefix == NULL)
10368 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10369 name);
10370 else
10371 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10372 prefix, name);
10373 #endif
10374
10375 if (CUR != '(') {
10376 xmlFree(name);
10377 xmlFree(prefix);
10378 XP_ERROR(XPATH_EXPR_ERROR);
10379 }
10380 NEXT;
10381 SKIP_BLANKS;
10382
10383 /*
10384 * Optimization for count(): we don't need the node-set to be sorted.
10385 */
10386 if ((prefix == NULL) && (name[0] == 'c') &&
10387 xmlStrEqual(name, BAD_CAST "count"))
10388 {
10389 sort = 0;
10390 }
10391 ctxt->comp->last = -1;
10392 if (CUR != ')') {
10393 while (CUR != 0) {
10394 int op1 = ctxt->comp->last;
10395 ctxt->comp->last = -1;
10396 xmlXPathCompileExpr(ctxt, sort);
10397 if (ctxt->error != XPATH_EXPRESSION_OK) {
10398 xmlFree(name);
10399 xmlFree(prefix);
10400 return;
10401 }
10402 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10403 nbargs++;
10404 if (CUR == ')') break;
10405 if (CUR != ',') {
10406 xmlFree(name);
10407 xmlFree(prefix);
10408 XP_ERROR(XPATH_EXPR_ERROR);
10409 }
10410 NEXT;
10411 SKIP_BLANKS;
10412 }
10413 }
10414 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10415 xmlFree(prefix);
10416 xmlFree(name);
10417 }
10418 NEXT;
10419 SKIP_BLANKS;
10420 }
10421
10422 /**
10423 * xmlXPathCompPrimaryExpr:
10424 * @ctxt: the XPath Parser context
10425 *
10426 * [15] PrimaryExpr ::= VariableReference
10427 * | '(' Expr ')'
10428 * | Literal
10429 * | Number
10430 * | FunctionCall
10431 *
10432 * Compile a primary expression.
10433 */
10434 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10435 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10436 SKIP_BLANKS;
10437 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10438 else if (CUR == '(') {
10439 NEXT;
10440 SKIP_BLANKS;
10441 xmlXPathCompileExpr(ctxt, 1);
10442 CHECK_ERROR;
10443 if (CUR != ')') {
10444 XP_ERROR(XPATH_EXPR_ERROR);
10445 }
10446 NEXT;
10447 SKIP_BLANKS;
10448 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10449 xmlXPathCompNumber(ctxt);
10450 } else if ((CUR == '\'') || (CUR == '"')) {
10451 xmlXPathCompLiteral(ctxt);
10452 } else {
10453 xmlXPathCompFunctionCall(ctxt);
10454 }
10455 SKIP_BLANKS;
10456 }
10457
10458 /**
10459 * xmlXPathCompFilterExpr:
10460 * @ctxt: the XPath Parser context
10461 *
10462 * [20] FilterExpr ::= PrimaryExpr
10463 * | FilterExpr Predicate
10464 *
10465 * Compile a filter expression.
10466 * Square brackets are used to filter expressions in the same way that
10467 * they are used in location paths. It is an error if the expression to
10468 * be filtered does not evaluate to a node-set. The context node list
10469 * used for evaluating the expression in square brackets is the node-set
10470 * to be filtered listed in document order.
10471 */
10472
10473 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10474 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10475 xmlXPathCompPrimaryExpr(ctxt);
10476 CHECK_ERROR;
10477 SKIP_BLANKS;
10478
10479 while (CUR == '[') {
10480 xmlXPathCompPredicate(ctxt, 1);
10481 SKIP_BLANKS;
10482 }
10483
10484
10485 }
10486
10487 /**
10488 * xmlXPathScanName:
10489 * @ctxt: the XPath Parser context
10490 *
10491 * Trickery: parse an XML name but without consuming the input flow
10492 * Needed to avoid insanity in the parser state.
10493 *
10494 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10495 * CombiningChar | Extender
10496 *
10497 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10498 *
10499 * [6] Names ::= Name (S Name)*
10500 *
10501 * Returns the Name parsed or NULL
10502 */
10503
10504 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10505 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10506 int l;
10507 int c;
10508 const xmlChar *cur;
10509 xmlChar *ret;
10510
10511 cur = ctxt->cur;
10512
10513 c = CUR_CHAR(l);
10514 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10515 (!IS_LETTER(c) && (c != '_') &&
10516 (c != ':'))) {
10517 return(NULL);
10518 }
10519
10520 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10521 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10522 (c == '.') || (c == '-') ||
10523 (c == '_') || (c == ':') ||
10524 (IS_COMBINING(c)) ||
10525 (IS_EXTENDER(c)))) {
10526 NEXTL(l);
10527 c = CUR_CHAR(l);
10528 }
10529 ret = xmlStrndup(cur, ctxt->cur - cur);
10530 ctxt->cur = cur;
10531 return(ret);
10532 }
10533
10534 /**
10535 * xmlXPathCompPathExpr:
10536 * @ctxt: the XPath Parser context
10537 *
10538 * [19] PathExpr ::= LocationPath
10539 * | FilterExpr
10540 * | FilterExpr '/' RelativeLocationPath
10541 * | FilterExpr '//' RelativeLocationPath
10542 *
10543 * Compile a path expression.
10544 * The / operator and // operators combine an arbitrary expression
10545 * and a relative location path. It is an error if the expression
10546 * does not evaluate to a node-set.
10547 * The / operator does composition in the same way as when / is
10548 * used in a location path. As in location paths, // is short for
10549 * /descendant-or-self::node()/.
10550 */
10551
10552 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10553 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10554 int lc = 1; /* Should we branch to LocationPath ? */
10555 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10556
10557 SKIP_BLANKS;
10558 if ((CUR == '$') || (CUR == '(') ||
10559 (IS_ASCII_DIGIT(CUR)) ||
10560 (CUR == '\'') || (CUR == '"') ||
10561 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10562 lc = 0;
10563 } else if (CUR == '*') {
10564 /* relative or absolute location path */
10565 lc = 1;
10566 } else if (CUR == '/') {
10567 /* relative or absolute location path */
10568 lc = 1;
10569 } else if (CUR == '@') {
10570 /* relative abbreviated attribute location path */
10571 lc = 1;
10572 } else if (CUR == '.') {
10573 /* relative abbreviated attribute location path */
10574 lc = 1;
10575 } else {
10576 /*
10577 * Problem is finding if we have a name here whether it's:
10578 * - a nodetype
10579 * - a function call in which case it's followed by '('
10580 * - an axis in which case it's followed by ':'
10581 * - a element name
10582 * We do an a priori analysis here rather than having to
10583 * maintain parsed token content through the recursive function
10584 * calls. This looks uglier but makes the code easier to
10585 * read/write/debug.
10586 */
10587 SKIP_BLANKS;
10588 name = xmlXPathScanName(ctxt);
10589 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10590 #ifdef DEBUG_STEP
10591 xmlGenericError(xmlGenericErrorContext,
10592 "PathExpr: Axis\n");
10593 #endif
10594 lc = 1;
10595 xmlFree(name);
10596 } else if (name != NULL) {
10597 int len =xmlStrlen(name);
10598
10599
10600 while (NXT(len) != 0) {
10601 if (NXT(len) == '/') {
10602 /* element name */
10603 #ifdef DEBUG_STEP
10604 xmlGenericError(xmlGenericErrorContext,
10605 "PathExpr: AbbrRelLocation\n");
10606 #endif
10607 lc = 1;
10608 break;
10609 } else if (IS_BLANK_CH(NXT(len))) {
10610 /* ignore blanks */
10611 ;
10612 } else if (NXT(len) == ':') {
10613 #ifdef DEBUG_STEP
10614 xmlGenericError(xmlGenericErrorContext,
10615 "PathExpr: AbbrRelLocation\n");
10616 #endif
10617 lc = 1;
10618 break;
10619 } else if ((NXT(len) == '(')) {
10620 /* Node Type or Function */
10621 if (xmlXPathIsNodeType(name)) {
10622 #ifdef DEBUG_STEP
10623 xmlGenericError(xmlGenericErrorContext,
10624 "PathExpr: Type search\n");
10625 #endif
10626 lc = 1;
10627 #ifdef LIBXML_XPTR_LOCS_ENABLED
10628 } else if (ctxt->xptr &&
10629 xmlStrEqual(name, BAD_CAST "range-to")) {
10630 lc = 1;
10631 #endif
10632 } else {
10633 #ifdef DEBUG_STEP
10634 xmlGenericError(xmlGenericErrorContext,
10635 "PathExpr: function call\n");
10636 #endif
10637 lc = 0;
10638 }
10639 break;
10640 } else if ((NXT(len) == '[')) {
10641 /* element name */
10642 #ifdef DEBUG_STEP
10643 xmlGenericError(xmlGenericErrorContext,
10644 "PathExpr: AbbrRelLocation\n");
10645 #endif
10646 lc = 1;
10647 break;
10648 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10649 (NXT(len) == '=')) {
10650 lc = 1;
10651 break;
10652 } else {
10653 lc = 1;
10654 break;
10655 }
10656 len++;
10657 }
10658 if (NXT(len) == 0) {
10659 #ifdef DEBUG_STEP
10660 xmlGenericError(xmlGenericErrorContext,
10661 "PathExpr: AbbrRelLocation\n");
10662 #endif
10663 /* element name */
10664 lc = 1;
10665 }
10666 xmlFree(name);
10667 } else {
10668 /* make sure all cases are covered explicitly */
10669 XP_ERROR(XPATH_EXPR_ERROR);
10670 }
10671 }
10672
10673 if (lc) {
10674 if (CUR == '/') {
10675 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10676 } else {
10677 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10678 }
10679 xmlXPathCompLocationPath(ctxt);
10680 } else {
10681 xmlXPathCompFilterExpr(ctxt);
10682 CHECK_ERROR;
10683 if ((CUR == '/') && (NXT(1) == '/')) {
10684 SKIP(2);
10685 SKIP_BLANKS;
10686
10687 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10688 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10689
10690 xmlXPathCompRelativeLocationPath(ctxt);
10691 } else if (CUR == '/') {
10692 xmlXPathCompRelativeLocationPath(ctxt);
10693 }
10694 }
10695 SKIP_BLANKS;
10696 }
10697
10698 /**
10699 * xmlXPathCompUnionExpr:
10700 * @ctxt: the XPath Parser context
10701 *
10702 * [18] UnionExpr ::= PathExpr
10703 * | UnionExpr '|' PathExpr
10704 *
10705 * Compile an union expression.
10706 */
10707
10708 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10709 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10710 xmlXPathCompPathExpr(ctxt);
10711 CHECK_ERROR;
10712 SKIP_BLANKS;
10713 while (CUR == '|') {
10714 int op1 = ctxt->comp->last;
10715 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10716
10717 NEXT;
10718 SKIP_BLANKS;
10719 xmlXPathCompPathExpr(ctxt);
10720
10721 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10722
10723 SKIP_BLANKS;
10724 }
10725 }
10726
10727 /**
10728 * xmlXPathCompUnaryExpr:
10729 * @ctxt: the XPath Parser context
10730 *
10731 * [27] UnaryExpr ::= UnionExpr
10732 * | '-' UnaryExpr
10733 *
10734 * Compile an unary expression.
10735 */
10736
10737 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10738 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10739 int minus = 0;
10740 int found = 0;
10741
10742 SKIP_BLANKS;
10743 while (CUR == '-') {
10744 minus = 1 - minus;
10745 found = 1;
10746 NEXT;
10747 SKIP_BLANKS;
10748 }
10749
10750 xmlXPathCompUnionExpr(ctxt);
10751 CHECK_ERROR;
10752 if (found) {
10753 if (minus)
10754 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10755 else
10756 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10757 }
10758 }
10759
10760 /**
10761 * xmlXPathCompMultiplicativeExpr:
10762 * @ctxt: the XPath Parser context
10763 *
10764 * [26] MultiplicativeExpr ::= UnaryExpr
10765 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10766 * | MultiplicativeExpr 'div' UnaryExpr
10767 * | MultiplicativeExpr 'mod' UnaryExpr
10768 * [34] MultiplyOperator ::= '*'
10769 *
10770 * Compile an Additive expression.
10771 */
10772
10773 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10774 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10775 xmlXPathCompUnaryExpr(ctxt);
10776 CHECK_ERROR;
10777 SKIP_BLANKS;
10778 while ((CUR == '*') ||
10779 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10780 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10781 int op = -1;
10782 int op1 = ctxt->comp->last;
10783
10784 if (CUR == '*') {
10785 op = 0;
10786 NEXT;
10787 } else if (CUR == 'd') {
10788 op = 1;
10789 SKIP(3);
10790 } else if (CUR == 'm') {
10791 op = 2;
10792 SKIP(3);
10793 }
10794 SKIP_BLANKS;
10795 xmlXPathCompUnaryExpr(ctxt);
10796 CHECK_ERROR;
10797 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10798 SKIP_BLANKS;
10799 }
10800 }
10801
10802 /**
10803 * xmlXPathCompAdditiveExpr:
10804 * @ctxt: the XPath Parser context
10805 *
10806 * [25] AdditiveExpr ::= MultiplicativeExpr
10807 * | AdditiveExpr '+' MultiplicativeExpr
10808 * | AdditiveExpr '-' MultiplicativeExpr
10809 *
10810 * Compile an Additive expression.
10811 */
10812
10813 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10814 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10815
10816 xmlXPathCompMultiplicativeExpr(ctxt);
10817 CHECK_ERROR;
10818 SKIP_BLANKS;
10819 while ((CUR == '+') || (CUR == '-')) {
10820 int plus;
10821 int op1 = ctxt->comp->last;
10822
10823 if (CUR == '+') plus = 1;
10824 else plus = 0;
10825 NEXT;
10826 SKIP_BLANKS;
10827 xmlXPathCompMultiplicativeExpr(ctxt);
10828 CHECK_ERROR;
10829 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10830 SKIP_BLANKS;
10831 }
10832 }
10833
10834 /**
10835 * xmlXPathCompRelationalExpr:
10836 * @ctxt: the XPath Parser context
10837 *
10838 * [24] RelationalExpr ::= AdditiveExpr
10839 * | RelationalExpr '<' AdditiveExpr
10840 * | RelationalExpr '>' AdditiveExpr
10841 * | RelationalExpr '<=' AdditiveExpr
10842 * | RelationalExpr '>=' AdditiveExpr
10843 *
10844 * A <= B > C is allowed ? Answer from James, yes with
10845 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10846 * which is basically what got implemented.
10847 *
10848 * Compile a Relational expression, then push the result
10849 * on the stack
10850 */
10851
10852 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10853 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10854 xmlXPathCompAdditiveExpr(ctxt);
10855 CHECK_ERROR;
10856 SKIP_BLANKS;
10857 while ((CUR == '<') || (CUR == '>')) {
10858 int inf, strict;
10859 int op1 = ctxt->comp->last;
10860
10861 if (CUR == '<') inf = 1;
10862 else inf = 0;
10863 if (NXT(1) == '=') strict = 0;
10864 else strict = 1;
10865 NEXT;
10866 if (!strict) NEXT;
10867 SKIP_BLANKS;
10868 xmlXPathCompAdditiveExpr(ctxt);
10869 CHECK_ERROR;
10870 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10871 SKIP_BLANKS;
10872 }
10873 }
10874
10875 /**
10876 * xmlXPathCompEqualityExpr:
10877 * @ctxt: the XPath Parser context
10878 *
10879 * [23] EqualityExpr ::= RelationalExpr
10880 * | EqualityExpr '=' RelationalExpr
10881 * | EqualityExpr '!=' RelationalExpr
10882 *
10883 * A != B != C is allowed ? Answer from James, yes with
10884 * (RelationalExpr = RelationalExpr) = RelationalExpr
10885 * (RelationalExpr != RelationalExpr) != RelationalExpr
10886 * which is basically what got implemented.
10887 *
10888 * Compile an Equality expression.
10889 *
10890 */
10891 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10892 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10893 xmlXPathCompRelationalExpr(ctxt);
10894 CHECK_ERROR;
10895 SKIP_BLANKS;
10896 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10897 int eq;
10898 int op1 = ctxt->comp->last;
10899
10900 if (CUR == '=') eq = 1;
10901 else eq = 0;
10902 NEXT;
10903 if (!eq) NEXT;
10904 SKIP_BLANKS;
10905 xmlXPathCompRelationalExpr(ctxt);
10906 CHECK_ERROR;
10907 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10908 SKIP_BLANKS;
10909 }
10910 }
10911
10912 /**
10913 * xmlXPathCompAndExpr:
10914 * @ctxt: the XPath Parser context
10915 *
10916 * [22] AndExpr ::= EqualityExpr
10917 * | AndExpr 'and' EqualityExpr
10918 *
10919 * Compile an AND expression.
10920 *
10921 */
10922 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10923 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10924 xmlXPathCompEqualityExpr(ctxt);
10925 CHECK_ERROR;
10926 SKIP_BLANKS;
10927 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10928 int op1 = ctxt->comp->last;
10929 SKIP(3);
10930 SKIP_BLANKS;
10931 xmlXPathCompEqualityExpr(ctxt);
10932 CHECK_ERROR;
10933 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10934 SKIP_BLANKS;
10935 }
10936 }
10937
10938 /**
10939 * xmlXPathCompileExpr:
10940 * @ctxt: the XPath Parser context
10941 *
10942 * [14] Expr ::= OrExpr
10943 * [21] OrExpr ::= AndExpr
10944 * | OrExpr 'or' AndExpr
10945 *
10946 * Parse and compile an expression
10947 */
10948 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10949 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10950 xmlXPathContextPtr xpctxt = ctxt->context;
10951
10952 if (xpctxt != NULL) {
10953 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10954 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10955 /*
10956 * Parsing a single '(' pushes about 10 functions on the call stack
10957 * before recursing!
10958 */
10959 xpctxt->depth += 10;
10960 }
10961
10962 xmlXPathCompAndExpr(ctxt);
10963 CHECK_ERROR;
10964 SKIP_BLANKS;
10965 while ((CUR == 'o') && (NXT(1) == 'r')) {
10966 int op1 = ctxt->comp->last;
10967 SKIP(2);
10968 SKIP_BLANKS;
10969 xmlXPathCompAndExpr(ctxt);
10970 CHECK_ERROR;
10971 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10972 SKIP_BLANKS;
10973 }
10974 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10975 /* more ops could be optimized too */
10976 /*
10977 * This is the main place to eliminate sorting for
10978 * operations which don't require a sorted node-set.
10979 * E.g. count().
10980 */
10981 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10982 }
10983
10984 if (xpctxt != NULL)
10985 xpctxt->depth -= 10;
10986 }
10987
10988 /**
10989 * xmlXPathCompPredicate:
10990 * @ctxt: the XPath Parser context
10991 * @filter: act as a filter
10992 *
10993 * [8] Predicate ::= '[' PredicateExpr ']'
10994 * [9] PredicateExpr ::= Expr
10995 *
10996 * Compile a predicate expression
10997 */
10998 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)10999 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11000 int op1 = ctxt->comp->last;
11001
11002 SKIP_BLANKS;
11003 if (CUR != '[') {
11004 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11005 }
11006 NEXT;
11007 SKIP_BLANKS;
11008
11009 ctxt->comp->last = -1;
11010 /*
11011 * This call to xmlXPathCompileExpr() will deactivate sorting
11012 * of the predicate result.
11013 * TODO: Sorting is still activated for filters, since I'm not
11014 * sure if needed. Normally sorting should not be needed, since
11015 * a filter can only diminish the number of items in a sequence,
11016 * but won't change its order; so if the initial sequence is sorted,
11017 * subsequent sorting is not needed.
11018 */
11019 if (! filter)
11020 xmlXPathCompileExpr(ctxt, 0);
11021 else
11022 xmlXPathCompileExpr(ctxt, 1);
11023 CHECK_ERROR;
11024
11025 if (CUR != ']') {
11026 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11027 }
11028
11029 if (filter)
11030 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11031 else
11032 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11033
11034 NEXT;
11035 SKIP_BLANKS;
11036 }
11037
11038 /**
11039 * xmlXPathCompNodeTest:
11040 * @ctxt: the XPath Parser context
11041 * @test: pointer to a xmlXPathTestVal
11042 * @type: pointer to a xmlXPathTypeVal
11043 * @prefix: placeholder for a possible name prefix
11044 *
11045 * [7] NodeTest ::= NameTest
11046 * | NodeType '(' ')'
11047 * | 'processing-instruction' '(' Literal ')'
11048 *
11049 * [37] NameTest ::= '*'
11050 * | NCName ':' '*'
11051 * | QName
11052 * [38] NodeType ::= 'comment'
11053 * | 'text'
11054 * | 'processing-instruction'
11055 * | 'node'
11056 *
11057 * Returns the name found and updates @test, @type and @prefix appropriately
11058 */
11059 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)11060 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11061 xmlXPathTypeVal *type, xmlChar **prefix,
11062 xmlChar *name) {
11063 int blanks;
11064
11065 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11066 STRANGE;
11067 return(NULL);
11068 }
11069 *type = (xmlXPathTypeVal) 0;
11070 *test = (xmlXPathTestVal) 0;
11071 *prefix = NULL;
11072 SKIP_BLANKS;
11073
11074 if ((name == NULL) && (CUR == '*')) {
11075 /*
11076 * All elements
11077 */
11078 NEXT;
11079 *test = NODE_TEST_ALL;
11080 return(NULL);
11081 }
11082
11083 if (name == NULL)
11084 name = xmlXPathParseNCName(ctxt);
11085 if (name == NULL) {
11086 XP_ERRORNULL(XPATH_EXPR_ERROR);
11087 }
11088
11089 blanks = IS_BLANK_CH(CUR);
11090 SKIP_BLANKS;
11091 if (CUR == '(') {
11092 NEXT;
11093 /*
11094 * NodeType or PI search
11095 */
11096 if (xmlStrEqual(name, BAD_CAST "comment"))
11097 *type = NODE_TYPE_COMMENT;
11098 else if (xmlStrEqual(name, BAD_CAST "node"))
11099 *type = NODE_TYPE_NODE;
11100 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11101 *type = NODE_TYPE_PI;
11102 else if (xmlStrEqual(name, BAD_CAST "text"))
11103 *type = NODE_TYPE_TEXT;
11104 else {
11105 if (name != NULL)
11106 xmlFree(name);
11107 XP_ERRORNULL(XPATH_EXPR_ERROR);
11108 }
11109
11110 *test = NODE_TEST_TYPE;
11111
11112 SKIP_BLANKS;
11113 if (*type == NODE_TYPE_PI) {
11114 /*
11115 * Specific case: search a PI by name.
11116 */
11117 if (name != NULL)
11118 xmlFree(name);
11119 name = NULL;
11120 if (CUR != ')') {
11121 name = xmlXPathParseLiteral(ctxt);
11122 if (name == NULL) {
11123 XP_ERRORNULL(XPATH_EXPR_ERROR);
11124 }
11125 *test = NODE_TEST_PI;
11126 SKIP_BLANKS;
11127 }
11128 }
11129 if (CUR != ')') {
11130 if (name != NULL)
11131 xmlFree(name);
11132 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11133 }
11134 NEXT;
11135 return(name);
11136 }
11137 *test = NODE_TEST_NAME;
11138 if ((!blanks) && (CUR == ':')) {
11139 NEXT;
11140
11141 /*
11142 * Since currently the parser context don't have a
11143 * namespace list associated:
11144 * The namespace name for this prefix can be computed
11145 * only at evaluation time. The compilation is done
11146 * outside of any context.
11147 */
11148 #if 0
11149 *prefix = xmlXPathNsLookup(ctxt->context, name);
11150 if (name != NULL)
11151 xmlFree(name);
11152 if (*prefix == NULL) {
11153 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11154 }
11155 #else
11156 *prefix = name;
11157 #endif
11158
11159 if (CUR == '*') {
11160 /*
11161 * All elements
11162 */
11163 NEXT;
11164 *test = NODE_TEST_ALL;
11165 return(NULL);
11166 }
11167
11168 name = xmlXPathParseNCName(ctxt);
11169 if (name == NULL) {
11170 XP_ERRORNULL(XPATH_EXPR_ERROR);
11171 }
11172 }
11173 return(name);
11174 }
11175
11176 /**
11177 * xmlXPathIsAxisName:
11178 * @name: a preparsed name token
11179 *
11180 * [6] AxisName ::= 'ancestor'
11181 * | 'ancestor-or-self'
11182 * | 'attribute'
11183 * | 'child'
11184 * | 'descendant'
11185 * | 'descendant-or-self'
11186 * | 'following'
11187 * | 'following-sibling'
11188 * | 'namespace'
11189 * | 'parent'
11190 * | 'preceding'
11191 * | 'preceding-sibling'
11192 * | 'self'
11193 *
11194 * Returns the axis or 0
11195 */
11196 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11197 xmlXPathIsAxisName(const xmlChar *name) {
11198 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11199 switch (name[0]) {
11200 case 'a':
11201 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11202 ret = AXIS_ANCESTOR;
11203 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11204 ret = AXIS_ANCESTOR_OR_SELF;
11205 if (xmlStrEqual(name, BAD_CAST "attribute"))
11206 ret = AXIS_ATTRIBUTE;
11207 break;
11208 case 'c':
11209 if (xmlStrEqual(name, BAD_CAST "child"))
11210 ret = AXIS_CHILD;
11211 break;
11212 case 'd':
11213 if (xmlStrEqual(name, BAD_CAST "descendant"))
11214 ret = AXIS_DESCENDANT;
11215 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11216 ret = AXIS_DESCENDANT_OR_SELF;
11217 break;
11218 case 'f':
11219 if (xmlStrEqual(name, BAD_CAST "following"))
11220 ret = AXIS_FOLLOWING;
11221 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11222 ret = AXIS_FOLLOWING_SIBLING;
11223 break;
11224 case 'n':
11225 if (xmlStrEqual(name, BAD_CAST "namespace"))
11226 ret = AXIS_NAMESPACE;
11227 break;
11228 case 'p':
11229 if (xmlStrEqual(name, BAD_CAST "parent"))
11230 ret = AXIS_PARENT;
11231 if (xmlStrEqual(name, BAD_CAST "preceding"))
11232 ret = AXIS_PRECEDING;
11233 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11234 ret = AXIS_PRECEDING_SIBLING;
11235 break;
11236 case 's':
11237 if (xmlStrEqual(name, BAD_CAST "self"))
11238 ret = AXIS_SELF;
11239 break;
11240 }
11241 return(ret);
11242 }
11243
11244 /**
11245 * xmlXPathCompStep:
11246 * @ctxt: the XPath Parser context
11247 *
11248 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11249 * | AbbreviatedStep
11250 *
11251 * [12] AbbreviatedStep ::= '.' | '..'
11252 *
11253 * [5] AxisSpecifier ::= AxisName '::'
11254 * | AbbreviatedAxisSpecifier
11255 *
11256 * [13] AbbreviatedAxisSpecifier ::= '@'?
11257 *
11258 * Modified for XPtr range support as:
11259 *
11260 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11261 * | AbbreviatedStep
11262 * | 'range-to' '(' Expr ')' Predicate*
11263 *
11264 * Compile one step in a Location Path
11265 * A location step of . is short for self::node(). This is
11266 * particularly useful in conjunction with //. For example, the
11267 * location path .//para is short for
11268 * self::node()/descendant-or-self::node()/child::para
11269 * and so will select all para descendant elements of the context
11270 * node.
11271 * Similarly, a location step of .. is short for parent::node().
11272 * For example, ../title is short for parent::node()/child::title
11273 * and so will select the title children of the parent of the context
11274 * node.
11275 */
11276 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11277 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11278 #ifdef LIBXML_XPTR_LOCS_ENABLED
11279 int rangeto = 0;
11280 int op2 = -1;
11281 #endif
11282
11283 SKIP_BLANKS;
11284 if ((CUR == '.') && (NXT(1) == '.')) {
11285 SKIP(2);
11286 SKIP_BLANKS;
11287 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11288 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11289 } else if (CUR == '.') {
11290 NEXT;
11291 SKIP_BLANKS;
11292 } else {
11293 xmlChar *name = NULL;
11294 xmlChar *prefix = NULL;
11295 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11296 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11297 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11298 int op1;
11299
11300 /*
11301 * The modification needed for XPointer change to the production
11302 */
11303 #ifdef LIBXML_XPTR_LOCS_ENABLED
11304 if (ctxt->xptr) {
11305 name = xmlXPathParseNCName(ctxt);
11306 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11307 op2 = ctxt->comp->last;
11308 xmlFree(name);
11309 SKIP_BLANKS;
11310 if (CUR != '(') {
11311 XP_ERROR(XPATH_EXPR_ERROR);
11312 }
11313 NEXT;
11314 SKIP_BLANKS;
11315
11316 xmlXPathCompileExpr(ctxt, 1);
11317 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11318 CHECK_ERROR;
11319
11320 SKIP_BLANKS;
11321 if (CUR != ')') {
11322 XP_ERROR(XPATH_EXPR_ERROR);
11323 }
11324 NEXT;
11325 rangeto = 1;
11326 goto eval_predicates;
11327 }
11328 }
11329 #endif
11330 if (CUR == '*') {
11331 axis = AXIS_CHILD;
11332 } else {
11333 if (name == NULL)
11334 name = xmlXPathParseNCName(ctxt);
11335 if (name != NULL) {
11336 axis = xmlXPathIsAxisName(name);
11337 if (axis != 0) {
11338 SKIP_BLANKS;
11339 if ((CUR == ':') && (NXT(1) == ':')) {
11340 SKIP(2);
11341 xmlFree(name);
11342 name = NULL;
11343 } else {
11344 /* an element name can conflict with an axis one :-\ */
11345 axis = AXIS_CHILD;
11346 }
11347 } else {
11348 axis = AXIS_CHILD;
11349 }
11350 } else if (CUR == '@') {
11351 NEXT;
11352 axis = AXIS_ATTRIBUTE;
11353 } else {
11354 axis = AXIS_CHILD;
11355 }
11356 }
11357
11358 if (ctxt->error != XPATH_EXPRESSION_OK) {
11359 xmlFree(name);
11360 return;
11361 }
11362
11363 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11364 if (test == 0)
11365 return;
11366
11367 if ((prefix != NULL) && (ctxt->context != NULL) &&
11368 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11369 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11370 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11371 }
11372 }
11373 #ifdef DEBUG_STEP
11374 xmlGenericError(xmlGenericErrorContext,
11375 "Basis : computing new set\n");
11376 #endif
11377
11378 #ifdef DEBUG_STEP
11379 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11380 if (ctxt->value == NULL)
11381 xmlGenericError(xmlGenericErrorContext, "no value\n");
11382 else if (ctxt->value->nodesetval == NULL)
11383 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11384 else
11385 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11386 #endif
11387
11388 #ifdef LIBXML_XPTR_LOCS_ENABLED
11389 eval_predicates:
11390 #endif
11391 op1 = ctxt->comp->last;
11392 ctxt->comp->last = -1;
11393
11394 SKIP_BLANKS;
11395 while (CUR == '[') {
11396 xmlXPathCompPredicate(ctxt, 0);
11397 }
11398
11399 #ifdef LIBXML_XPTR_LOCS_ENABLED
11400 if (rangeto) {
11401 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11402 } else
11403 #endif
11404 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11405 test, type, (void *)prefix, (void *)name) == -1) {
11406 xmlFree(prefix);
11407 xmlFree(name);
11408 }
11409 }
11410 #ifdef DEBUG_STEP
11411 xmlGenericError(xmlGenericErrorContext, "Step : ");
11412 if (ctxt->value == NULL)
11413 xmlGenericError(xmlGenericErrorContext, "no value\n");
11414 else if (ctxt->value->nodesetval == NULL)
11415 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11416 else
11417 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11418 ctxt->value->nodesetval);
11419 #endif
11420 }
11421
11422 /**
11423 * xmlXPathCompRelativeLocationPath:
11424 * @ctxt: the XPath Parser context
11425 *
11426 * [3] RelativeLocationPath ::= Step
11427 * | RelativeLocationPath '/' Step
11428 * | AbbreviatedRelativeLocationPath
11429 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11430 *
11431 * Compile a relative location path.
11432 */
11433 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11434 xmlXPathCompRelativeLocationPath
11435 (xmlXPathParserContextPtr ctxt) {
11436 SKIP_BLANKS;
11437 if ((CUR == '/') && (NXT(1) == '/')) {
11438 SKIP(2);
11439 SKIP_BLANKS;
11440 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11441 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11442 } else if (CUR == '/') {
11443 NEXT;
11444 SKIP_BLANKS;
11445 }
11446 xmlXPathCompStep(ctxt);
11447 CHECK_ERROR;
11448 SKIP_BLANKS;
11449 while (CUR == '/') {
11450 if ((CUR == '/') && (NXT(1) == '/')) {
11451 SKIP(2);
11452 SKIP_BLANKS;
11453 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11454 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11455 xmlXPathCompStep(ctxt);
11456 } else if (CUR == '/') {
11457 NEXT;
11458 SKIP_BLANKS;
11459 xmlXPathCompStep(ctxt);
11460 }
11461 SKIP_BLANKS;
11462 }
11463 }
11464
11465 /**
11466 * xmlXPathCompLocationPath:
11467 * @ctxt: the XPath Parser context
11468 *
11469 * [1] LocationPath ::= RelativeLocationPath
11470 * | AbsoluteLocationPath
11471 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11472 * | AbbreviatedAbsoluteLocationPath
11473 * [10] AbbreviatedAbsoluteLocationPath ::=
11474 * '//' RelativeLocationPath
11475 *
11476 * Compile a location path
11477 *
11478 * // is short for /descendant-or-self::node()/. For example,
11479 * //para is short for /descendant-or-self::node()/child::para and
11480 * so will select any para element in the document (even a para element
11481 * that is a document element will be selected by //para since the
11482 * document element node is a child of the root node); div//para is
11483 * short for div/descendant-or-self::node()/child::para and so will
11484 * select all para descendants of div children.
11485 */
11486 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11487 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11488 SKIP_BLANKS;
11489 if (CUR != '/') {
11490 xmlXPathCompRelativeLocationPath(ctxt);
11491 } else {
11492 while (CUR == '/') {
11493 if ((CUR == '/') && (NXT(1) == '/')) {
11494 SKIP(2);
11495 SKIP_BLANKS;
11496 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11497 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11498 xmlXPathCompRelativeLocationPath(ctxt);
11499 } else if (CUR == '/') {
11500 NEXT;
11501 SKIP_BLANKS;
11502 if ((CUR != 0 ) &&
11503 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11504 (CUR == '@') || (CUR == '*')))
11505 xmlXPathCompRelativeLocationPath(ctxt);
11506 }
11507 CHECK_ERROR;
11508 }
11509 }
11510 }
11511
11512 /************************************************************************
11513 * *
11514 * XPath precompiled expression evaluation *
11515 * *
11516 ************************************************************************/
11517
11518 static int
11519 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11520
11521 #ifdef DEBUG_STEP
11522 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11523 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11524 int nbNodes)
11525 {
11526 xmlGenericError(xmlGenericErrorContext, "new step : ");
11527 switch (op->value) {
11528 case AXIS_ANCESTOR:
11529 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11530 break;
11531 case AXIS_ANCESTOR_OR_SELF:
11532 xmlGenericError(xmlGenericErrorContext,
11533 "axis 'ancestors-or-self' ");
11534 break;
11535 case AXIS_ATTRIBUTE:
11536 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11537 break;
11538 case AXIS_CHILD:
11539 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11540 break;
11541 case AXIS_DESCENDANT:
11542 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11543 break;
11544 case AXIS_DESCENDANT_OR_SELF:
11545 xmlGenericError(xmlGenericErrorContext,
11546 "axis 'descendant-or-self' ");
11547 break;
11548 case AXIS_FOLLOWING:
11549 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11550 break;
11551 case AXIS_FOLLOWING_SIBLING:
11552 xmlGenericError(xmlGenericErrorContext,
11553 "axis 'following-siblings' ");
11554 break;
11555 case AXIS_NAMESPACE:
11556 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11557 break;
11558 case AXIS_PARENT:
11559 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11560 break;
11561 case AXIS_PRECEDING:
11562 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11563 break;
11564 case AXIS_PRECEDING_SIBLING:
11565 xmlGenericError(xmlGenericErrorContext,
11566 "axis 'preceding-sibling' ");
11567 break;
11568 case AXIS_SELF:
11569 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11570 break;
11571 }
11572 xmlGenericError(xmlGenericErrorContext,
11573 " context contains %d nodes\n", nbNodes);
11574 switch (op->value2) {
11575 case NODE_TEST_NONE:
11576 xmlGenericError(xmlGenericErrorContext,
11577 " searching for none !!!\n");
11578 break;
11579 case NODE_TEST_TYPE:
11580 xmlGenericError(xmlGenericErrorContext,
11581 " searching for type %d\n", op->value3);
11582 break;
11583 case NODE_TEST_PI:
11584 xmlGenericError(xmlGenericErrorContext,
11585 " searching for PI !!!\n");
11586 break;
11587 case NODE_TEST_ALL:
11588 xmlGenericError(xmlGenericErrorContext,
11589 " searching for *\n");
11590 break;
11591 case NODE_TEST_NS:
11592 xmlGenericError(xmlGenericErrorContext,
11593 " searching for namespace %s\n",
11594 op->value5);
11595 break;
11596 case NODE_TEST_NAME:
11597 xmlGenericError(xmlGenericErrorContext,
11598 " searching for name %s\n", op->value5);
11599 if (op->value4)
11600 xmlGenericError(xmlGenericErrorContext,
11601 " with namespace %s\n", op->value4);
11602 break;
11603 }
11604 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11605 }
11606 #endif /* DEBUG_STEP */
11607
11608 /**
11609 * xmlXPathNodeSetFilter:
11610 * @ctxt: the XPath Parser context
11611 * @set: the node set to filter
11612 * @filterOpIndex: the index of the predicate/filter op
11613 * @minPos: minimum position in the filtered set (1-based)
11614 * @maxPos: maximum position in the filtered set (1-based)
11615 * @hasNsNodes: true if the node set may contain namespace nodes
11616 *
11617 * Filter a node set, keeping only nodes for which the predicate expression
11618 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11619 * filtered result.
11620 */
11621 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)11622 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11623 xmlNodeSetPtr set,
11624 int filterOpIndex,
11625 int minPos, int maxPos,
11626 int hasNsNodes)
11627 {
11628 xmlXPathContextPtr xpctxt;
11629 xmlNodePtr oldnode;
11630 xmlDocPtr olddoc;
11631 xmlXPathStepOpPtr filterOp;
11632 int oldcs, oldpp;
11633 int i, j, pos;
11634
11635 if ((set == NULL) || (set->nodeNr == 0))
11636 return;
11637
11638 /*
11639 * Check if the node set contains a sufficient number of nodes for
11640 * the requested range.
11641 */
11642 if (set->nodeNr < minPos) {
11643 xmlXPathNodeSetClear(set, hasNsNodes);
11644 return;
11645 }
11646
11647 xpctxt = ctxt->context;
11648 oldnode = xpctxt->node;
11649 olddoc = xpctxt->doc;
11650 oldcs = xpctxt->contextSize;
11651 oldpp = xpctxt->proximityPosition;
11652 filterOp = &ctxt->comp->steps[filterOpIndex];
11653
11654 xpctxt->contextSize = set->nodeNr;
11655
11656 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11657 xmlNodePtr node = set->nodeTab[i];
11658 int res;
11659
11660 xpctxt->node = node;
11661 xpctxt->proximityPosition = i + 1;
11662
11663 /*
11664 * Also set the xpath document in case things like
11665 * key() are evaluated in the predicate.
11666 *
11667 * TODO: Get real doc for namespace nodes.
11668 */
11669 if ((node->type != XML_NAMESPACE_DECL) &&
11670 (node->doc != NULL))
11671 xpctxt->doc = node->doc;
11672
11673 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11674
11675 if (ctxt->error != XPATH_EXPRESSION_OK)
11676 break;
11677 if (res < 0) {
11678 /* Shouldn't happen */
11679 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11680 break;
11681 }
11682
11683 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11684 if (i != j) {
11685 set->nodeTab[j] = node;
11686 set->nodeTab[i] = NULL;
11687 }
11688
11689 j += 1;
11690 } else {
11691 /* Remove the entry from the initial node set. */
11692 set->nodeTab[i] = NULL;
11693 if (node->type == XML_NAMESPACE_DECL)
11694 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11695 }
11696
11697 if (res != 0) {
11698 if (pos == maxPos) {
11699 i += 1;
11700 break;
11701 }
11702
11703 pos += 1;
11704 }
11705 }
11706
11707 /* Free remaining nodes. */
11708 if (hasNsNodes) {
11709 for (; i < set->nodeNr; i++) {
11710 xmlNodePtr node = set->nodeTab[i];
11711 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11712 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11713 }
11714 }
11715
11716 set->nodeNr = j;
11717
11718 /* If too many elements were removed, shrink table to preserve memory. */
11719 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11720 (set->nodeNr < set->nodeMax / 2)) {
11721 xmlNodePtr *tmp;
11722 int nodeMax = set->nodeNr;
11723
11724 if (nodeMax < XML_NODESET_DEFAULT)
11725 nodeMax = XML_NODESET_DEFAULT;
11726 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11727 nodeMax * sizeof(xmlNodePtr));
11728 if (tmp == NULL) {
11729 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11730 } else {
11731 set->nodeTab = tmp;
11732 set->nodeMax = nodeMax;
11733 }
11734 }
11735
11736 xpctxt->node = oldnode;
11737 xpctxt->doc = olddoc;
11738 xpctxt->contextSize = oldcs;
11739 xpctxt->proximityPosition = oldpp;
11740 }
11741
11742 #ifdef LIBXML_XPTR_LOCS_ENABLED
11743 /**
11744 * xmlXPathLocationSetFilter:
11745 * @ctxt: the XPath Parser context
11746 * @locset: the location set to filter
11747 * @filterOpIndex: the index of the predicate/filter op
11748 * @minPos: minimum position in the filtered set (1-based)
11749 * @maxPos: maximum position in the filtered set (1-based)
11750 *
11751 * Filter a location set, keeping only nodes for which the predicate
11752 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11753 * in the filtered result.
11754 */
11755 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)11756 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11757 xmlLocationSetPtr locset,
11758 int filterOpIndex,
11759 int minPos, int maxPos)
11760 {
11761 xmlXPathContextPtr xpctxt;
11762 xmlNodePtr oldnode;
11763 xmlDocPtr olddoc;
11764 xmlXPathStepOpPtr filterOp;
11765 int oldcs, oldpp;
11766 int i, j, pos;
11767
11768 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11769 return;
11770
11771 xpctxt = ctxt->context;
11772 oldnode = xpctxt->node;
11773 olddoc = xpctxt->doc;
11774 oldcs = xpctxt->contextSize;
11775 oldpp = xpctxt->proximityPosition;
11776 filterOp = &ctxt->comp->steps[filterOpIndex];
11777
11778 xpctxt->contextSize = locset->locNr;
11779
11780 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11781 xmlNodePtr contextNode = locset->locTab[i]->user;
11782 int res;
11783
11784 xpctxt->node = contextNode;
11785 xpctxt->proximityPosition = i + 1;
11786
11787 /*
11788 * Also set the xpath document in case things like
11789 * key() are evaluated in the predicate.
11790 *
11791 * TODO: Get real doc for namespace nodes.
11792 */
11793 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11794 (contextNode->doc != NULL))
11795 xpctxt->doc = contextNode->doc;
11796
11797 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11798
11799 if (ctxt->error != XPATH_EXPRESSION_OK)
11800 break;
11801 if (res < 0) {
11802 /* Shouldn't happen */
11803 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11804 break;
11805 }
11806
11807 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11808 if (i != j) {
11809 locset->locTab[j] = locset->locTab[i];
11810 locset->locTab[i] = NULL;
11811 }
11812
11813 j += 1;
11814 } else {
11815 /* Remove the entry from the initial location set. */
11816 xmlXPathFreeObject(locset->locTab[i]);
11817 locset->locTab[i] = NULL;
11818 }
11819
11820 if (res != 0) {
11821 if (pos == maxPos) {
11822 i += 1;
11823 break;
11824 }
11825
11826 pos += 1;
11827 }
11828 }
11829
11830 /* Free remaining nodes. */
11831 for (; i < locset->locNr; i++)
11832 xmlXPathFreeObject(locset->locTab[i]);
11833
11834 locset->locNr = j;
11835
11836 /* If too many elements were removed, shrink table to preserve memory. */
11837 if ((locset->locMax > XML_NODESET_DEFAULT) &&
11838 (locset->locNr < locset->locMax / 2)) {
11839 xmlXPathObjectPtr *tmp;
11840 int locMax = locset->locNr;
11841
11842 if (locMax < XML_NODESET_DEFAULT)
11843 locMax = XML_NODESET_DEFAULT;
11844 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11845 locMax * sizeof(xmlXPathObjectPtr));
11846 if (tmp == NULL) {
11847 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11848 } else {
11849 locset->locTab = tmp;
11850 locset->locMax = locMax;
11851 }
11852 }
11853
11854 xpctxt->node = oldnode;
11855 xpctxt->doc = olddoc;
11856 xpctxt->contextSize = oldcs;
11857 xpctxt->proximityPosition = oldpp;
11858 }
11859 #endif /* LIBXML_XPTR_LOCS_ENABLED */
11860
11861 /**
11862 * xmlXPathCompOpEvalPredicate:
11863 * @ctxt: the XPath Parser context
11864 * @op: the predicate op
11865 * @set: the node set to filter
11866 * @minPos: minimum position in the filtered set (1-based)
11867 * @maxPos: maximum position in the filtered set (1-based)
11868 * @hasNsNodes: true if the node set may contain namespace nodes
11869 *
11870 * Filter a node set, keeping only nodes for which the sequence of predicate
11871 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11872 * in the filtered result.
11873 */
11874 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)11875 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11876 xmlXPathStepOpPtr op,
11877 xmlNodeSetPtr set,
11878 int minPos, int maxPos,
11879 int hasNsNodes)
11880 {
11881 if (op->ch1 != -1) {
11882 xmlXPathCompExprPtr comp = ctxt->comp;
11883 /*
11884 * Process inner predicates first.
11885 */
11886 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11887 xmlGenericError(xmlGenericErrorContext,
11888 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11889 XP_ERROR(XPATH_INVALID_OPERAND);
11890 }
11891 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11892 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11893 ctxt->context->depth += 1;
11894 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11895 1, set->nodeNr, hasNsNodes);
11896 ctxt->context->depth -= 1;
11897 CHECK_ERROR;
11898 }
11899
11900 if (op->ch2 != -1)
11901 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11902 }
11903
11904 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11905 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11906 xmlXPathStepOpPtr op,
11907 int *maxPos)
11908 {
11909
11910 xmlXPathStepOpPtr exprOp;
11911
11912 /*
11913 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11914 */
11915
11916 /*
11917 * If not -1, then ch1 will point to:
11918 * 1) For predicates (XPATH_OP_PREDICATE):
11919 * - an inner predicate operator
11920 * 2) For filters (XPATH_OP_FILTER):
11921 * - an inner filter operator OR
11922 * - an expression selecting the node set.
11923 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11924 */
11925 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11926 return(0);
11927
11928 if (op->ch2 != -1) {
11929 exprOp = &ctxt->comp->steps[op->ch2];
11930 } else
11931 return(0);
11932
11933 if ((exprOp != NULL) &&
11934 (exprOp->op == XPATH_OP_VALUE) &&
11935 (exprOp->value4 != NULL) &&
11936 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11937 {
11938 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11939
11940 /*
11941 * We have a "[n]" predicate here.
11942 * TODO: Unfortunately this simplistic test here is not
11943 * able to detect a position() predicate in compound
11944 * expressions like "[@attr = 'a" and position() = 1],
11945 * and even not the usage of position() in
11946 * "[position() = 1]"; thus - obviously - a position-range,
11947 * like it "[position() < 5]", is also not detected.
11948 * Maybe we could rewrite the AST to ease the optimization.
11949 */
11950
11951 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11952 *maxPos = (int) floatval;
11953 if (floatval == (double) *maxPos)
11954 return(1);
11955 }
11956 }
11957 return(0);
11958 }
11959
11960 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11961 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11962 xmlXPathStepOpPtr op,
11963 xmlNodePtr * first, xmlNodePtr * last,
11964 int toBool)
11965 {
11966
11967 #define XP_TEST_HIT \
11968 if (hasAxisRange != 0) { \
11969 if (++pos == maxPos) { \
11970 if (addNode(seq, cur) < 0) \
11971 ctxt->error = XPATH_MEMORY_ERROR; \
11972 goto axis_range_end; } \
11973 } else { \
11974 if (addNode(seq, cur) < 0) \
11975 ctxt->error = XPATH_MEMORY_ERROR; \
11976 if (breakOnFirstHit) goto first_hit; }
11977
11978 #define XP_TEST_HIT_NS \
11979 if (hasAxisRange != 0) { \
11980 if (++pos == maxPos) { \
11981 hasNsNodes = 1; \
11982 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11983 ctxt->error = XPATH_MEMORY_ERROR; \
11984 goto axis_range_end; } \
11985 } else { \
11986 hasNsNodes = 1; \
11987 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11988 ctxt->error = XPATH_MEMORY_ERROR; \
11989 if (breakOnFirstHit) goto first_hit; }
11990
11991 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11992 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11993 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11994 const xmlChar *prefix = op->value4;
11995 const xmlChar *name = op->value5;
11996 const xmlChar *URI = NULL;
11997
11998 #ifdef DEBUG_STEP
11999 int nbMatches = 0, prevMatches = 0;
12000 #endif
12001 int total = 0, hasNsNodes = 0;
12002 /* The popped object holding the context nodes */
12003 xmlXPathObjectPtr obj;
12004 /* The set of context nodes for the node tests */
12005 xmlNodeSetPtr contextSeq;
12006 int contextIdx;
12007 xmlNodePtr contextNode;
12008 /* The final resulting node set wrt to all context nodes */
12009 xmlNodeSetPtr outSeq;
12010 /*
12011 * The temporary resulting node set wrt 1 context node.
12012 * Used to feed predicate evaluation.
12013 */
12014 xmlNodeSetPtr seq;
12015 xmlNodePtr cur;
12016 /* First predicate operator */
12017 xmlXPathStepOpPtr predOp;
12018 int maxPos; /* The requested position() (when a "[n]" predicate) */
12019 int hasPredicateRange, hasAxisRange, pos;
12020 int breakOnFirstHit;
12021
12022 xmlXPathTraversalFunction next = NULL;
12023 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12024 xmlXPathNodeSetMergeFunction mergeAndClear;
12025 xmlNodePtr oldContextNode;
12026 xmlXPathContextPtr xpctxt = ctxt->context;
12027
12028
12029 CHECK_TYPE0(XPATH_NODESET);
12030 obj = valuePop(ctxt);
12031 /*
12032 * Setup namespaces.
12033 */
12034 if (prefix != NULL) {
12035 URI = xmlXPathNsLookup(xpctxt, prefix);
12036 if (URI == NULL) {
12037 xmlXPathReleaseObject(xpctxt, obj);
12038 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12039 }
12040 }
12041 /*
12042 * Setup axis.
12043 *
12044 * MAYBE FUTURE TODO: merging optimizations:
12045 * - If the nodes to be traversed wrt to the initial nodes and
12046 * the current axis cannot overlap, then we could avoid searching
12047 * for duplicates during the merge.
12048 * But the question is how/when to evaluate if they cannot overlap.
12049 * Example: if we know that for two initial nodes, the one is
12050 * not in the ancestor-or-self axis of the other, then we could safely
12051 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12052 * the descendant-or-self axis.
12053 */
12054 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12055 switch (axis) {
12056 case AXIS_ANCESTOR:
12057 first = NULL;
12058 next = xmlXPathNextAncestor;
12059 break;
12060 case AXIS_ANCESTOR_OR_SELF:
12061 first = NULL;
12062 next = xmlXPathNextAncestorOrSelf;
12063 break;
12064 case AXIS_ATTRIBUTE:
12065 first = NULL;
12066 last = NULL;
12067 next = xmlXPathNextAttribute;
12068 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12069 break;
12070 case AXIS_CHILD:
12071 last = NULL;
12072 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12073 (type == NODE_TYPE_NODE))
12074 {
12075 /*
12076 * Optimization if an element node type is 'element'.
12077 */
12078 next = xmlXPathNextChildElement;
12079 } else
12080 next = xmlXPathNextChild;
12081 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12082 break;
12083 case AXIS_DESCENDANT:
12084 last = NULL;
12085 next = xmlXPathNextDescendant;
12086 break;
12087 case AXIS_DESCENDANT_OR_SELF:
12088 last = NULL;
12089 next = xmlXPathNextDescendantOrSelf;
12090 break;
12091 case AXIS_FOLLOWING:
12092 last = NULL;
12093 next = xmlXPathNextFollowing;
12094 break;
12095 case AXIS_FOLLOWING_SIBLING:
12096 last = NULL;
12097 next = xmlXPathNextFollowingSibling;
12098 break;
12099 case AXIS_NAMESPACE:
12100 first = NULL;
12101 last = NULL;
12102 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12103 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12104 break;
12105 case AXIS_PARENT:
12106 first = NULL;
12107 next = xmlXPathNextParent;
12108 break;
12109 case AXIS_PRECEDING:
12110 first = NULL;
12111 next = xmlXPathNextPrecedingInternal;
12112 break;
12113 case AXIS_PRECEDING_SIBLING:
12114 first = NULL;
12115 next = xmlXPathNextPrecedingSibling;
12116 break;
12117 case AXIS_SELF:
12118 first = NULL;
12119 last = NULL;
12120 next = xmlXPathNextSelf;
12121 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122 break;
12123 }
12124
12125 #ifdef DEBUG_STEP
12126 xmlXPathDebugDumpStepAxis(op,
12127 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12128 #endif
12129
12130 if (next == NULL) {
12131 xmlXPathReleaseObject(xpctxt, obj);
12132 return(0);
12133 }
12134 contextSeq = obj->nodesetval;
12135 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12136 xmlXPathReleaseObject(xpctxt, obj);
12137 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12138 return(0);
12139 }
12140 /*
12141 * Predicate optimization ---------------------------------------------
12142 * If this step has a last predicate, which contains a position(),
12143 * then we'll optimize (although not exactly "position()", but only
12144 * the short-hand form, i.e., "[n]".
12145 *
12146 * Example - expression "/foo[parent::bar][1]":
12147 *
12148 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12149 * ROOT -- op->ch1
12150 * PREDICATE -- op->ch2 (predOp)
12151 * PREDICATE -- predOp->ch1 = [parent::bar]
12152 * SORT
12153 * COLLECT 'parent' 'name' 'node' bar
12154 * NODE
12155 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12156 *
12157 */
12158 maxPos = 0;
12159 predOp = NULL;
12160 hasPredicateRange = 0;
12161 hasAxisRange = 0;
12162 if (op->ch2 != -1) {
12163 /*
12164 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12165 */
12166 predOp = &ctxt->comp->steps[op->ch2];
12167 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12168 if (predOp->ch1 != -1) {
12169 /*
12170 * Use the next inner predicate operator.
12171 */
12172 predOp = &ctxt->comp->steps[predOp->ch1];
12173 hasPredicateRange = 1;
12174 } else {
12175 /*
12176 * There's no other predicate than the [n] predicate.
12177 */
12178 predOp = NULL;
12179 hasAxisRange = 1;
12180 }
12181 }
12182 }
12183 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12184 /*
12185 * Axis traversal -----------------------------------------------------
12186 */
12187 /*
12188 * 2.3 Node Tests
12189 * - For the attribute axis, the principal node type is attribute.
12190 * - For the namespace axis, the principal node type is namespace.
12191 * - For other axes, the principal node type is element.
12192 *
12193 * A node test * is true for any node of the
12194 * principal node type. For example, child::* will
12195 * select all element children of the context node
12196 */
12197 oldContextNode = xpctxt->node;
12198 addNode = xmlXPathNodeSetAddUnique;
12199 outSeq = NULL;
12200 seq = NULL;
12201 contextNode = NULL;
12202 contextIdx = 0;
12203
12204
12205 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12206 (ctxt->error == XPATH_EXPRESSION_OK)) {
12207 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12208
12209 if (seq == NULL) {
12210 seq = xmlXPathNodeSetCreate(NULL);
12211 if (seq == NULL) {
12212 /* TODO: Propagate memory error. */
12213 total = 0;
12214 goto error;
12215 }
12216 }
12217 /*
12218 * Traverse the axis and test the nodes.
12219 */
12220 pos = 0;
12221 cur = NULL;
12222 hasNsNodes = 0;
12223 do {
12224 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12225 goto error;
12226
12227 cur = next(ctxt, cur);
12228 if (cur == NULL)
12229 break;
12230
12231 /*
12232 * QUESTION TODO: What does the "first" and "last" stuff do?
12233 */
12234 if ((first != NULL) && (*first != NULL)) {
12235 if (*first == cur)
12236 break;
12237 if (((total % 256) == 0) &&
12238 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12239 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12240 #else
12241 (xmlXPathCmpNodes(*first, cur) >= 0))
12242 #endif
12243 {
12244 break;
12245 }
12246 }
12247 if ((last != NULL) && (*last != NULL)) {
12248 if (*last == cur)
12249 break;
12250 if (((total % 256) == 0) &&
12251 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12252 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12253 #else
12254 (xmlXPathCmpNodes(cur, *last) >= 0))
12255 #endif
12256 {
12257 break;
12258 }
12259 }
12260
12261 total++;
12262
12263 #ifdef DEBUG_STEP
12264 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12265 #endif
12266
12267 switch (test) {
12268 case NODE_TEST_NONE:
12269 total = 0;
12270 STRANGE
12271 goto error;
12272 case NODE_TEST_TYPE:
12273 if (type == NODE_TYPE_NODE) {
12274 switch (cur->type) {
12275 case XML_DOCUMENT_NODE:
12276 case XML_HTML_DOCUMENT_NODE:
12277 case XML_ELEMENT_NODE:
12278 case XML_ATTRIBUTE_NODE:
12279 case XML_PI_NODE:
12280 case XML_COMMENT_NODE:
12281 case XML_CDATA_SECTION_NODE:
12282 case XML_TEXT_NODE:
12283 XP_TEST_HIT
12284 break;
12285 case XML_NAMESPACE_DECL: {
12286 if (axis == AXIS_NAMESPACE) {
12287 XP_TEST_HIT_NS
12288 } else {
12289 hasNsNodes = 1;
12290 XP_TEST_HIT
12291 }
12292 break;
12293 }
12294 default:
12295 break;
12296 }
12297 } else if (cur->type == (xmlElementType) type) {
12298 if (cur->type == XML_NAMESPACE_DECL)
12299 XP_TEST_HIT_NS
12300 else
12301 XP_TEST_HIT
12302 } else if ((type == NODE_TYPE_TEXT) &&
12303 (cur->type == XML_CDATA_SECTION_NODE))
12304 {
12305 XP_TEST_HIT
12306 }
12307 break;
12308 case NODE_TEST_PI:
12309 if ((cur->type == XML_PI_NODE) &&
12310 ((name == NULL) || xmlStrEqual(name, cur->name)))
12311 {
12312 XP_TEST_HIT
12313 }
12314 break;
12315 case NODE_TEST_ALL:
12316 if (axis == AXIS_ATTRIBUTE) {
12317 if (cur->type == XML_ATTRIBUTE_NODE)
12318 {
12319 if (prefix == NULL)
12320 {
12321 XP_TEST_HIT
12322 } else if ((cur->ns != NULL) &&
12323 (xmlStrEqual(URI, cur->ns->href)))
12324 {
12325 XP_TEST_HIT
12326 }
12327 }
12328 } else if (axis == AXIS_NAMESPACE) {
12329 if (cur->type == XML_NAMESPACE_DECL)
12330 {
12331 XP_TEST_HIT_NS
12332 }
12333 } else {
12334 if (cur->type == XML_ELEMENT_NODE) {
12335 if (prefix == NULL)
12336 {
12337 XP_TEST_HIT
12338
12339 } else if ((cur->ns != NULL) &&
12340 (xmlStrEqual(URI, cur->ns->href)))
12341 {
12342 XP_TEST_HIT
12343 }
12344 }
12345 }
12346 break;
12347 case NODE_TEST_NS:{
12348 TODO;
12349 break;
12350 }
12351 case NODE_TEST_NAME:
12352 if (axis == AXIS_ATTRIBUTE) {
12353 if (cur->type != XML_ATTRIBUTE_NODE)
12354 break;
12355 } else if (axis == AXIS_NAMESPACE) {
12356 if (cur->type != XML_NAMESPACE_DECL)
12357 break;
12358 } else {
12359 if (cur->type != XML_ELEMENT_NODE)
12360 break;
12361 }
12362 switch (cur->type) {
12363 case XML_ELEMENT_NODE:
12364 if (xmlStrEqual(name, cur->name)) {
12365 if (prefix == NULL) {
12366 if (cur->ns == NULL)
12367 {
12368 XP_TEST_HIT
12369 }
12370 } else {
12371 if ((cur->ns != NULL) &&
12372 (xmlStrEqual(URI, cur->ns->href)))
12373 {
12374 XP_TEST_HIT
12375 }
12376 }
12377 }
12378 break;
12379 case XML_ATTRIBUTE_NODE:{
12380 xmlAttrPtr attr = (xmlAttrPtr) cur;
12381
12382 if (xmlStrEqual(name, attr->name)) {
12383 if (prefix == NULL) {
12384 if ((attr->ns == NULL) ||
12385 (attr->ns->prefix == NULL))
12386 {
12387 XP_TEST_HIT
12388 }
12389 } else {
12390 if ((attr->ns != NULL) &&
12391 (xmlStrEqual(URI,
12392 attr->ns->href)))
12393 {
12394 XP_TEST_HIT
12395 }
12396 }
12397 }
12398 break;
12399 }
12400 case XML_NAMESPACE_DECL:
12401 if (cur->type == XML_NAMESPACE_DECL) {
12402 xmlNsPtr ns = (xmlNsPtr) cur;
12403
12404 if ((ns->prefix != NULL) && (name != NULL)
12405 && (xmlStrEqual(ns->prefix, name)))
12406 {
12407 XP_TEST_HIT_NS
12408 }
12409 }
12410 break;
12411 default:
12412 break;
12413 }
12414 break;
12415 } /* switch(test) */
12416 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12417
12418 goto apply_predicates;
12419
12420 axis_range_end: /* ----------------------------------------------------- */
12421 /*
12422 * We have a "/foo[n]", and position() = n was reached.
12423 * Note that we can have as well "/foo/::parent::foo[1]", so
12424 * a duplicate-aware merge is still needed.
12425 * Merge with the result.
12426 */
12427 if (outSeq == NULL) {
12428 outSeq = seq;
12429 seq = NULL;
12430 } else
12431 /* TODO: Check memory error. */
12432 outSeq = mergeAndClear(outSeq, seq);
12433 /*
12434 * Break if only a true/false result was requested.
12435 */
12436 if (toBool)
12437 break;
12438 continue;
12439
12440 first_hit: /* ---------------------------------------------------------- */
12441 /*
12442 * Break if only a true/false result was requested and
12443 * no predicates existed and a node test succeeded.
12444 */
12445 if (outSeq == NULL) {
12446 outSeq = seq;
12447 seq = NULL;
12448 } else
12449 /* TODO: Check memory error. */
12450 outSeq = mergeAndClear(outSeq, seq);
12451 break;
12452
12453 #ifdef DEBUG_STEP
12454 if (seq != NULL)
12455 nbMatches += seq->nodeNr;
12456 #endif
12457
12458 apply_predicates: /* --------------------------------------------------- */
12459 if (ctxt->error != XPATH_EXPRESSION_OK)
12460 goto error;
12461
12462 /*
12463 * Apply predicates.
12464 */
12465 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12466 /*
12467 * E.g. when we have a "/foo[some expression][n]".
12468 */
12469 /*
12470 * QUESTION TODO: The old predicate evaluation took into
12471 * account location-sets.
12472 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12473 * Do we expect such a set here?
12474 * All what I learned now from the evaluation semantics
12475 * does not indicate that a location-set will be processed
12476 * here, so this looks OK.
12477 */
12478 /*
12479 * Iterate over all predicates, starting with the outermost
12480 * predicate.
12481 * TODO: Problem: we cannot execute the inner predicates first
12482 * since we cannot go back *up* the operator tree!
12483 * Options we have:
12484 * 1) Use of recursive functions (like is it currently done
12485 * via xmlXPathCompOpEval())
12486 * 2) Add a predicate evaluation information stack to the
12487 * context struct
12488 * 3) Change the way the operators are linked; we need a
12489 * "parent" field on xmlXPathStepOp
12490 *
12491 * For the moment, I'll try to solve this with a recursive
12492 * function: xmlXPathCompOpEvalPredicate().
12493 */
12494 if (hasPredicateRange != 0)
12495 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12496 hasNsNodes);
12497 else
12498 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12499 hasNsNodes);
12500
12501 if (ctxt->error != XPATH_EXPRESSION_OK) {
12502 total = 0;
12503 goto error;
12504 }
12505 }
12506
12507 if (seq->nodeNr > 0) {
12508 /*
12509 * Add to result set.
12510 */
12511 if (outSeq == NULL) {
12512 outSeq = seq;
12513 seq = NULL;
12514 } else {
12515 /* TODO: Check memory error. */
12516 outSeq = mergeAndClear(outSeq, seq);
12517 }
12518
12519 if (toBool)
12520 break;
12521 }
12522 }
12523
12524 error:
12525 if ((obj->boolval) && (obj->user != NULL)) {
12526 /*
12527 * QUESTION TODO: What does this do and why?
12528 * TODO: Do we have to do this also for the "error"
12529 * cleanup further down?
12530 */
12531 ctxt->value->boolval = 1;
12532 ctxt->value->user = obj->user;
12533 obj->user = NULL;
12534 obj->boolval = 0;
12535 }
12536 xmlXPathReleaseObject(xpctxt, obj);
12537
12538 /*
12539 * Ensure we return at least an empty set.
12540 */
12541 if (outSeq == NULL) {
12542 if ((seq != NULL) && (seq->nodeNr == 0))
12543 outSeq = seq;
12544 else
12545 /* TODO: Check memory error. */
12546 outSeq = xmlXPathNodeSetCreate(NULL);
12547 }
12548 if ((seq != NULL) && (seq != outSeq)) {
12549 xmlXPathFreeNodeSet(seq);
12550 }
12551 /*
12552 * Hand over the result. Better to push the set also in
12553 * case of errors.
12554 */
12555 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12556 /*
12557 * Reset the context node.
12558 */
12559 xpctxt->node = oldContextNode;
12560 /*
12561 * When traversing the namespace axis in "toBool" mode, it's
12562 * possible that tmpNsList wasn't freed.
12563 */
12564 if (xpctxt->tmpNsList != NULL) {
12565 xmlFree(xpctxt->tmpNsList);
12566 xpctxt->tmpNsList = NULL;
12567 }
12568
12569 #ifdef DEBUG_STEP
12570 xmlGenericError(xmlGenericErrorContext,
12571 "\nExamined %d nodes, found %d nodes at that step\n",
12572 total, nbMatches);
12573 #endif
12574
12575 return(total);
12576 }
12577
12578 static int
12579 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12580 xmlXPathStepOpPtr op, xmlNodePtr * first);
12581
12582 /**
12583 * xmlXPathCompOpEvalFirst:
12584 * @ctxt: the XPath parser context with the compiled expression
12585 * @op: an XPath compiled operation
12586 * @first: the first elem found so far
12587 *
12588 * Evaluate the Precompiled XPath operation searching only the first
12589 * element in document order
12590 *
12591 * Returns the number of examined objects.
12592 */
12593 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12594 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12595 xmlXPathStepOpPtr op, xmlNodePtr * first)
12596 {
12597 int total = 0, cur;
12598 xmlXPathCompExprPtr comp;
12599 xmlXPathObjectPtr arg1, arg2;
12600
12601 CHECK_ERROR0;
12602 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12603 return(0);
12604 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12605 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12606 ctxt->context->depth += 1;
12607 comp = ctxt->comp;
12608 switch (op->op) {
12609 case XPATH_OP_END:
12610 break;
12611 case XPATH_OP_UNION:
12612 total =
12613 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12614 first);
12615 CHECK_ERROR0;
12616 if ((ctxt->value != NULL)
12617 && (ctxt->value->type == XPATH_NODESET)
12618 && (ctxt->value->nodesetval != NULL)
12619 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12620 /*
12621 * limit tree traversing to first node in the result
12622 */
12623 /*
12624 * OPTIMIZE TODO: This implicitly sorts
12625 * the result, even if not needed. E.g. if the argument
12626 * of the count() function, no sorting is needed.
12627 * OPTIMIZE TODO: How do we know if the node-list wasn't
12628 * already sorted?
12629 */
12630 if (ctxt->value->nodesetval->nodeNr > 1)
12631 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12632 *first = ctxt->value->nodesetval->nodeTab[0];
12633 }
12634 cur =
12635 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12636 first);
12637 CHECK_ERROR0;
12638
12639 arg2 = valuePop(ctxt);
12640 arg1 = valuePop(ctxt);
12641 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12642 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12643 xmlXPathReleaseObject(ctxt->context, arg1);
12644 xmlXPathReleaseObject(ctxt->context, arg2);
12645 XP_ERROR0(XPATH_INVALID_TYPE);
12646 }
12647 if ((ctxt->context->opLimit != 0) &&
12648 (((arg1->nodesetval != NULL) &&
12649 (xmlXPathCheckOpLimit(ctxt,
12650 arg1->nodesetval->nodeNr) < 0)) ||
12651 ((arg2->nodesetval != NULL) &&
12652 (xmlXPathCheckOpLimit(ctxt,
12653 arg2->nodesetval->nodeNr) < 0)))) {
12654 xmlXPathReleaseObject(ctxt->context, arg1);
12655 xmlXPathReleaseObject(ctxt->context, arg2);
12656 break;
12657 }
12658
12659 /* TODO: Check memory error. */
12660 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12661 arg2->nodesetval);
12662 valuePush(ctxt, arg1);
12663 xmlXPathReleaseObject(ctxt->context, arg2);
12664 /* optimizer */
12665 if (total > cur)
12666 xmlXPathCompSwap(op);
12667 total += cur;
12668 break;
12669 case XPATH_OP_ROOT:
12670 xmlXPathRoot(ctxt);
12671 break;
12672 case XPATH_OP_NODE:
12673 if (op->ch1 != -1)
12674 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12675 CHECK_ERROR0;
12676 if (op->ch2 != -1)
12677 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12678 CHECK_ERROR0;
12679 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12680 ctxt->context->node));
12681 break;
12682 case XPATH_OP_COLLECT:{
12683 if (op->ch1 == -1)
12684 break;
12685
12686 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12687 CHECK_ERROR0;
12688
12689 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12690 break;
12691 }
12692 case XPATH_OP_VALUE:
12693 valuePush(ctxt,
12694 xmlXPathCacheObjectCopy(ctxt->context,
12695 (xmlXPathObjectPtr) op->value4));
12696 break;
12697 case XPATH_OP_SORT:
12698 if (op->ch1 != -1)
12699 total +=
12700 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12701 first);
12702 CHECK_ERROR0;
12703 if ((ctxt->value != NULL)
12704 && (ctxt->value->type == XPATH_NODESET)
12705 && (ctxt->value->nodesetval != NULL)
12706 && (ctxt->value->nodesetval->nodeNr > 1))
12707 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12708 break;
12709 #ifdef XP_OPTIMIZED_FILTER_FIRST
12710 case XPATH_OP_FILTER:
12711 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12712 break;
12713 #endif
12714 default:
12715 total += xmlXPathCompOpEval(ctxt, op);
12716 break;
12717 }
12718
12719 ctxt->context->depth -= 1;
12720 return(total);
12721 }
12722
12723 /**
12724 * xmlXPathCompOpEvalLast:
12725 * @ctxt: the XPath parser context with the compiled expression
12726 * @op: an XPath compiled operation
12727 * @last: the last elem found so far
12728 *
12729 * Evaluate the Precompiled XPath operation searching only the last
12730 * element in document order
12731 *
12732 * Returns the number of nodes traversed
12733 */
12734 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12735 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12736 xmlNodePtr * last)
12737 {
12738 int total = 0, cur;
12739 xmlXPathCompExprPtr comp;
12740 xmlXPathObjectPtr arg1, arg2;
12741
12742 CHECK_ERROR0;
12743 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12744 return(0);
12745 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12746 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12747 ctxt->context->depth += 1;
12748 comp = ctxt->comp;
12749 switch (op->op) {
12750 case XPATH_OP_END:
12751 break;
12752 case XPATH_OP_UNION:
12753 total =
12754 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12755 CHECK_ERROR0;
12756 if ((ctxt->value != NULL)
12757 && (ctxt->value->type == XPATH_NODESET)
12758 && (ctxt->value->nodesetval != NULL)
12759 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12760 /*
12761 * limit tree traversing to first node in the result
12762 */
12763 if (ctxt->value->nodesetval->nodeNr > 1)
12764 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12765 *last =
12766 ctxt->value->nodesetval->nodeTab[ctxt->value->
12767 nodesetval->nodeNr -
12768 1];
12769 }
12770 cur =
12771 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12772 CHECK_ERROR0;
12773 if ((ctxt->value != NULL)
12774 && (ctxt->value->type == XPATH_NODESET)
12775 && (ctxt->value->nodesetval != NULL)
12776 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12777 }
12778
12779 arg2 = valuePop(ctxt);
12780 arg1 = valuePop(ctxt);
12781 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12782 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12783 xmlXPathReleaseObject(ctxt->context, arg1);
12784 xmlXPathReleaseObject(ctxt->context, arg2);
12785 XP_ERROR0(XPATH_INVALID_TYPE);
12786 }
12787 if ((ctxt->context->opLimit != 0) &&
12788 (((arg1->nodesetval != NULL) &&
12789 (xmlXPathCheckOpLimit(ctxt,
12790 arg1->nodesetval->nodeNr) < 0)) ||
12791 ((arg2->nodesetval != NULL) &&
12792 (xmlXPathCheckOpLimit(ctxt,
12793 arg2->nodesetval->nodeNr) < 0)))) {
12794 xmlXPathReleaseObject(ctxt->context, arg1);
12795 xmlXPathReleaseObject(ctxt->context, arg2);
12796 break;
12797 }
12798
12799 /* TODO: Check memory error. */
12800 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12801 arg2->nodesetval);
12802 valuePush(ctxt, arg1);
12803 xmlXPathReleaseObject(ctxt->context, arg2);
12804 /* optimizer */
12805 if (total > cur)
12806 xmlXPathCompSwap(op);
12807 total += cur;
12808 break;
12809 case XPATH_OP_ROOT:
12810 xmlXPathRoot(ctxt);
12811 break;
12812 case XPATH_OP_NODE:
12813 if (op->ch1 != -1)
12814 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12815 CHECK_ERROR0;
12816 if (op->ch2 != -1)
12817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12818 CHECK_ERROR0;
12819 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12820 ctxt->context->node));
12821 break;
12822 case XPATH_OP_COLLECT:{
12823 if (op->ch1 == -1)
12824 break;
12825
12826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12827 CHECK_ERROR0;
12828
12829 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12830 break;
12831 }
12832 case XPATH_OP_VALUE:
12833 valuePush(ctxt,
12834 xmlXPathCacheObjectCopy(ctxt->context,
12835 (xmlXPathObjectPtr) op->value4));
12836 break;
12837 case XPATH_OP_SORT:
12838 if (op->ch1 != -1)
12839 total +=
12840 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12841 last);
12842 CHECK_ERROR0;
12843 if ((ctxt->value != NULL)
12844 && (ctxt->value->type == XPATH_NODESET)
12845 && (ctxt->value->nodesetval != NULL)
12846 && (ctxt->value->nodesetval->nodeNr > 1))
12847 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12848 break;
12849 default:
12850 total += xmlXPathCompOpEval(ctxt, op);
12851 break;
12852 }
12853
12854 ctxt->context->depth -= 1;
12855 return (total);
12856 }
12857
12858 #ifdef XP_OPTIMIZED_FILTER_FIRST
12859 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12860 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12861 xmlXPathStepOpPtr op, xmlNodePtr * first)
12862 {
12863 int total = 0;
12864 xmlXPathCompExprPtr comp;
12865 xmlNodeSetPtr set;
12866
12867 CHECK_ERROR0;
12868 comp = ctxt->comp;
12869 /*
12870 * Optimization for ()[last()] selection i.e. the last elem
12871 */
12872 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12873 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12874 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12875 int f = comp->steps[op->ch2].ch1;
12876
12877 if ((f != -1) &&
12878 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12879 (comp->steps[f].value5 == NULL) &&
12880 (comp->steps[f].value == 0) &&
12881 (comp->steps[f].value4 != NULL) &&
12882 (xmlStrEqual
12883 (comp->steps[f].value4, BAD_CAST "last"))) {
12884 xmlNodePtr last = NULL;
12885
12886 total +=
12887 xmlXPathCompOpEvalLast(ctxt,
12888 &comp->steps[op->ch1],
12889 &last);
12890 CHECK_ERROR0;
12891 /*
12892 * The nodeset should be in document order,
12893 * Keep only the last value
12894 */
12895 if ((ctxt->value != NULL) &&
12896 (ctxt->value->type == XPATH_NODESET) &&
12897 (ctxt->value->nodesetval != NULL) &&
12898 (ctxt->value->nodesetval->nodeTab != NULL) &&
12899 (ctxt->value->nodesetval->nodeNr > 1)) {
12900 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12901 *first = *(ctxt->value->nodesetval->nodeTab);
12902 }
12903 return (total);
12904 }
12905 }
12906
12907 if (op->ch1 != -1)
12908 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12909 CHECK_ERROR0;
12910 if (op->ch2 == -1)
12911 return (total);
12912 if (ctxt->value == NULL)
12913 return (total);
12914
12915 #ifdef LIBXML_XPTR_LOCS_ENABLED
12916 /*
12917 * Hum are we filtering the result of an XPointer expression
12918 */
12919 if (ctxt->value->type == XPATH_LOCATIONSET) {
12920 xmlLocationSetPtr locset = ctxt->value->user;
12921
12922 if (locset != NULL) {
12923 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12924 if (locset->locNr > 0)
12925 *first = (xmlNodePtr) locset->locTab[0]->user;
12926 }
12927
12928 return (total);
12929 }
12930 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12931
12932 CHECK_TYPE0(XPATH_NODESET);
12933 set = ctxt->value->nodesetval;
12934 if (set != NULL) {
12935 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12936 if (set->nodeNr > 0)
12937 *first = set->nodeTab[0];
12938 }
12939
12940 return (total);
12941 }
12942 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12943
12944 /**
12945 * xmlXPathCompOpEval:
12946 * @ctxt: the XPath parser context with the compiled expression
12947 * @op: an XPath compiled operation
12948 *
12949 * Evaluate the Precompiled XPath operation
12950 * Returns the number of nodes traversed
12951 */
12952 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)12953 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12954 {
12955 int total = 0;
12956 int equal, ret;
12957 xmlXPathCompExprPtr comp;
12958 xmlXPathObjectPtr arg1, arg2;
12959
12960 CHECK_ERROR0;
12961 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12962 return(0);
12963 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12964 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12965 ctxt->context->depth += 1;
12966 comp = ctxt->comp;
12967 switch (op->op) {
12968 case XPATH_OP_END:
12969 break;
12970 case XPATH_OP_AND:
12971 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12972 CHECK_ERROR0;
12973 xmlXPathBooleanFunction(ctxt, 1);
12974 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12975 break;
12976 arg2 = valuePop(ctxt);
12977 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12978 if (ctxt->error) {
12979 xmlXPathFreeObject(arg2);
12980 break;
12981 }
12982 xmlXPathBooleanFunction(ctxt, 1);
12983 if (ctxt->value != NULL)
12984 ctxt->value->boolval &= arg2->boolval;
12985 xmlXPathReleaseObject(ctxt->context, arg2);
12986 break;
12987 case XPATH_OP_OR:
12988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12989 CHECK_ERROR0;
12990 xmlXPathBooleanFunction(ctxt, 1);
12991 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12992 break;
12993 arg2 = valuePop(ctxt);
12994 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12995 if (ctxt->error) {
12996 xmlXPathFreeObject(arg2);
12997 break;
12998 }
12999 xmlXPathBooleanFunction(ctxt, 1);
13000 if (ctxt->value != NULL)
13001 ctxt->value->boolval |= arg2->boolval;
13002 xmlXPathReleaseObject(ctxt->context, arg2);
13003 break;
13004 case XPATH_OP_EQUAL:
13005 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13006 CHECK_ERROR0;
13007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13008 CHECK_ERROR0;
13009 if (op->value)
13010 equal = xmlXPathEqualValues(ctxt);
13011 else
13012 equal = xmlXPathNotEqualValues(ctxt);
13013 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13014 break;
13015 case XPATH_OP_CMP:
13016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13017 CHECK_ERROR0;
13018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13019 CHECK_ERROR0;
13020 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13021 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13022 break;
13023 case XPATH_OP_PLUS:
13024 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13025 CHECK_ERROR0;
13026 if (op->ch2 != -1) {
13027 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13028 }
13029 CHECK_ERROR0;
13030 if (op->value == 0)
13031 xmlXPathSubValues(ctxt);
13032 else if (op->value == 1)
13033 xmlXPathAddValues(ctxt);
13034 else if (op->value == 2)
13035 xmlXPathValueFlipSign(ctxt);
13036 else if (op->value == 3) {
13037 CAST_TO_NUMBER;
13038 CHECK_TYPE0(XPATH_NUMBER);
13039 }
13040 break;
13041 case XPATH_OP_MULT:
13042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13043 CHECK_ERROR0;
13044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13045 CHECK_ERROR0;
13046 if (op->value == 0)
13047 xmlXPathMultValues(ctxt);
13048 else if (op->value == 1)
13049 xmlXPathDivValues(ctxt);
13050 else if (op->value == 2)
13051 xmlXPathModValues(ctxt);
13052 break;
13053 case XPATH_OP_UNION:
13054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13055 CHECK_ERROR0;
13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13057 CHECK_ERROR0;
13058
13059 arg2 = valuePop(ctxt);
13060 arg1 = valuePop(ctxt);
13061 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13062 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13063 xmlXPathReleaseObject(ctxt->context, arg1);
13064 xmlXPathReleaseObject(ctxt->context, arg2);
13065 XP_ERROR0(XPATH_INVALID_TYPE);
13066 }
13067 if ((ctxt->context->opLimit != 0) &&
13068 (((arg1->nodesetval != NULL) &&
13069 (xmlXPathCheckOpLimit(ctxt,
13070 arg1->nodesetval->nodeNr) < 0)) ||
13071 ((arg2->nodesetval != NULL) &&
13072 (xmlXPathCheckOpLimit(ctxt,
13073 arg2->nodesetval->nodeNr) < 0)))) {
13074 xmlXPathReleaseObject(ctxt->context, arg1);
13075 xmlXPathReleaseObject(ctxt->context, arg2);
13076 break;
13077 }
13078
13079 if ((arg1->nodesetval == NULL) ||
13080 ((arg2->nodesetval != NULL) &&
13081 (arg2->nodesetval->nodeNr != 0)))
13082 {
13083 /* TODO: Check memory error. */
13084 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13085 arg2->nodesetval);
13086 }
13087
13088 valuePush(ctxt, arg1);
13089 xmlXPathReleaseObject(ctxt->context, arg2);
13090 break;
13091 case XPATH_OP_ROOT:
13092 xmlXPathRoot(ctxt);
13093 break;
13094 case XPATH_OP_NODE:
13095 if (op->ch1 != -1)
13096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13097 CHECK_ERROR0;
13098 if (op->ch2 != -1)
13099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13100 CHECK_ERROR0;
13101 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13102 ctxt->context->node));
13103 break;
13104 case XPATH_OP_COLLECT:{
13105 if (op->ch1 == -1)
13106 break;
13107
13108 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13109 CHECK_ERROR0;
13110
13111 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13112 break;
13113 }
13114 case XPATH_OP_VALUE:
13115 valuePush(ctxt,
13116 xmlXPathCacheObjectCopy(ctxt->context,
13117 (xmlXPathObjectPtr) op->value4));
13118 break;
13119 case XPATH_OP_VARIABLE:{
13120 xmlXPathObjectPtr val;
13121
13122 if (op->ch1 != -1)
13123 total +=
13124 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13125 if (op->value5 == NULL) {
13126 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13127 if (val == NULL)
13128 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13129 valuePush(ctxt, val);
13130 } else {
13131 const xmlChar *URI;
13132
13133 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13134 if (URI == NULL) {
13135 xmlGenericError(xmlGenericErrorContext,
13136 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13137 (char *) op->value4, (char *)op->value5);
13138 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13139 break;
13140 }
13141 val = xmlXPathVariableLookupNS(ctxt->context,
13142 op->value4, URI);
13143 if (val == NULL)
13144 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13145 valuePush(ctxt, val);
13146 }
13147 break;
13148 }
13149 case XPATH_OP_FUNCTION:{
13150 xmlXPathFunction func;
13151 const xmlChar *oldFunc, *oldFuncURI;
13152 int i;
13153 int frame;
13154
13155 frame = xmlXPathSetFrame(ctxt);
13156 if (op->ch1 != -1) {
13157 total +=
13158 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13159 if (ctxt->error != XPATH_EXPRESSION_OK) {
13160 xmlXPathPopFrame(ctxt, frame);
13161 break;
13162 }
13163 }
13164 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13165 xmlGenericError(xmlGenericErrorContext,
13166 "xmlXPathCompOpEval: parameter error\n");
13167 ctxt->error = XPATH_INVALID_OPERAND;
13168 xmlXPathPopFrame(ctxt, frame);
13169 break;
13170 }
13171 for (i = 0; i < op->value; i++) {
13172 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13173 xmlGenericError(xmlGenericErrorContext,
13174 "xmlXPathCompOpEval: parameter error\n");
13175 ctxt->error = XPATH_INVALID_OPERAND;
13176 xmlXPathPopFrame(ctxt, frame);
13177 break;
13178 }
13179 }
13180 if (op->cache != NULL)
13181 func = op->cache;
13182 else {
13183 const xmlChar *URI = NULL;
13184
13185 if (op->value5 == NULL)
13186 func =
13187 xmlXPathFunctionLookup(ctxt->context,
13188 op->value4);
13189 else {
13190 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13191 if (URI == NULL) {
13192 xmlGenericError(xmlGenericErrorContext,
13193 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13194 (char *)op->value4, (char *)op->value5);
13195 xmlXPathPopFrame(ctxt, frame);
13196 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13197 break;
13198 }
13199 func = xmlXPathFunctionLookupNS(ctxt->context,
13200 op->value4, URI);
13201 }
13202 if (func == NULL) {
13203 xmlGenericError(xmlGenericErrorContext,
13204 "xmlXPathCompOpEval: function %s not found\n",
13205 (char *)op->value4);
13206 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13207 }
13208 op->cache = func;
13209 op->cacheURI = (void *) URI;
13210 }
13211 oldFunc = ctxt->context->function;
13212 oldFuncURI = ctxt->context->functionURI;
13213 ctxt->context->function = op->value4;
13214 ctxt->context->functionURI = op->cacheURI;
13215 func(ctxt, op->value);
13216 ctxt->context->function = oldFunc;
13217 ctxt->context->functionURI = oldFuncURI;
13218 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13219 (ctxt->valueNr != ctxt->valueFrame + 1))
13220 XP_ERROR0(XPATH_STACK_ERROR);
13221 xmlXPathPopFrame(ctxt, frame);
13222 break;
13223 }
13224 case XPATH_OP_ARG:
13225 if (op->ch1 != -1) {
13226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13227 CHECK_ERROR0;
13228 }
13229 if (op->ch2 != -1) {
13230 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13231 CHECK_ERROR0;
13232 }
13233 break;
13234 case XPATH_OP_PREDICATE:
13235 case XPATH_OP_FILTER:{
13236 xmlNodeSetPtr set;
13237
13238 /*
13239 * Optimization for ()[1] selection i.e. the first elem
13240 */
13241 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13242 #ifdef XP_OPTIMIZED_FILTER_FIRST
13243 /*
13244 * FILTER TODO: Can we assume that the inner processing
13245 * will result in an ordered list if we have an
13246 * XPATH_OP_FILTER?
13247 * What about an additional field or flag on
13248 * xmlXPathObject like @sorted ? This way we wouldn't need
13249 * to assume anything, so it would be more robust and
13250 * easier to optimize.
13251 */
13252 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13253 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13254 #else
13255 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13256 #endif
13257 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13258 xmlXPathObjectPtr val;
13259
13260 val = comp->steps[op->ch2].value4;
13261 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13262 (val->floatval == 1.0)) {
13263 xmlNodePtr first = NULL;
13264
13265 total +=
13266 xmlXPathCompOpEvalFirst(ctxt,
13267 &comp->steps[op->ch1],
13268 &first);
13269 CHECK_ERROR0;
13270 /*
13271 * The nodeset should be in document order,
13272 * Keep only the first value
13273 */
13274 if ((ctxt->value != NULL) &&
13275 (ctxt->value->type == XPATH_NODESET) &&
13276 (ctxt->value->nodesetval != NULL) &&
13277 (ctxt->value->nodesetval->nodeNr > 1))
13278 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13279 1, 1);
13280 break;
13281 }
13282 }
13283 /*
13284 * Optimization for ()[last()] selection i.e. the last elem
13285 */
13286 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13287 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13288 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13289 int f = comp->steps[op->ch2].ch1;
13290
13291 if ((f != -1) &&
13292 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13293 (comp->steps[f].value5 == NULL) &&
13294 (comp->steps[f].value == 0) &&
13295 (comp->steps[f].value4 != NULL) &&
13296 (xmlStrEqual
13297 (comp->steps[f].value4, BAD_CAST "last"))) {
13298 xmlNodePtr last = NULL;
13299
13300 total +=
13301 xmlXPathCompOpEvalLast(ctxt,
13302 &comp->steps[op->ch1],
13303 &last);
13304 CHECK_ERROR0;
13305 /*
13306 * The nodeset should be in document order,
13307 * Keep only the last value
13308 */
13309 if ((ctxt->value != NULL) &&
13310 (ctxt->value->type == XPATH_NODESET) &&
13311 (ctxt->value->nodesetval != NULL) &&
13312 (ctxt->value->nodesetval->nodeTab != NULL) &&
13313 (ctxt->value->nodesetval->nodeNr > 1))
13314 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13315 break;
13316 }
13317 }
13318 /*
13319 * Process inner predicates first.
13320 * Example "index[parent::book][1]":
13321 * ...
13322 * PREDICATE <-- we are here "[1]"
13323 * PREDICATE <-- process "[parent::book]" first
13324 * SORT
13325 * COLLECT 'parent' 'name' 'node' book
13326 * NODE
13327 * ELEM Object is a number : 1
13328 */
13329 if (op->ch1 != -1)
13330 total +=
13331 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13332 CHECK_ERROR0;
13333 if (op->ch2 == -1)
13334 break;
13335 if (ctxt->value == NULL)
13336 break;
13337
13338 #ifdef LIBXML_XPTR_LOCS_ENABLED
13339 /*
13340 * Hum are we filtering the result of an XPointer expression
13341 */
13342 if (ctxt->value->type == XPATH_LOCATIONSET) {
13343 xmlLocationSetPtr locset = ctxt->value->user;
13344 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13345 1, locset->locNr);
13346 break;
13347 }
13348 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13349
13350 CHECK_TYPE0(XPATH_NODESET);
13351 set = ctxt->value->nodesetval;
13352 if (set != NULL)
13353 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13354 1, set->nodeNr, 1);
13355 break;
13356 }
13357 case XPATH_OP_SORT:
13358 if (op->ch1 != -1)
13359 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13360 CHECK_ERROR0;
13361 if ((ctxt->value != NULL) &&
13362 (ctxt->value->type == XPATH_NODESET) &&
13363 (ctxt->value->nodesetval != NULL) &&
13364 (ctxt->value->nodesetval->nodeNr > 1))
13365 {
13366 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13367 }
13368 break;
13369 #ifdef LIBXML_XPTR_LOCS_ENABLED
13370 case XPATH_OP_RANGETO:{
13371 xmlXPathObjectPtr range;
13372 xmlXPathObjectPtr res, obj;
13373 xmlXPathObjectPtr tmp;
13374 xmlLocationSetPtr newlocset = NULL;
13375 xmlLocationSetPtr oldlocset;
13376 xmlNodeSetPtr oldset;
13377 xmlNodePtr oldnode = ctxt->context->node;
13378 int oldcs = ctxt->context->contextSize;
13379 int oldpp = ctxt->context->proximityPosition;
13380 int i, j;
13381
13382 if (op->ch1 != -1) {
13383 total +=
13384 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13385 CHECK_ERROR0;
13386 }
13387 if (ctxt->value == NULL) {
13388 XP_ERROR0(XPATH_INVALID_OPERAND);
13389 }
13390 if (op->ch2 == -1)
13391 break;
13392
13393 if (ctxt->value->type == XPATH_LOCATIONSET) {
13394 /*
13395 * Extract the old locset, and then evaluate the result of the
13396 * expression for all the element in the locset. use it to grow
13397 * up a new locset.
13398 */
13399 CHECK_TYPE0(XPATH_LOCATIONSET);
13400
13401 if ((ctxt->value->user == NULL) ||
13402 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13403 break;
13404
13405 obj = valuePop(ctxt);
13406 oldlocset = obj->user;
13407
13408 newlocset = xmlXPtrLocationSetCreate(NULL);
13409
13410 for (i = 0; i < oldlocset->locNr; i++) {
13411 /*
13412 * Run the evaluation with a node list made of a
13413 * single item in the nodelocset.
13414 */
13415 ctxt->context->node = oldlocset->locTab[i]->user;
13416 ctxt->context->contextSize = oldlocset->locNr;
13417 ctxt->context->proximityPosition = i + 1;
13418 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13419 ctxt->context->node);
13420 valuePush(ctxt, tmp);
13421
13422 if (op->ch2 != -1)
13423 total +=
13424 xmlXPathCompOpEval(ctxt,
13425 &comp->steps[op->ch2]);
13426 if (ctxt->error != XPATH_EXPRESSION_OK) {
13427 xmlXPtrFreeLocationSet(newlocset);
13428 goto rangeto_error;
13429 }
13430
13431 res = valuePop(ctxt);
13432 if (res->type == XPATH_LOCATIONSET) {
13433 xmlLocationSetPtr rloc =
13434 (xmlLocationSetPtr)res->user;
13435 for (j=0; j<rloc->locNr; j++) {
13436 range = xmlXPtrNewRange(
13437 oldlocset->locTab[i]->user,
13438 oldlocset->locTab[i]->index,
13439 rloc->locTab[j]->user2,
13440 rloc->locTab[j]->index2);
13441 if (range != NULL) {
13442 xmlXPtrLocationSetAdd(newlocset, range);
13443 }
13444 }
13445 } else {
13446 range = xmlXPtrNewRangeNodeObject(
13447 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13448 if (range != NULL) {
13449 xmlXPtrLocationSetAdd(newlocset,range);
13450 }
13451 }
13452
13453 /*
13454 * Cleanup
13455 */
13456 if (res != NULL) {
13457 xmlXPathReleaseObject(ctxt->context, res);
13458 }
13459 if (ctxt->value == tmp) {
13460 res = valuePop(ctxt);
13461 xmlXPathReleaseObject(ctxt->context, res);
13462 }
13463 }
13464 } else { /* Not a location set */
13465 CHECK_TYPE0(XPATH_NODESET);
13466 obj = valuePop(ctxt);
13467 oldset = obj->nodesetval;
13468
13469 newlocset = xmlXPtrLocationSetCreate(NULL);
13470
13471 if (oldset != NULL) {
13472 for (i = 0; i < oldset->nodeNr; i++) {
13473 /*
13474 * Run the evaluation with a node list made of a single item
13475 * in the nodeset.
13476 */
13477 ctxt->context->node = oldset->nodeTab[i];
13478 /*
13479 * OPTIMIZE TODO: Avoid recreation for every iteration.
13480 */
13481 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13482 ctxt->context->node);
13483 valuePush(ctxt, tmp);
13484
13485 if (op->ch2 != -1)
13486 total +=
13487 xmlXPathCompOpEval(ctxt,
13488 &comp->steps[op->ch2]);
13489 if (ctxt->error != XPATH_EXPRESSION_OK) {
13490 xmlXPtrFreeLocationSet(newlocset);
13491 goto rangeto_error;
13492 }
13493
13494 res = valuePop(ctxt);
13495 range =
13496 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13497 res);
13498 if (range != NULL) {
13499 xmlXPtrLocationSetAdd(newlocset, range);
13500 }
13501
13502 /*
13503 * Cleanup
13504 */
13505 if (res != NULL) {
13506 xmlXPathReleaseObject(ctxt->context, res);
13507 }
13508 if (ctxt->value == tmp) {
13509 res = valuePop(ctxt);
13510 xmlXPathReleaseObject(ctxt->context, res);
13511 }
13512 }
13513 }
13514 }
13515
13516 /*
13517 * The result is used as the new evaluation set.
13518 */
13519 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13520 rangeto_error:
13521 xmlXPathReleaseObject(ctxt->context, obj);
13522 ctxt->context->node = oldnode;
13523 ctxt->context->contextSize = oldcs;
13524 ctxt->context->proximityPosition = oldpp;
13525 break;
13526 }
13527 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13528 default:
13529 xmlGenericError(xmlGenericErrorContext,
13530 "XPath: unknown precompiled operation %d\n", op->op);
13531 ctxt->error = XPATH_INVALID_OPERAND;
13532 break;
13533 }
13534
13535 ctxt->context->depth -= 1;
13536 return (total);
13537 }
13538
13539 /**
13540 * xmlXPathCompOpEvalToBoolean:
13541 * @ctxt: the XPath parser context
13542 *
13543 * Evaluates if the expression evaluates to true.
13544 *
13545 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13546 */
13547 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13548 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13549 xmlXPathStepOpPtr op,
13550 int isPredicate)
13551 {
13552 xmlXPathObjectPtr resObj = NULL;
13553
13554 start:
13555 if (OP_LIMIT_EXCEEDED(ctxt, 1))
13556 return(0);
13557 /* comp = ctxt->comp; */
13558 switch (op->op) {
13559 case XPATH_OP_END:
13560 return (0);
13561 case XPATH_OP_VALUE:
13562 resObj = (xmlXPathObjectPtr) op->value4;
13563 if (isPredicate)
13564 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13565 return(xmlXPathCastToBoolean(resObj));
13566 case XPATH_OP_SORT:
13567 /*
13568 * We don't need sorting for boolean results. Skip this one.
13569 */
13570 if (op->ch1 != -1) {
13571 op = &ctxt->comp->steps[op->ch1];
13572 goto start;
13573 }
13574 return(0);
13575 case XPATH_OP_COLLECT:
13576 if (op->ch1 == -1)
13577 return(0);
13578
13579 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13580 if (ctxt->error != XPATH_EXPRESSION_OK)
13581 return(-1);
13582
13583 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13584 if (ctxt->error != XPATH_EXPRESSION_OK)
13585 return(-1);
13586
13587 resObj = valuePop(ctxt);
13588 if (resObj == NULL)
13589 return(-1);
13590 break;
13591 default:
13592 /*
13593 * Fallback to call xmlXPathCompOpEval().
13594 */
13595 xmlXPathCompOpEval(ctxt, op);
13596 if (ctxt->error != XPATH_EXPRESSION_OK)
13597 return(-1);
13598
13599 resObj = valuePop(ctxt);
13600 if (resObj == NULL)
13601 return(-1);
13602 break;
13603 }
13604
13605 if (resObj) {
13606 int res;
13607
13608 if (resObj->type == XPATH_BOOLEAN) {
13609 res = resObj->boolval;
13610 } else if (isPredicate) {
13611 /*
13612 * For predicates a result of type "number" is handled
13613 * differently:
13614 * SPEC XPath 1.0:
13615 * "If the result is a number, the result will be converted
13616 * to true if the number is equal to the context position
13617 * and will be converted to false otherwise;"
13618 */
13619 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13620 } else {
13621 res = xmlXPathCastToBoolean(resObj);
13622 }
13623 xmlXPathReleaseObject(ctxt->context, resObj);
13624 return(res);
13625 }
13626
13627 return(0);
13628 }
13629
13630 #ifdef XPATH_STREAMING
13631 /**
13632 * xmlXPathRunStreamEval:
13633 * @ctxt: the XPath parser context with the compiled expression
13634 *
13635 * Evaluate the Precompiled Streamable XPath expression in the given context.
13636 */
13637 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)13638 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13639 xmlXPathObjectPtr *resultSeq, int toBool)
13640 {
13641 int max_depth, min_depth;
13642 int from_root;
13643 int ret, depth;
13644 int eval_all_nodes;
13645 xmlNodePtr cur = NULL, limit = NULL;
13646 xmlStreamCtxtPtr patstream = NULL;
13647
13648 int nb_nodes = 0;
13649
13650 if ((ctxt == NULL) || (comp == NULL))
13651 return(-1);
13652 max_depth = xmlPatternMaxDepth(comp);
13653 if (max_depth == -1)
13654 return(-1);
13655 if (max_depth == -2)
13656 max_depth = 10000;
13657 min_depth = xmlPatternMinDepth(comp);
13658 if (min_depth == -1)
13659 return(-1);
13660 from_root = xmlPatternFromRoot(comp);
13661 if (from_root < 0)
13662 return(-1);
13663 #if 0
13664 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13665 #endif
13666
13667 if (! toBool) {
13668 if (resultSeq == NULL)
13669 return(-1);
13670 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13671 if (*resultSeq == NULL)
13672 return(-1);
13673 }
13674
13675 /*
13676 * handle the special cases of "/" amd "." being matched
13677 */
13678 if (min_depth == 0) {
13679 if (from_root) {
13680 /* Select "/" */
13681 if (toBool)
13682 return(1);
13683 /* TODO: Check memory error. */
13684 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13685 (xmlNodePtr) ctxt->doc);
13686 } else {
13687 /* Select "self::node()" */
13688 if (toBool)
13689 return(1);
13690 /* TODO: Check memory error. */
13691 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13692 }
13693 }
13694 if (max_depth == 0) {
13695 return(0);
13696 }
13697
13698 if (from_root) {
13699 cur = (xmlNodePtr)ctxt->doc;
13700 } else if (ctxt->node != NULL) {
13701 switch (ctxt->node->type) {
13702 case XML_ELEMENT_NODE:
13703 case XML_DOCUMENT_NODE:
13704 case XML_DOCUMENT_FRAG_NODE:
13705 case XML_HTML_DOCUMENT_NODE:
13706 cur = ctxt->node;
13707 break;
13708 case XML_ATTRIBUTE_NODE:
13709 case XML_TEXT_NODE:
13710 case XML_CDATA_SECTION_NODE:
13711 case XML_ENTITY_REF_NODE:
13712 case XML_ENTITY_NODE:
13713 case XML_PI_NODE:
13714 case XML_COMMENT_NODE:
13715 case XML_NOTATION_NODE:
13716 case XML_DTD_NODE:
13717 case XML_DOCUMENT_TYPE_NODE:
13718 case XML_ELEMENT_DECL:
13719 case XML_ATTRIBUTE_DECL:
13720 case XML_ENTITY_DECL:
13721 case XML_NAMESPACE_DECL:
13722 case XML_XINCLUDE_START:
13723 case XML_XINCLUDE_END:
13724 break;
13725 }
13726 limit = cur;
13727 }
13728 if (cur == NULL) {
13729 return(0);
13730 }
13731
13732 patstream = xmlPatternGetStreamCtxt(comp);
13733 if (patstream == NULL) {
13734 /*
13735 * QUESTION TODO: Is this an error?
13736 */
13737 return(0);
13738 }
13739
13740 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13741
13742 if (from_root) {
13743 ret = xmlStreamPush(patstream, NULL, NULL);
13744 if (ret < 0) {
13745 } else if (ret == 1) {
13746 if (toBool)
13747 goto return_1;
13748 /* TODO: Check memory error. */
13749 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13750 }
13751 }
13752 depth = 0;
13753 goto scan_children;
13754 next_node:
13755 do {
13756 if (ctxt->opLimit != 0) {
13757 if (ctxt->opCount >= ctxt->opLimit) {
13758 xmlGenericError(xmlGenericErrorContext,
13759 "XPath operation limit exceeded\n");
13760 xmlFreeStreamCtxt(patstream);
13761 return(-1);
13762 }
13763 ctxt->opCount++;
13764 }
13765
13766 nb_nodes++;
13767
13768 switch (cur->type) {
13769 case XML_ELEMENT_NODE:
13770 case XML_TEXT_NODE:
13771 case XML_CDATA_SECTION_NODE:
13772 case XML_COMMENT_NODE:
13773 case XML_PI_NODE:
13774 if (cur->type == XML_ELEMENT_NODE) {
13775 ret = xmlStreamPush(patstream, cur->name,
13776 (cur->ns ? cur->ns->href : NULL));
13777 } else if (eval_all_nodes)
13778 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13779 else
13780 break;
13781
13782 if (ret < 0) {
13783 /* NOP. */
13784 } else if (ret == 1) {
13785 if (toBool)
13786 goto return_1;
13787 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13788 < 0) {
13789 ctxt->lastError.domain = XML_FROM_XPATH;
13790 ctxt->lastError.code = XML_ERR_NO_MEMORY;
13791 }
13792 }
13793 if ((cur->children == NULL) || (depth >= max_depth)) {
13794 ret = xmlStreamPop(patstream);
13795 while (cur->next != NULL) {
13796 cur = cur->next;
13797 if ((cur->type != XML_ENTITY_DECL) &&
13798 (cur->type != XML_DTD_NODE))
13799 goto next_node;
13800 }
13801 }
13802 default:
13803 break;
13804 }
13805
13806 scan_children:
13807 if (cur->type == XML_NAMESPACE_DECL) break;
13808 if ((cur->children != NULL) && (depth < max_depth)) {
13809 /*
13810 * Do not descend on entities declarations
13811 */
13812 if (cur->children->type != XML_ENTITY_DECL) {
13813 cur = cur->children;
13814 depth++;
13815 /*
13816 * Skip DTDs
13817 */
13818 if (cur->type != XML_DTD_NODE)
13819 continue;
13820 }
13821 }
13822
13823 if (cur == limit)
13824 break;
13825
13826 while (cur->next != NULL) {
13827 cur = cur->next;
13828 if ((cur->type != XML_ENTITY_DECL) &&
13829 (cur->type != XML_DTD_NODE))
13830 goto next_node;
13831 }
13832
13833 do {
13834 cur = cur->parent;
13835 depth--;
13836 if ((cur == NULL) || (cur == limit) ||
13837 (cur->type == XML_DOCUMENT_NODE))
13838 goto done;
13839 if (cur->type == XML_ELEMENT_NODE) {
13840 ret = xmlStreamPop(patstream);
13841 } else if ((eval_all_nodes) &&
13842 ((cur->type == XML_TEXT_NODE) ||
13843 (cur->type == XML_CDATA_SECTION_NODE) ||
13844 (cur->type == XML_COMMENT_NODE) ||
13845 (cur->type == XML_PI_NODE)))
13846 {
13847 ret = xmlStreamPop(patstream);
13848 }
13849 if (cur->next != NULL) {
13850 cur = cur->next;
13851 break;
13852 }
13853 } while (cur != NULL);
13854
13855 } while ((cur != NULL) && (depth >= 0));
13856
13857 done:
13858
13859 #if 0
13860 printf("stream eval: checked %d nodes selected %d\n",
13861 nb_nodes, retObj->nodesetval->nodeNr);
13862 #endif
13863
13864 if (patstream)
13865 xmlFreeStreamCtxt(patstream);
13866 return(0);
13867
13868 return_1:
13869 if (patstream)
13870 xmlFreeStreamCtxt(patstream);
13871 return(1);
13872 }
13873 #endif /* XPATH_STREAMING */
13874
13875 /**
13876 * xmlXPathRunEval:
13877 * @ctxt: the XPath parser context with the compiled expression
13878 * @toBool: evaluate to a boolean result
13879 *
13880 * Evaluate the Precompiled XPath expression in the given context.
13881 */
13882 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)13883 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13884 {
13885 xmlXPathCompExprPtr comp;
13886 int oldDepth;
13887
13888 if ((ctxt == NULL) || (ctxt->comp == NULL))
13889 return(-1);
13890
13891 if (ctxt->valueTab == NULL) {
13892 /* Allocate the value stack */
13893 ctxt->valueTab = (xmlXPathObjectPtr *)
13894 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13895 if (ctxt->valueTab == NULL) {
13896 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13897 return(-1);
13898 }
13899 ctxt->valueNr = 0;
13900 ctxt->valueMax = 10;
13901 ctxt->value = NULL;
13902 ctxt->valueFrame = 0;
13903 }
13904 #ifdef XPATH_STREAMING
13905 if (ctxt->comp->stream) {
13906 int res;
13907
13908 if (toBool) {
13909 /*
13910 * Evaluation to boolean result.
13911 */
13912 res = xmlXPathRunStreamEval(ctxt->context,
13913 ctxt->comp->stream, NULL, 1);
13914 if (res != -1)
13915 return(res);
13916 } else {
13917 xmlXPathObjectPtr resObj = NULL;
13918
13919 /*
13920 * Evaluation to a sequence.
13921 */
13922 res = xmlXPathRunStreamEval(ctxt->context,
13923 ctxt->comp->stream, &resObj, 0);
13924
13925 if ((res != -1) && (resObj != NULL)) {
13926 valuePush(ctxt, resObj);
13927 return(0);
13928 }
13929 if (resObj != NULL)
13930 xmlXPathReleaseObject(ctxt->context, resObj);
13931 }
13932 /*
13933 * QUESTION TODO: This falls back to normal XPath evaluation
13934 * if res == -1. Is this intended?
13935 */
13936 }
13937 #endif
13938 comp = ctxt->comp;
13939 if (comp->last < 0) {
13940 xmlGenericError(xmlGenericErrorContext,
13941 "xmlXPathRunEval: last is less than zero\n");
13942 return(-1);
13943 }
13944 oldDepth = ctxt->context->depth;
13945 if (toBool)
13946 return(xmlXPathCompOpEvalToBoolean(ctxt,
13947 &comp->steps[comp->last], 0));
13948 else
13949 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13950 ctxt->context->depth = oldDepth;
13951
13952 return(0);
13953 }
13954
13955 /************************************************************************
13956 * *
13957 * Public interfaces *
13958 * *
13959 ************************************************************************/
13960
13961 /**
13962 * xmlXPathEvalPredicate:
13963 * @ctxt: the XPath context
13964 * @res: the Predicate Expression evaluation result
13965 *
13966 * Evaluate a predicate result for the current node.
13967 * A PredicateExpr is evaluated by evaluating the Expr and converting
13968 * the result to a boolean. If the result is a number, the result will
13969 * be converted to true if the number is equal to the position of the
13970 * context node in the context node list (as returned by the position
13971 * function) and will be converted to false otherwise; if the result
13972 * is not a number, then the result will be converted as if by a call
13973 * to the boolean function.
13974 *
13975 * Returns 1 if predicate is true, 0 otherwise
13976 */
13977 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)13978 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13979 if ((ctxt == NULL) || (res == NULL)) return(0);
13980 switch (res->type) {
13981 case XPATH_BOOLEAN:
13982 return(res->boolval);
13983 case XPATH_NUMBER:
13984 return(res->floatval == ctxt->proximityPosition);
13985 case XPATH_NODESET:
13986 case XPATH_XSLT_TREE:
13987 if (res->nodesetval == NULL)
13988 return(0);
13989 return(res->nodesetval->nodeNr != 0);
13990 case XPATH_STRING:
13991 return((res->stringval != NULL) &&
13992 (xmlStrlen(res->stringval) != 0));
13993 default:
13994 STRANGE
13995 }
13996 return(0);
13997 }
13998
13999 /**
14000 * xmlXPathEvaluatePredicateResult:
14001 * @ctxt: the XPath Parser context
14002 * @res: the Predicate Expression evaluation result
14003 *
14004 * Evaluate a predicate result for the current node.
14005 * A PredicateExpr is evaluated by evaluating the Expr and converting
14006 * the result to a boolean. If the result is a number, the result will
14007 * be converted to true if the number is equal to the position of the
14008 * context node in the context node list (as returned by the position
14009 * function) and will be converted to false otherwise; if the result
14010 * is not a number, then the result will be converted as if by a call
14011 * to the boolean function.
14012 *
14013 * Returns 1 if predicate is true, 0 otherwise
14014 */
14015 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14016 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14017 xmlXPathObjectPtr res) {
14018 if ((ctxt == NULL) || (res == NULL)) return(0);
14019 switch (res->type) {
14020 case XPATH_BOOLEAN:
14021 return(res->boolval);
14022 case XPATH_NUMBER:
14023 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14024 return((res->floatval == ctxt->context->proximityPosition) &&
14025 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14026 #else
14027 return(res->floatval == ctxt->context->proximityPosition);
14028 #endif
14029 case XPATH_NODESET:
14030 case XPATH_XSLT_TREE:
14031 if (res->nodesetval == NULL)
14032 return(0);
14033 return(res->nodesetval->nodeNr != 0);
14034 case XPATH_STRING:
14035 return((res->stringval != NULL) && (res->stringval[0] != 0));
14036 #ifdef LIBXML_XPTR_LOCS_ENABLED
14037 case XPATH_LOCATIONSET:{
14038 xmlLocationSetPtr ptr = res->user;
14039 if (ptr == NULL)
14040 return(0);
14041 return (ptr->locNr != 0);
14042 }
14043 #endif
14044 default:
14045 STRANGE
14046 }
14047 return(0);
14048 }
14049
14050 #ifdef XPATH_STREAMING
14051 /**
14052 * xmlXPathTryStreamCompile:
14053 * @ctxt: an XPath context
14054 * @str: the XPath expression
14055 *
14056 * Try to compile the XPath expression as a streamable subset.
14057 *
14058 * Returns the compiled expression or NULL if failed to compile.
14059 */
14060 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14061 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14062 /*
14063 * Optimization: use streaming patterns when the XPath expression can
14064 * be compiled to a stream lookup
14065 */
14066 xmlPatternPtr stream;
14067 xmlXPathCompExprPtr comp;
14068 xmlDictPtr dict = NULL;
14069 const xmlChar **namespaces = NULL;
14070 xmlNsPtr ns;
14071 int i, j;
14072
14073 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14074 (!xmlStrchr(str, '@'))) {
14075 const xmlChar *tmp;
14076
14077 /*
14078 * We don't try to handle expressions using the verbose axis
14079 * specifiers ("::"), just the simplified form at this point.
14080 * Additionally, if there is no list of namespaces available and
14081 * there's a ":" in the expression, indicating a prefixed QName,
14082 * then we won't try to compile either. xmlPatterncompile() needs
14083 * to have a list of namespaces at compilation time in order to
14084 * compile prefixed name tests.
14085 */
14086 tmp = xmlStrchr(str, ':');
14087 if ((tmp != NULL) &&
14088 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14089 return(NULL);
14090
14091 if (ctxt != NULL) {
14092 dict = ctxt->dict;
14093 if (ctxt->nsNr > 0) {
14094 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14095 if (namespaces == NULL) {
14096 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14097 return(NULL);
14098 }
14099 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14100 ns = ctxt->namespaces[j];
14101 namespaces[i++] = ns->href;
14102 namespaces[i++] = ns->prefix;
14103 }
14104 namespaces[i++] = NULL;
14105 namespaces[i] = NULL;
14106 }
14107 }
14108
14109 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14110 if (namespaces != NULL) {
14111 xmlFree((xmlChar **)namespaces);
14112 }
14113 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14114 comp = xmlXPathNewCompExpr();
14115 if (comp == NULL) {
14116 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14117 return(NULL);
14118 }
14119 comp->stream = stream;
14120 comp->dict = dict;
14121 if (comp->dict)
14122 xmlDictReference(comp->dict);
14123 return(comp);
14124 }
14125 xmlFreePattern(stream);
14126 }
14127 return(NULL);
14128 }
14129 #endif /* XPATH_STREAMING */
14130
14131 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)14132 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14133 xmlXPathStepOpPtr op)
14134 {
14135 xmlXPathCompExprPtr comp = pctxt->comp;
14136 xmlXPathContextPtr ctxt;
14137
14138 /*
14139 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14140 * internal representation.
14141 */
14142
14143 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14144 (op->ch1 != -1) &&
14145 (op->ch2 == -1 /* no predicate */))
14146 {
14147 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14148
14149 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14150 ((xmlXPathAxisVal) prevop->value ==
14151 AXIS_DESCENDANT_OR_SELF) &&
14152 (prevop->ch2 == -1) &&
14153 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14154 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14155 {
14156 /*
14157 * This is a "descendant-or-self::node()" without predicates.
14158 * Try to eliminate it.
14159 */
14160
14161 switch ((xmlXPathAxisVal) op->value) {
14162 case AXIS_CHILD:
14163 case AXIS_DESCENDANT:
14164 /*
14165 * Convert "descendant-or-self::node()/child::" or
14166 * "descendant-or-self::node()/descendant::" to
14167 * "descendant::"
14168 */
14169 op->ch1 = prevop->ch1;
14170 op->value = AXIS_DESCENDANT;
14171 break;
14172 case AXIS_SELF:
14173 case AXIS_DESCENDANT_OR_SELF:
14174 /*
14175 * Convert "descendant-or-self::node()/self::" or
14176 * "descendant-or-self::node()/descendant-or-self::" to
14177 * to "descendant-or-self::"
14178 */
14179 op->ch1 = prevop->ch1;
14180 op->value = AXIS_DESCENDANT_OR_SELF;
14181 break;
14182 default:
14183 break;
14184 }
14185 }
14186 }
14187
14188 /* OP_VALUE has invalid ch1. */
14189 if (op->op == XPATH_OP_VALUE)
14190 return;
14191
14192 /* Recurse */
14193 ctxt = pctxt->context;
14194 if (ctxt != NULL) {
14195 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14196 return;
14197 ctxt->depth += 1;
14198 }
14199 if (op->ch1 != -1)
14200 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14201 if (op->ch2 != -1)
14202 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14203 if (ctxt != NULL)
14204 ctxt->depth -= 1;
14205 }
14206
14207 /**
14208 * xmlXPathCtxtCompile:
14209 * @ctxt: an XPath context
14210 * @str: the XPath expression
14211 *
14212 * Compile an XPath expression
14213 *
14214 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14215 * the caller has to free the object.
14216 */
14217 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14218 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14219 xmlXPathParserContextPtr pctxt;
14220 xmlXPathCompExprPtr comp;
14221 int oldDepth = 0;
14222
14223 #ifdef XPATH_STREAMING
14224 comp = xmlXPathTryStreamCompile(ctxt, str);
14225 if (comp != NULL)
14226 return(comp);
14227 #endif
14228
14229 xmlInitParser();
14230
14231 pctxt = xmlXPathNewParserContext(str, ctxt);
14232 if (pctxt == NULL)
14233 return NULL;
14234 if (ctxt != NULL)
14235 oldDepth = ctxt->depth;
14236 xmlXPathCompileExpr(pctxt, 1);
14237 if (ctxt != NULL)
14238 ctxt->depth = oldDepth;
14239
14240 if( pctxt->error != XPATH_EXPRESSION_OK )
14241 {
14242 xmlXPathFreeParserContext(pctxt);
14243 return(NULL);
14244 }
14245
14246 if (*pctxt->cur != 0) {
14247 /*
14248 * aleksey: in some cases this line prints *second* error message
14249 * (see bug #78858) and probably this should be fixed.
14250 * However, we are not sure that all error messages are printed
14251 * out in other places. It's not critical so we leave it as-is for now
14252 */
14253 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14254 comp = NULL;
14255 } else {
14256 comp = pctxt->comp;
14257 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14258 if (ctxt != NULL)
14259 oldDepth = ctxt->depth;
14260 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14261 if (ctxt != NULL)
14262 ctxt->depth = oldDepth;
14263 }
14264 pctxt->comp = NULL;
14265 }
14266 xmlXPathFreeParserContext(pctxt);
14267
14268 if (comp != NULL) {
14269 comp->expr = xmlStrdup(str);
14270 #ifdef DEBUG_EVAL_COUNTS
14271 comp->string = xmlStrdup(str);
14272 comp->nb = 0;
14273 #endif
14274 }
14275 return(comp);
14276 }
14277
14278 /**
14279 * xmlXPathCompile:
14280 * @str: the XPath expression
14281 *
14282 * Compile an XPath expression
14283 *
14284 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14285 * the caller has to free the object.
14286 */
14287 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14288 xmlXPathCompile(const xmlChar *str) {
14289 return(xmlXPathCtxtCompile(NULL, str));
14290 }
14291
14292 /**
14293 * xmlXPathCompiledEvalInternal:
14294 * @comp: the compiled XPath expression
14295 * @ctxt: the XPath context
14296 * @resObj: the resulting XPath object or NULL
14297 * @toBool: 1 if only a boolean result is requested
14298 *
14299 * Evaluate the Precompiled XPath expression in the given context.
14300 * The caller has to free @resObj.
14301 *
14302 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14303 * the caller has to free the object.
14304 */
14305 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14306 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14307 xmlXPathContextPtr ctxt,
14308 xmlXPathObjectPtr *resObjPtr,
14309 int toBool)
14310 {
14311 xmlXPathParserContextPtr pctxt;
14312 xmlXPathObjectPtr resObj;
14313 #ifndef LIBXML_THREAD_ENABLED
14314 static int reentance = 0;
14315 #endif
14316 int res;
14317
14318 CHECK_CTXT_NEG(ctxt)
14319
14320 if (comp == NULL)
14321 return(-1);
14322 xmlInitParser();
14323
14324 #ifndef LIBXML_THREAD_ENABLED
14325 reentance++;
14326 if (reentance > 1)
14327 xmlXPathDisableOptimizer = 1;
14328 #endif
14329
14330 #ifdef DEBUG_EVAL_COUNTS
14331 comp->nb++;
14332 if ((comp->string != NULL) && (comp->nb > 100)) {
14333 fprintf(stderr, "100 x %s\n", comp->string);
14334 comp->nb = 0;
14335 }
14336 #endif
14337 pctxt = xmlXPathCompParserContext(comp, ctxt);
14338 res = xmlXPathRunEval(pctxt, toBool);
14339
14340 if (pctxt->error != XPATH_EXPRESSION_OK) {
14341 resObj = NULL;
14342 } else {
14343 resObj = valuePop(pctxt);
14344 if (resObj == NULL) {
14345 if (!toBool)
14346 xmlGenericError(xmlGenericErrorContext,
14347 "xmlXPathCompiledEval: No result on the stack.\n");
14348 } else if (pctxt->valueNr > 0) {
14349 xmlGenericError(xmlGenericErrorContext,
14350 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14351 pctxt->valueNr);
14352 }
14353 }
14354
14355 if (resObjPtr)
14356 *resObjPtr = resObj;
14357 else
14358 xmlXPathReleaseObject(ctxt, resObj);
14359
14360 pctxt->comp = NULL;
14361 xmlXPathFreeParserContext(pctxt);
14362 #ifndef LIBXML_THREAD_ENABLED
14363 reentance--;
14364 #endif
14365
14366 return(res);
14367 }
14368
14369 /**
14370 * xmlXPathCompiledEval:
14371 * @comp: the compiled XPath expression
14372 * @ctx: the XPath context
14373 *
14374 * Evaluate the Precompiled XPath expression in the given context.
14375 *
14376 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14377 * the caller has to free the object.
14378 */
14379 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14380 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14381 {
14382 xmlXPathObjectPtr res = NULL;
14383
14384 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14385 return(res);
14386 }
14387
14388 /**
14389 * xmlXPathCompiledEvalToBoolean:
14390 * @comp: the compiled XPath expression
14391 * @ctxt: the XPath context
14392 *
14393 * Applies the XPath boolean() function on the result of the given
14394 * compiled expression.
14395 *
14396 * Returns 1 if the expression evaluated to true, 0 if to false and
14397 * -1 in API and internal errors.
14398 */
14399 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14400 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14401 xmlXPathContextPtr ctxt)
14402 {
14403 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14404 }
14405
14406 /**
14407 * xmlXPathEvalExpr:
14408 * @ctxt: the XPath Parser context
14409 *
14410 * Parse and evaluate an XPath expression in the given context,
14411 * then push the result on the context stack
14412 */
14413 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14414 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14415 #ifdef XPATH_STREAMING
14416 xmlXPathCompExprPtr comp;
14417 #endif
14418 int oldDepth = 0;
14419
14420 if (ctxt == NULL) return;
14421
14422 #ifdef XPATH_STREAMING
14423 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14424 if (comp != NULL) {
14425 if (ctxt->comp != NULL)
14426 xmlXPathFreeCompExpr(ctxt->comp);
14427 ctxt->comp = comp;
14428 } else
14429 #endif
14430 {
14431 if (ctxt->context != NULL)
14432 oldDepth = ctxt->context->depth;
14433 xmlXPathCompileExpr(ctxt, 1);
14434 if (ctxt->context != NULL)
14435 ctxt->context->depth = oldDepth;
14436 CHECK_ERROR;
14437
14438 /* Check for trailing characters. */
14439 if (*ctxt->cur != 0)
14440 XP_ERROR(XPATH_EXPR_ERROR);
14441
14442 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14443 if (ctxt->context != NULL)
14444 oldDepth = ctxt->context->depth;
14445 xmlXPathOptimizeExpression(ctxt,
14446 &ctxt->comp->steps[ctxt->comp->last]);
14447 if (ctxt->context != NULL)
14448 ctxt->context->depth = oldDepth;
14449 }
14450 }
14451
14452 xmlXPathRunEval(ctxt, 0);
14453 }
14454
14455 /**
14456 * xmlXPathEval:
14457 * @str: the XPath expression
14458 * @ctx: the XPath context
14459 *
14460 * Evaluate the XPath Location Path in the given context.
14461 *
14462 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14463 * the caller has to free the object.
14464 */
14465 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14466 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14467 xmlXPathParserContextPtr ctxt;
14468 xmlXPathObjectPtr res;
14469
14470 CHECK_CTXT(ctx)
14471
14472 xmlInitParser();
14473
14474 ctxt = xmlXPathNewParserContext(str, ctx);
14475 if (ctxt == NULL)
14476 return NULL;
14477 xmlXPathEvalExpr(ctxt);
14478
14479 if (ctxt->error != XPATH_EXPRESSION_OK) {
14480 res = NULL;
14481 } else {
14482 res = valuePop(ctxt);
14483 if (res == NULL) {
14484 xmlGenericError(xmlGenericErrorContext,
14485 "xmlXPathCompiledEval: No result on the stack.\n");
14486 } else if (ctxt->valueNr > 0) {
14487 xmlGenericError(xmlGenericErrorContext,
14488 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14489 ctxt->valueNr);
14490 }
14491 }
14492
14493 xmlXPathFreeParserContext(ctxt);
14494 return(res);
14495 }
14496
14497 /**
14498 * xmlXPathSetContextNode:
14499 * @node: the node to to use as the context node
14500 * @ctx: the XPath context
14501 *
14502 * Sets 'node' as the context node. The node must be in the same
14503 * document as that associated with the context.
14504 *
14505 * Returns -1 in case of error or 0 if successful
14506 */
14507 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14508 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14509 if ((node == NULL) || (ctx == NULL))
14510 return(-1);
14511
14512 if (node->doc == ctx->doc) {
14513 ctx->node = node;
14514 return(0);
14515 }
14516 return(-1);
14517 }
14518
14519 /**
14520 * xmlXPathNodeEval:
14521 * @node: the node to to use as the context node
14522 * @str: the XPath expression
14523 * @ctx: the XPath context
14524 *
14525 * Evaluate the XPath Location Path in the given context. The node 'node'
14526 * is set as the context node. The context node is not restored.
14527 *
14528 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14529 * the caller has to free the object.
14530 */
14531 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14532 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14533 if (str == NULL)
14534 return(NULL);
14535 if (xmlXPathSetContextNode(node, ctx) < 0)
14536 return(NULL);
14537 return(xmlXPathEval(str, ctx));
14538 }
14539
14540 /**
14541 * xmlXPathEvalExpression:
14542 * @str: the XPath expression
14543 * @ctxt: the XPath context
14544 *
14545 * Alias for xmlXPathEval().
14546 *
14547 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14548 * the caller has to free the object.
14549 */
14550 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14551 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14552 return(xmlXPathEval(str, ctxt));
14553 }
14554
14555 /************************************************************************
14556 * *
14557 * Extra functions not pertaining to the XPath spec *
14558 * *
14559 ************************************************************************/
14560 /**
14561 * xmlXPathEscapeUriFunction:
14562 * @ctxt: the XPath Parser context
14563 * @nargs: the number of arguments
14564 *
14565 * Implement the escape-uri() XPath function
14566 * string escape-uri(string $str, bool $escape-reserved)
14567 *
14568 * This function applies the URI escaping rules defined in section 2 of [RFC
14569 * 2396] to the string supplied as $uri-part, which typically represents all
14570 * or part of a URI. The effect of the function is to replace any special
14571 * character in the string by an escape sequence of the form %xx%yy...,
14572 * where xxyy... is the hexadecimal representation of the octets used to
14573 * represent the character in UTF-8.
14574 *
14575 * The set of characters that are escaped depends on the setting of the
14576 * boolean argument $escape-reserved.
14577 *
14578 * If $escape-reserved is true, all characters are escaped other than lower
14579 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14580 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14581 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14582 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14583 * A-F).
14584 *
14585 * If $escape-reserved is false, the behavior differs in that characters
14586 * referred to in [RFC 2396] as reserved characters are not escaped. These
14587 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14588 *
14589 * [RFC 2396] does not define whether escaped URIs should use lower case or
14590 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14591 * compared using string comparison functions, this function must always use
14592 * the upper-case letters A-F.
14593 *
14594 * Generally, $escape-reserved should be set to true when escaping a string
14595 * that is to form a single part of a URI, and to false when escaping an
14596 * entire URI or URI reference.
14597 *
14598 * In the case of non-ascii characters, the string is encoded according to
14599 * utf-8 and then converted according to RFC 2396.
14600 *
14601 * Examples
14602 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14603 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14604 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14605 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14606 *
14607 */
14608 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)14609 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14610 xmlXPathObjectPtr str;
14611 int escape_reserved;
14612 xmlBufPtr target;
14613 xmlChar *cptr;
14614 xmlChar escape[4];
14615
14616 CHECK_ARITY(2);
14617
14618 escape_reserved = xmlXPathPopBoolean(ctxt);
14619
14620 CAST_TO_STRING;
14621 str = valuePop(ctxt);
14622
14623 target = xmlBufCreate();
14624
14625 escape[0] = '%';
14626 escape[3] = 0;
14627
14628 if (target) {
14629 for (cptr = str->stringval; *cptr; cptr++) {
14630 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14631 (*cptr >= 'a' && *cptr <= 'z') ||
14632 (*cptr >= '0' && *cptr <= '9') ||
14633 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14634 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14635 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14636 (*cptr == '%' &&
14637 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14638 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14639 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14640 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14641 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14642 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14643 (!escape_reserved &&
14644 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14645 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14646 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14647 *cptr == ','))) {
14648 xmlBufAdd(target, cptr, 1);
14649 } else {
14650 if ((*cptr >> 4) < 10)
14651 escape[1] = '0' + (*cptr >> 4);
14652 else
14653 escape[1] = 'A' - 10 + (*cptr >> 4);
14654 if ((*cptr & 0xF) < 10)
14655 escape[2] = '0' + (*cptr & 0xF);
14656 else
14657 escape[2] = 'A' - 10 + (*cptr & 0xF);
14658
14659 xmlBufAdd(target, &escape[0], 3);
14660 }
14661 }
14662 }
14663 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14664 xmlBufContent(target)));
14665 xmlBufFree(target);
14666 xmlXPathReleaseObject(ctxt->context, str);
14667 }
14668
14669 /**
14670 * xmlXPathRegisterAllFunctions:
14671 * @ctxt: the XPath context
14672 *
14673 * Registers all default XPath functions in this context
14674 */
14675 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)14676 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14677 {
14678 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14679 xmlXPathBooleanFunction);
14680 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14681 xmlXPathCeilingFunction);
14682 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14683 xmlXPathCountFunction);
14684 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14685 xmlXPathConcatFunction);
14686 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14687 xmlXPathContainsFunction);
14688 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14689 xmlXPathIdFunction);
14690 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14691 xmlXPathFalseFunction);
14692 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14693 xmlXPathFloorFunction);
14694 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14695 xmlXPathLastFunction);
14696 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14697 xmlXPathLangFunction);
14698 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14699 xmlXPathLocalNameFunction);
14700 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14701 xmlXPathNotFunction);
14702 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14703 xmlXPathNameFunction);
14704 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14705 xmlXPathNamespaceURIFunction);
14706 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14707 xmlXPathNormalizeFunction);
14708 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14709 xmlXPathNumberFunction);
14710 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14711 xmlXPathPositionFunction);
14712 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14713 xmlXPathRoundFunction);
14714 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14715 xmlXPathStringFunction);
14716 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14717 xmlXPathStringLengthFunction);
14718 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14719 xmlXPathStartsWithFunction);
14720 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14721 xmlXPathSubstringFunction);
14722 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14723 xmlXPathSubstringBeforeFunction);
14724 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14725 xmlXPathSubstringAfterFunction);
14726 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14727 xmlXPathSumFunction);
14728 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14729 xmlXPathTrueFunction);
14730 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14731 xmlXPathTranslateFunction);
14732
14733 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14734 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14735 xmlXPathEscapeUriFunction);
14736 }
14737
14738 #endif /* LIBXML_XPATH_ENABLED */
14739