1 /*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See Copyright for the status of this software
12 *
13 * Author: daniel@veillard.com
14 *
15 */
16
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21
22 #define IN_LIBXML
23 #include "libxml.h"
24
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_MATH_H
33 #include <math.h>
34 #endif
35 #ifdef HAVE_FLOAT_H
36 #include <float.h>
37 #endif
38 #ifdef HAVE_CTYPE_H
39 #include <ctype.h>
40 #endif
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
54 #endif
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
57 #endif
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
63 #endif
64
65 #include "buf.h"
66
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
69 #endif
70
71 #define TODO \
72 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
74 __FILE__, __LINE__);
75
76 /**
77 * WITH_TIM_SORT:
78 *
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
82 */
83 #define WITH_TIM_SORT
84
85 /*
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
93 */
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
95
96 /*
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
100 */
101 #define XP_OPTIMIZED_FILTER_FIRST
102
103 /*
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
106 * created.
107 */
108 /* #define XP_DEBUG_OBJ_USAGE */
109
110 /*
111 * XPATH_MAX_STEPS:
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
115 * circumstances
116 */
117 #define XPATH_MAX_STEPS 1000000
118
119 /*
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
124 * circumstances
125 */
126 #define XPATH_MAX_STACK_DEPTH 1000000
127
128 /*
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
135 */
136 #define XPATH_MAX_NODESET_LENGTH 10000000
137
138 /*
139 * XPATH_MAX_RECRUSION_DEPTH:
140 * Maximum amount of nested functions calls when parsing or evaluating
141 * expressions
142 */
143 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
144 #define XPATH_MAX_RECURSION_DEPTH 500
145 #else
146 #define XPATH_MAX_RECURSION_DEPTH 5000
147 #endif
148
149 /*
150 * TODO:
151 * There are a few spots where some tests are done which depend upon ascii
152 * data. These should be enhanced for full UTF8 support (see particularly
153 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
154 */
155
156 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157 /**
158 * xmlXPathCmpNodesExt:
159 * @node1: the first node
160 * @node2: the second node
161 *
162 * Compare two nodes w.r.t document order.
163 * This one is optimized for handling of non-element nodes.
164 *
165 * Returns -2 in case of error 1 if first point < second point, 0 if
166 * it's the same node, -1 otherwise
167 */
168 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)169 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
170 int depth1, depth2;
171 int misc = 0, precedence1 = 0, precedence2 = 0;
172 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
173 xmlNodePtr cur, root;
174 ptrdiff_t l1, l2;
175
176 if ((node1 == NULL) || (node2 == NULL))
177 return(-2);
178
179 if (node1 == node2)
180 return(0);
181
182 /*
183 * a couple of optimizations which will avoid computations in most cases
184 */
185 switch (node1->type) {
186 case XML_ELEMENT_NODE:
187 if (node2->type == XML_ELEMENT_NODE) {
188 if ((0 > (ptrdiff_t) node1->content) &&
189 (0 > (ptrdiff_t) node2->content) &&
190 (node1->doc == node2->doc))
191 {
192 l1 = -((ptrdiff_t) node1->content);
193 l2 = -((ptrdiff_t) node2->content);
194 if (l1 < l2)
195 return(1);
196 if (l1 > l2)
197 return(-1);
198 } else
199 goto turtle_comparison;
200 }
201 break;
202 case XML_ATTRIBUTE_NODE:
203 precedence1 = 1; /* element is owner */
204 miscNode1 = node1;
205 node1 = node1->parent;
206 misc = 1;
207 break;
208 case XML_TEXT_NODE:
209 case XML_CDATA_SECTION_NODE:
210 case XML_COMMENT_NODE:
211 case XML_PI_NODE: {
212 miscNode1 = node1;
213 /*
214 * Find nearest element node.
215 */
216 if (node1->prev != NULL) {
217 do {
218 node1 = node1->prev;
219 if (node1->type == XML_ELEMENT_NODE) {
220 precedence1 = 3; /* element in prev-sibl axis */
221 break;
222 }
223 if (node1->prev == NULL) {
224 precedence1 = 2; /* element is parent */
225 /*
226 * URGENT TODO: Are there any cases, where the
227 * parent of such a node is not an element node?
228 */
229 node1 = node1->parent;
230 break;
231 }
232 } while (1);
233 } else {
234 precedence1 = 2; /* element is parent */
235 node1 = node1->parent;
236 }
237 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
238 (0 <= (ptrdiff_t) node1->content)) {
239 /*
240 * Fallback for whatever case.
241 */
242 node1 = miscNode1;
243 precedence1 = 0;
244 } else
245 misc = 1;
246 }
247 break;
248 case XML_NAMESPACE_DECL:
249 /*
250 * TODO: why do we return 1 for namespace nodes?
251 */
252 return(1);
253 default:
254 break;
255 }
256 switch (node2->type) {
257 case XML_ELEMENT_NODE:
258 break;
259 case XML_ATTRIBUTE_NODE:
260 precedence2 = 1; /* element is owner */
261 miscNode2 = node2;
262 node2 = node2->parent;
263 misc = 1;
264 break;
265 case XML_TEXT_NODE:
266 case XML_CDATA_SECTION_NODE:
267 case XML_COMMENT_NODE:
268 case XML_PI_NODE: {
269 miscNode2 = node2;
270 if (node2->prev != NULL) {
271 do {
272 node2 = node2->prev;
273 if (node2->type == XML_ELEMENT_NODE) {
274 precedence2 = 3; /* element in prev-sibl axis */
275 break;
276 }
277 if (node2->prev == NULL) {
278 precedence2 = 2; /* element is parent */
279 node2 = node2->parent;
280 break;
281 }
282 } while (1);
283 } else {
284 precedence2 = 2; /* element is parent */
285 node2 = node2->parent;
286 }
287 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
288 (0 <= (ptrdiff_t) node2->content))
289 {
290 node2 = miscNode2;
291 precedence2 = 0;
292 } else
293 misc = 1;
294 }
295 break;
296 case XML_NAMESPACE_DECL:
297 return(1);
298 default:
299 break;
300 }
301 if (misc) {
302 if (node1 == node2) {
303 if (precedence1 == precedence2) {
304 /*
305 * The ugly case; but normally there aren't many
306 * adjacent non-element nodes around.
307 */
308 cur = miscNode2->prev;
309 while (cur != NULL) {
310 if (cur == miscNode1)
311 return(1);
312 if (cur->type == XML_ELEMENT_NODE)
313 return(-1);
314 cur = cur->prev;
315 }
316 return (-1);
317 } else {
318 /*
319 * Evaluate based on higher precedence wrt to the element.
320 * TODO: This assumes attributes are sorted before content.
321 * Is this 100% correct?
322 */
323 if (precedence1 < precedence2)
324 return(1);
325 else
326 return(-1);
327 }
328 }
329 /*
330 * Special case: One of the helper-elements is contained by the other.
331 * <foo>
332 * <node2>
333 * <node1>Text-1(precedence1 == 2)</node1>
334 * </node2>
335 * Text-6(precedence2 == 3)
336 * </foo>
337 */
338 if ((precedence2 == 3) && (precedence1 > 1)) {
339 cur = node1->parent;
340 while (cur) {
341 if (cur == node2)
342 return(1);
343 cur = cur->parent;
344 }
345 }
346 if ((precedence1 == 3) && (precedence2 > 1)) {
347 cur = node2->parent;
348 while (cur) {
349 if (cur == node1)
350 return(-1);
351 cur = cur->parent;
352 }
353 }
354 }
355
356 /*
357 * Speedup using document order if available.
358 */
359 if ((node1->type == XML_ELEMENT_NODE) &&
360 (node2->type == XML_ELEMENT_NODE) &&
361 (0 > (ptrdiff_t) node1->content) &&
362 (0 > (ptrdiff_t) node2->content) &&
363 (node1->doc == node2->doc)) {
364
365 l1 = -((ptrdiff_t) node1->content);
366 l2 = -((ptrdiff_t) node2->content);
367 if (l1 < l2)
368 return(1);
369 if (l1 > l2)
370 return(-1);
371 }
372
373 turtle_comparison:
374
375 if (node1 == node2->prev)
376 return(1);
377 if (node1 == node2->next)
378 return(-1);
379 /*
380 * compute depth to root
381 */
382 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
383 if (cur->parent == node1)
384 return(1);
385 depth2++;
386 }
387 root = cur;
388 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
389 if (cur->parent == node2)
390 return(-1);
391 depth1++;
392 }
393 /*
394 * Distinct document (or distinct entities :-( ) case.
395 */
396 if (root != cur) {
397 return(-2);
398 }
399 /*
400 * get the nearest common ancestor.
401 */
402 while (depth1 > depth2) {
403 depth1--;
404 node1 = node1->parent;
405 }
406 while (depth2 > depth1) {
407 depth2--;
408 node2 = node2->parent;
409 }
410 while (node1->parent != node2->parent) {
411 node1 = node1->parent;
412 node2 = node2->parent;
413 /* should not happen but just in case ... */
414 if ((node1 == NULL) || (node2 == NULL))
415 return(-2);
416 }
417 /*
418 * Find who's first.
419 */
420 if (node1 == node2->prev)
421 return(1);
422 if (node1 == node2->next)
423 return(-1);
424 /*
425 * Speedup using document order if available.
426 */
427 if ((node1->type == XML_ELEMENT_NODE) &&
428 (node2->type == XML_ELEMENT_NODE) &&
429 (0 > (ptrdiff_t) node1->content) &&
430 (0 > (ptrdiff_t) node2->content) &&
431 (node1->doc == node2->doc)) {
432
433 l1 = -((ptrdiff_t) node1->content);
434 l2 = -((ptrdiff_t) node2->content);
435 if (l1 < l2)
436 return(1);
437 if (l1 > l2)
438 return(-1);
439 }
440
441 for (cur = node1->next;cur != NULL;cur = cur->next)
442 if (cur == node2)
443 return(1);
444 return(-1); /* assume there is no sibling list corruption */
445 }
446 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
447
448 /*
449 * Wrapper for the Timsort algorithm from timsort.h
450 */
451 #ifdef WITH_TIM_SORT
452 #define SORT_NAME libxml_domnode
453 #define SORT_TYPE xmlNodePtr
454 /**
455 * wrap_cmp:
456 * @x: a node
457 * @y: another node
458 *
459 * Comparison function for the Timsort implementation
460 *
461 * Returns -2 in case of error -1 if first point < second point, 0 if
462 * it's the same node, +1 otherwise
463 */
464 static
465 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
466 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)467 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
468 {
469 int res = xmlXPathCmpNodesExt(x, y);
470 return res == -2 ? res : -res;
471 }
472 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)473 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
474 {
475 int res = xmlXPathCmpNodes(x, y);
476 return res == -2 ? res : -res;
477 }
478 #endif
479 #define SORT_CMP(x, y) (wrap_cmp(x, y))
480 #include "timsort.h"
481 #endif /* WITH_TIM_SORT */
482
483 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
484
485 /************************************************************************
486 * *
487 * Floating point stuff *
488 * *
489 ************************************************************************/
490
491 double xmlXPathNAN;
492 double xmlXPathPINF;
493 double xmlXPathNINF;
494
495 /**
496 * xmlXPathInit:
497 *
498 * Initialize the XPath environment
499 */
500 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
501 void
xmlXPathInit(void)502 xmlXPathInit(void) {
503 /* MSVC doesn't allow division by zero in constant expressions. */
504 double zero = 0.0;
505 xmlXPathNAN = 0.0 / zero;
506 xmlXPathPINF = 1.0 / zero;
507 xmlXPathNINF = -xmlXPathPINF;
508 }
509
510 /**
511 * xmlXPathIsNaN:
512 * @val: a double value
513 *
514 * Returns 1 if the value is a NaN, 0 otherwise
515 */
516 int
xmlXPathIsNaN(double val)517 xmlXPathIsNaN(double val) {
518 #ifdef isnan
519 return isnan(val);
520 #else
521 return !(val == val);
522 #endif
523 }
524
525 /**
526 * xmlXPathIsInf:
527 * @val: a double value
528 *
529 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
530 */
531 int
xmlXPathIsInf(double val)532 xmlXPathIsInf(double val) {
533 #ifdef isinf
534 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
535 #else
536 if (val >= xmlXPathPINF)
537 return 1;
538 if (val <= -xmlXPathPINF)
539 return -1;
540 return 0;
541 #endif
542 }
543
544 #endif /* SCHEMAS or XPATH */
545
546 #ifdef LIBXML_XPATH_ENABLED
547
548 /*
549 * TODO: when compatibility allows remove all "fake node libxslt" strings
550 * the test should just be name[0] = ' '
551 */
552 #ifdef DEBUG_XPATH_EXPRESSION
553 #define DEBUG_STEP
554 #define DEBUG_EXPR
555 #define DEBUG_EVAL_COUNTS
556 #endif
557
558 static xmlNs xmlXPathXMLNamespaceStruct = {
559 NULL,
560 XML_NAMESPACE_DECL,
561 XML_XML_NAMESPACE,
562 BAD_CAST "xml",
563 NULL,
564 NULL
565 };
566 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
567 #ifndef LIBXML_THREAD_ENABLED
568 /*
569 * Optimizer is disabled only when threaded apps are detected while
570 * the library ain't compiled for thread safety.
571 */
572 static int xmlXPathDisableOptimizer = 0;
573 #endif
574
575 /************************************************************************
576 * *
577 * Error handling routines *
578 * *
579 ************************************************************************/
580
581 /**
582 * XP_ERRORNULL:
583 * @X: the error code
584 *
585 * Macro to raise an XPath error and return NULL.
586 */
587 #define XP_ERRORNULL(X) \
588 { xmlXPathErr(ctxt, X); return(NULL); }
589
590 /*
591 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
592 */
593 static const char *xmlXPathErrorMessages[] = {
594 "Ok\n",
595 "Number encoding\n",
596 "Unfinished literal\n",
597 "Start of literal\n",
598 "Expected $ for variable reference\n",
599 "Undefined variable\n",
600 "Invalid predicate\n",
601 "Invalid expression\n",
602 "Missing closing curly brace\n",
603 "Unregistered function\n",
604 "Invalid operand\n",
605 "Invalid type\n",
606 "Invalid number of arguments\n",
607 "Invalid context size\n",
608 "Invalid context position\n",
609 "Memory allocation error\n",
610 "Syntax error\n",
611 "Resource error\n",
612 "Sub resource error\n",
613 "Undefined namespace prefix\n",
614 "Encoding error\n",
615 "Char out of XML range\n",
616 "Invalid or incomplete context\n",
617 "Stack usage error\n",
618 "Forbidden variable\n",
619 "Operation limit exceeded\n",
620 "Recursion limit exceeded\n",
621 "?? Unknown error ??\n" /* Must be last in the list! */
622 };
623 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
624 sizeof(xmlXPathErrorMessages[0])) - 1)
625 /**
626 * xmlXPathErrMemory:
627 * @ctxt: an XPath context
628 * @extra: extra information
629 *
630 * Handle a redefinition of attribute error
631 */
632 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)633 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
634 {
635 if (ctxt != NULL) {
636 xmlResetError(&ctxt->lastError);
637 if (extra) {
638 xmlChar buf[200];
639
640 xmlStrPrintf(buf, 200,
641 "Memory allocation failed : %s\n",
642 extra);
643 ctxt->lastError.message = (char *) xmlStrdup(buf);
644 } else {
645 ctxt->lastError.message = (char *)
646 xmlStrdup(BAD_CAST "Memory allocation failed\n");
647 }
648 ctxt->lastError.domain = XML_FROM_XPATH;
649 ctxt->lastError.code = XML_ERR_NO_MEMORY;
650 if (ctxt->error != NULL)
651 ctxt->error(ctxt->userData, &ctxt->lastError);
652 } else {
653 if (extra)
654 __xmlRaiseError(NULL, NULL, NULL,
655 NULL, NULL, XML_FROM_XPATH,
656 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
657 extra, NULL, NULL, 0, 0,
658 "Memory allocation failed : %s\n", extra);
659 else
660 __xmlRaiseError(NULL, NULL, NULL,
661 NULL, NULL, XML_FROM_XPATH,
662 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
663 NULL, NULL, NULL, 0, 0,
664 "Memory allocation failed\n");
665 }
666 }
667
668 /**
669 * xmlXPathPErrMemory:
670 * @ctxt: an XPath parser context
671 * @extra: extra information
672 *
673 * Handle a redefinition of attribute error
674 */
675 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)676 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
677 {
678 if (ctxt == NULL)
679 xmlXPathErrMemory(NULL, extra);
680 else {
681 ctxt->error = XPATH_MEMORY_ERROR;
682 xmlXPathErrMemory(ctxt->context, extra);
683 }
684 }
685
686 /**
687 * xmlXPathErr:
688 * @ctxt: a XPath parser context
689 * @error: the error code
690 *
691 * Handle an XPath error
692 */
693 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)694 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
695 {
696 if ((error < 0) || (error > MAXERRNO))
697 error = MAXERRNO;
698 if (ctxt == NULL) {
699 __xmlRaiseError(NULL, NULL, NULL,
700 NULL, NULL, XML_FROM_XPATH,
701 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702 XML_ERR_ERROR, NULL, 0,
703 NULL, NULL, NULL, 0, 0,
704 "%s", xmlXPathErrorMessages[error]);
705 return;
706 }
707 ctxt->error = error;
708 if (ctxt->context == NULL) {
709 __xmlRaiseError(NULL, NULL, NULL,
710 NULL, NULL, XML_FROM_XPATH,
711 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
712 XML_ERR_ERROR, NULL, 0,
713 (const char *) ctxt->base, NULL, NULL,
714 ctxt->cur - ctxt->base, 0,
715 "%s", xmlXPathErrorMessages[error]);
716 return;
717 }
718
719 /* cleanup current last error */
720 xmlResetError(&ctxt->context->lastError);
721
722 ctxt->context->lastError.domain = XML_FROM_XPATH;
723 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
724 XPATH_EXPRESSION_OK;
725 ctxt->context->lastError.level = XML_ERR_ERROR;
726 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
727 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
728 ctxt->context->lastError.node = ctxt->context->debugNode;
729 if (ctxt->context->error != NULL) {
730 ctxt->context->error(ctxt->context->userData,
731 &ctxt->context->lastError);
732 } else {
733 __xmlRaiseError(NULL, NULL, NULL,
734 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
735 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
736 XML_ERR_ERROR, NULL, 0,
737 (const char *) ctxt->base, NULL, NULL,
738 ctxt->cur - ctxt->base, 0,
739 "%s", xmlXPathErrorMessages[error]);
740 }
741
742 }
743
744 /**
745 * xmlXPatherror:
746 * @ctxt: the XPath Parser context
747 * @file: the file name
748 * @line: the line number
749 * @no: the error number
750 *
751 * Formats an error message.
752 */
753 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)754 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
755 int line ATTRIBUTE_UNUSED, int no) {
756 xmlXPathErr(ctxt, no);
757 }
758
759 /**
760 * xmlXPathCheckOpLimit:
761 * @ctxt: the XPath Parser context
762 * @opCount: the number of operations to be added
763 *
764 * Adds opCount to the running total of operations and returns -1 if the
765 * operation limit is exceeded. Returns 0 otherwise.
766 */
767 static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt,unsigned long opCount)768 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
769 xmlXPathContextPtr xpctxt = ctxt->context;
770
771 if ((opCount > xpctxt->opLimit) ||
772 (xpctxt->opCount > xpctxt->opLimit - opCount)) {
773 xpctxt->opCount = xpctxt->opLimit;
774 xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
775 return(-1);
776 }
777
778 xpctxt->opCount += opCount;
779 return(0);
780 }
781
782 #define OP_LIMIT_EXCEEDED(ctxt, n) \
783 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
784
785 /************************************************************************
786 * *
787 * Utilities *
788 * *
789 ************************************************************************/
790
791 /**
792 * xsltPointerList:
793 *
794 * Pointer-list for various purposes.
795 */
796 typedef struct _xmlPointerList xmlPointerList;
797 typedef xmlPointerList *xmlPointerListPtr;
798 struct _xmlPointerList {
799 void **items;
800 int number;
801 int size;
802 };
803 /*
804 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
805 * and here, we should make the functions public.
806 */
807 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)808 xmlPointerListAddSize(xmlPointerListPtr list,
809 void *item,
810 int initialSize)
811 {
812 if (list->items == NULL) {
813 if (initialSize <= 0)
814 initialSize = 1;
815 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
816 if (list->items == NULL) {
817 xmlXPathErrMemory(NULL,
818 "xmlPointerListCreate: allocating item\n");
819 return(-1);
820 }
821 list->number = 0;
822 list->size = initialSize;
823 } else if (list->size <= list->number) {
824 if (list->size > 50000000) {
825 xmlXPathErrMemory(NULL,
826 "xmlPointerListAddSize: re-allocating item\n");
827 return(-1);
828 }
829 list->size *= 2;
830 list->items = (void **) xmlRealloc(list->items,
831 list->size * sizeof(void *));
832 if (list->items == NULL) {
833 xmlXPathErrMemory(NULL,
834 "xmlPointerListAddSize: re-allocating item\n");
835 list->size = 0;
836 return(-1);
837 }
838 }
839 list->items[list->number++] = item;
840 return(0);
841 }
842
843 /**
844 * xsltPointerListCreate:
845 *
846 * Creates an xsltPointerList structure.
847 *
848 * Returns a xsltPointerList structure or NULL in case of an error.
849 */
850 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)851 xmlPointerListCreate(int initialSize)
852 {
853 xmlPointerListPtr ret;
854
855 ret = xmlMalloc(sizeof(xmlPointerList));
856 if (ret == NULL) {
857 xmlXPathErrMemory(NULL,
858 "xmlPointerListCreate: allocating item\n");
859 return (NULL);
860 }
861 memset(ret, 0, sizeof(xmlPointerList));
862 if (initialSize > 0) {
863 xmlPointerListAddSize(ret, NULL, initialSize);
864 ret->number = 0;
865 }
866 return (ret);
867 }
868
869 /**
870 * xsltPointerListFree:
871 *
872 * Frees the xsltPointerList structure. This does not free
873 * the content of the list.
874 */
875 static void
xmlPointerListFree(xmlPointerListPtr list)876 xmlPointerListFree(xmlPointerListPtr list)
877 {
878 if (list == NULL)
879 return;
880 if (list->items != NULL)
881 xmlFree(list->items);
882 xmlFree(list);
883 }
884
885 /************************************************************************
886 * *
887 * Parser Types *
888 * *
889 ************************************************************************/
890
891 /*
892 * Types are private:
893 */
894
895 typedef enum {
896 XPATH_OP_END=0,
897 XPATH_OP_AND,
898 XPATH_OP_OR,
899 XPATH_OP_EQUAL,
900 XPATH_OP_CMP,
901 XPATH_OP_PLUS,
902 XPATH_OP_MULT,
903 XPATH_OP_UNION,
904 XPATH_OP_ROOT,
905 XPATH_OP_NODE,
906 XPATH_OP_COLLECT,
907 XPATH_OP_VALUE, /* 11 */
908 XPATH_OP_VARIABLE,
909 XPATH_OP_FUNCTION,
910 XPATH_OP_ARG,
911 XPATH_OP_PREDICATE,
912 XPATH_OP_FILTER, /* 16 */
913 XPATH_OP_SORT /* 17 */
914 #ifdef LIBXML_XPTR_ENABLED
915 ,XPATH_OP_RANGETO
916 #endif
917 } xmlXPathOp;
918
919 typedef enum {
920 AXIS_ANCESTOR = 1,
921 AXIS_ANCESTOR_OR_SELF,
922 AXIS_ATTRIBUTE,
923 AXIS_CHILD,
924 AXIS_DESCENDANT,
925 AXIS_DESCENDANT_OR_SELF,
926 AXIS_FOLLOWING,
927 AXIS_FOLLOWING_SIBLING,
928 AXIS_NAMESPACE,
929 AXIS_PARENT,
930 AXIS_PRECEDING,
931 AXIS_PRECEDING_SIBLING,
932 AXIS_SELF
933 } xmlXPathAxisVal;
934
935 typedef enum {
936 NODE_TEST_NONE = 0,
937 NODE_TEST_TYPE = 1,
938 NODE_TEST_PI = 2,
939 NODE_TEST_ALL = 3,
940 NODE_TEST_NS = 4,
941 NODE_TEST_NAME = 5
942 } xmlXPathTestVal;
943
944 typedef enum {
945 NODE_TYPE_NODE = 0,
946 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
947 NODE_TYPE_TEXT = XML_TEXT_NODE,
948 NODE_TYPE_PI = XML_PI_NODE
949 } xmlXPathTypeVal;
950
951 typedef struct _xmlXPathStepOp xmlXPathStepOp;
952 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
953 struct _xmlXPathStepOp {
954 xmlXPathOp op; /* The identifier of the operation */
955 int ch1; /* First child */
956 int ch2; /* Second child */
957 int value;
958 int value2;
959 int value3;
960 void *value4;
961 void *value5;
962 xmlXPathFunction cache;
963 void *cacheURI;
964 };
965
966 struct _xmlXPathCompExpr {
967 int nbStep; /* Number of steps in this expression */
968 int maxStep; /* Maximum number of steps allocated */
969 xmlXPathStepOp *steps; /* ops for computation of this expression */
970 int last; /* index of last step in expression */
971 xmlChar *expr; /* the expression being computed */
972 xmlDictPtr dict; /* the dictionary to use if any */
973 #ifdef DEBUG_EVAL_COUNTS
974 int nb;
975 xmlChar *string;
976 #endif
977 #ifdef XPATH_STREAMING
978 xmlPatternPtr stream;
979 #endif
980 };
981
982 /************************************************************************
983 * *
984 * Forward declarations *
985 * *
986 ************************************************************************/
987 static void
988 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
989 static void
990 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
991 static int
992 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
993 xmlXPathStepOpPtr op, xmlNodePtr *first);
994 static int
995 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
996 xmlXPathStepOpPtr op,
997 int isPredicate);
998 static void
999 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1000
1001 /************************************************************************
1002 * *
1003 * Parser Type functions *
1004 * *
1005 ************************************************************************/
1006
1007 /**
1008 * xmlXPathNewCompExpr:
1009 *
1010 * Create a new Xpath component
1011 *
1012 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1013 */
1014 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)1015 xmlXPathNewCompExpr(void) {
1016 xmlXPathCompExprPtr cur;
1017
1018 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1019 if (cur == NULL) {
1020 xmlXPathErrMemory(NULL, "allocating component\n");
1021 return(NULL);
1022 }
1023 memset(cur, 0, sizeof(xmlXPathCompExpr));
1024 cur->maxStep = 10;
1025 cur->nbStep = 0;
1026 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1027 sizeof(xmlXPathStepOp));
1028 if (cur->steps == NULL) {
1029 xmlXPathErrMemory(NULL, "allocating steps\n");
1030 xmlFree(cur);
1031 return(NULL);
1032 }
1033 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1034 cur->last = -1;
1035 #ifdef DEBUG_EVAL_COUNTS
1036 cur->nb = 0;
1037 #endif
1038 return(cur);
1039 }
1040
1041 /**
1042 * xmlXPathFreeCompExpr:
1043 * @comp: an XPATH comp
1044 *
1045 * Free up the memory allocated by @comp
1046 */
1047 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1048 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1049 {
1050 xmlXPathStepOpPtr op;
1051 int i;
1052
1053 if (comp == NULL)
1054 return;
1055 if (comp->dict == NULL) {
1056 for (i = 0; i < comp->nbStep; i++) {
1057 op = &comp->steps[i];
1058 if (op->value4 != NULL) {
1059 if (op->op == XPATH_OP_VALUE)
1060 xmlXPathFreeObject(op->value4);
1061 else
1062 xmlFree(op->value4);
1063 }
1064 if (op->value5 != NULL)
1065 xmlFree(op->value5);
1066 }
1067 } else {
1068 for (i = 0; i < comp->nbStep; i++) {
1069 op = &comp->steps[i];
1070 if (op->value4 != NULL) {
1071 if (op->op == XPATH_OP_VALUE)
1072 xmlXPathFreeObject(op->value4);
1073 }
1074 }
1075 xmlDictFree(comp->dict);
1076 }
1077 if (comp->steps != NULL) {
1078 xmlFree(comp->steps);
1079 }
1080 #ifdef DEBUG_EVAL_COUNTS
1081 if (comp->string != NULL) {
1082 xmlFree(comp->string);
1083 }
1084 #endif
1085 #ifdef XPATH_STREAMING
1086 if (comp->stream != NULL) {
1087 xmlFreePatternList(comp->stream);
1088 }
1089 #endif
1090 if (comp->expr != NULL) {
1091 xmlFree(comp->expr);
1092 }
1093
1094 xmlFree(comp);
1095 }
1096
1097 /**
1098 * xmlXPathCompExprAdd:
1099 * @comp: the compiled expression
1100 * @ch1: first child index
1101 * @ch2: second child index
1102 * @op: an op
1103 * @value: the first int value
1104 * @value2: the second int value
1105 * @value3: the third int value
1106 * @value4: the first string value
1107 * @value5: the second string value
1108 *
1109 * Add a step to an XPath Compiled Expression
1110 *
1111 * Returns -1 in case of failure, the index otherwise
1112 */
1113 static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1114 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1115 xmlXPathOp op, int value,
1116 int value2, int value3, void *value4, void *value5) {
1117 xmlXPathCompExprPtr comp = ctxt->comp;
1118 if (comp->nbStep >= comp->maxStep) {
1119 xmlXPathStepOp *real;
1120
1121 if (comp->maxStep >= XPATH_MAX_STEPS) {
1122 xmlXPathPErrMemory(ctxt, "adding step\n");
1123 return(-1);
1124 }
1125 comp->maxStep *= 2;
1126 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1127 comp->maxStep * sizeof(xmlXPathStepOp));
1128 if (real == NULL) {
1129 comp->maxStep /= 2;
1130 xmlXPathPErrMemory(ctxt, "adding step\n");
1131 return(-1);
1132 }
1133 comp->steps = real;
1134 }
1135 comp->last = comp->nbStep;
1136 comp->steps[comp->nbStep].ch1 = ch1;
1137 comp->steps[comp->nbStep].ch2 = ch2;
1138 comp->steps[comp->nbStep].op = op;
1139 comp->steps[comp->nbStep].value = value;
1140 comp->steps[comp->nbStep].value2 = value2;
1141 comp->steps[comp->nbStep].value3 = value3;
1142 if ((comp->dict != NULL) &&
1143 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1144 (op == XPATH_OP_COLLECT))) {
1145 if (value4 != NULL) {
1146 comp->steps[comp->nbStep].value4 = (xmlChar *)
1147 (void *)xmlDictLookup(comp->dict, value4, -1);
1148 xmlFree(value4);
1149 } else
1150 comp->steps[comp->nbStep].value4 = NULL;
1151 if (value5 != NULL) {
1152 comp->steps[comp->nbStep].value5 = (xmlChar *)
1153 (void *)xmlDictLookup(comp->dict, value5, -1);
1154 xmlFree(value5);
1155 } else
1156 comp->steps[comp->nbStep].value5 = NULL;
1157 } else {
1158 comp->steps[comp->nbStep].value4 = value4;
1159 comp->steps[comp->nbStep].value5 = value5;
1160 }
1161 comp->steps[comp->nbStep].cache = NULL;
1162 return(comp->nbStep++);
1163 }
1164
1165 /**
1166 * xmlXPathCompSwap:
1167 * @comp: the compiled expression
1168 * @op: operation index
1169 *
1170 * Swaps 2 operations in the compiled expression
1171 */
1172 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1173 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1174 int tmp;
1175
1176 #ifndef LIBXML_THREAD_ENABLED
1177 /*
1178 * Since this manipulates possibly shared variables, this is
1179 * disabled if one detects that the library is used in a multithreaded
1180 * application
1181 */
1182 if (xmlXPathDisableOptimizer)
1183 return;
1184 #endif
1185
1186 tmp = op->ch1;
1187 op->ch1 = op->ch2;
1188 op->ch2 = tmp;
1189 }
1190
1191 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1192 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1193 (op), (val), (val2), (val3), (val4), (val5))
1194 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1195 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1196 (op), (val), (val2), (val3), (val4), (val5))
1197
1198 #define PUSH_LEAVE_EXPR(op, val, val2) \
1199 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1200
1201 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1202 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1203
1204 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1205 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1206 (val), (val2), 0 ,NULL ,NULL)
1207
1208 /************************************************************************
1209 * *
1210 * XPath object cache structures *
1211 * *
1212 ************************************************************************/
1213
1214 /* #define XP_DEFAULT_CACHE_ON */
1215
1216 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1217
1218 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1219 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1220 struct _xmlXPathContextCache {
1221 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1222 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1223 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1224 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1225 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1226 int maxNodeset;
1227 int maxString;
1228 int maxBoolean;
1229 int maxNumber;
1230 int maxMisc;
1231 #ifdef XP_DEBUG_OBJ_USAGE
1232 int dbgCachedAll;
1233 int dbgCachedNodeset;
1234 int dbgCachedString;
1235 int dbgCachedBool;
1236 int dbgCachedNumber;
1237 int dbgCachedPoint;
1238 int dbgCachedRange;
1239 int dbgCachedLocset;
1240 int dbgCachedUsers;
1241 int dbgCachedXSLTTree;
1242 int dbgCachedUndefined;
1243
1244
1245 int dbgReusedAll;
1246 int dbgReusedNodeset;
1247 int dbgReusedString;
1248 int dbgReusedBool;
1249 int dbgReusedNumber;
1250 int dbgReusedPoint;
1251 int dbgReusedRange;
1252 int dbgReusedLocset;
1253 int dbgReusedUsers;
1254 int dbgReusedXSLTTree;
1255 int dbgReusedUndefined;
1256
1257 #endif
1258 };
1259
1260 /************************************************************************
1261 * *
1262 * Debugging related functions *
1263 * *
1264 ************************************************************************/
1265
1266 #define STRANGE \
1267 xmlGenericError(xmlGenericErrorContext, \
1268 "Internal error at %s:%d\n", \
1269 __FILE__, __LINE__);
1270
1271 #ifdef LIBXML_DEBUG_ENABLED
1272 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1273 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1274 int i;
1275 char shift[100];
1276
1277 for (i = 0;((i < depth) && (i < 25));i++)
1278 shift[2 * i] = shift[2 * i + 1] = ' ';
1279 shift[2 * i] = shift[2 * i + 1] = 0;
1280 if (cur == NULL) {
1281 fprintf(output, "%s", shift);
1282 fprintf(output, "Node is NULL !\n");
1283 return;
1284
1285 }
1286
1287 if ((cur->type == XML_DOCUMENT_NODE) ||
1288 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1289 fprintf(output, "%s", shift);
1290 fprintf(output, " /\n");
1291 } else if (cur->type == XML_ATTRIBUTE_NODE)
1292 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1293 else
1294 xmlDebugDumpOneNode(output, cur, depth);
1295 }
1296 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1297 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1298 xmlNodePtr tmp;
1299 int i;
1300 char shift[100];
1301
1302 for (i = 0;((i < depth) && (i < 25));i++)
1303 shift[2 * i] = shift[2 * i + 1] = ' ';
1304 shift[2 * i] = shift[2 * i + 1] = 0;
1305 if (cur == NULL) {
1306 fprintf(output, "%s", shift);
1307 fprintf(output, "Node is NULL !\n");
1308 return;
1309
1310 }
1311
1312 while (cur != NULL) {
1313 tmp = cur;
1314 cur = cur->next;
1315 xmlDebugDumpOneNode(output, tmp, depth);
1316 }
1317 }
1318
1319 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1320 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1321 int i;
1322 char shift[100];
1323
1324 for (i = 0;((i < depth) && (i < 25));i++)
1325 shift[2 * i] = shift[2 * i + 1] = ' ';
1326 shift[2 * i] = shift[2 * i + 1] = 0;
1327
1328 if (cur == NULL) {
1329 fprintf(output, "%s", shift);
1330 fprintf(output, "NodeSet is NULL !\n");
1331 return;
1332
1333 }
1334
1335 if (cur != NULL) {
1336 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1337 for (i = 0;i < cur->nodeNr;i++) {
1338 fprintf(output, "%s", shift);
1339 fprintf(output, "%d", i + 1);
1340 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1341 }
1342 }
1343 }
1344
1345 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1346 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1347 int i;
1348 char shift[100];
1349
1350 for (i = 0;((i < depth) && (i < 25));i++)
1351 shift[2 * i] = shift[2 * i + 1] = ' ';
1352 shift[2 * i] = shift[2 * i + 1] = 0;
1353
1354 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1355 fprintf(output, "%s", shift);
1356 fprintf(output, "Value Tree is NULL !\n");
1357 return;
1358
1359 }
1360
1361 fprintf(output, "%s", shift);
1362 fprintf(output, "%d", i + 1);
1363 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1364 }
1365 #if defined(LIBXML_XPTR_ENABLED)
1366 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1367 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1368 int i;
1369 char shift[100];
1370
1371 for (i = 0;((i < depth) && (i < 25));i++)
1372 shift[2 * i] = shift[2 * i + 1] = ' ';
1373 shift[2 * i] = shift[2 * i + 1] = 0;
1374
1375 if (cur == NULL) {
1376 fprintf(output, "%s", shift);
1377 fprintf(output, "LocationSet is NULL !\n");
1378 return;
1379
1380 }
1381
1382 for (i = 0;i < cur->locNr;i++) {
1383 fprintf(output, "%s", shift);
1384 fprintf(output, "%d : ", i + 1);
1385 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1386 }
1387 }
1388 #endif /* LIBXML_XPTR_ENABLED */
1389
1390 /**
1391 * xmlXPathDebugDumpObject:
1392 * @output: the FILE * to dump the output
1393 * @cur: the object to inspect
1394 * @depth: indentation level
1395 *
1396 * Dump the content of the object for debugging purposes
1397 */
1398 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1399 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1400 int i;
1401 char shift[100];
1402
1403 if (output == NULL) return;
1404
1405 for (i = 0;((i < depth) && (i < 25));i++)
1406 shift[2 * i] = shift[2 * i + 1] = ' ';
1407 shift[2 * i] = shift[2 * i + 1] = 0;
1408
1409
1410 fprintf(output, "%s", shift);
1411
1412 if (cur == NULL) {
1413 fprintf(output, "Object is empty (NULL)\n");
1414 return;
1415 }
1416 switch(cur->type) {
1417 case XPATH_UNDEFINED:
1418 fprintf(output, "Object is uninitialized\n");
1419 break;
1420 case XPATH_NODESET:
1421 fprintf(output, "Object is a Node Set :\n");
1422 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1423 break;
1424 case XPATH_XSLT_TREE:
1425 fprintf(output, "Object is an XSLT value tree :\n");
1426 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1427 break;
1428 case XPATH_BOOLEAN:
1429 fprintf(output, "Object is a Boolean : ");
1430 if (cur->boolval) fprintf(output, "true\n");
1431 else fprintf(output, "false\n");
1432 break;
1433 case XPATH_NUMBER:
1434 switch (xmlXPathIsInf(cur->floatval)) {
1435 case 1:
1436 fprintf(output, "Object is a number : Infinity\n");
1437 break;
1438 case -1:
1439 fprintf(output, "Object is a number : -Infinity\n");
1440 break;
1441 default:
1442 if (xmlXPathIsNaN(cur->floatval)) {
1443 fprintf(output, "Object is a number : NaN\n");
1444 } else if (cur->floatval == 0) {
1445 /* Omit sign for negative zero. */
1446 fprintf(output, "Object is a number : 0\n");
1447 } else {
1448 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1449 }
1450 }
1451 break;
1452 case XPATH_STRING:
1453 fprintf(output, "Object is a string : ");
1454 xmlDebugDumpString(output, cur->stringval);
1455 fprintf(output, "\n");
1456 break;
1457 case XPATH_POINT:
1458 fprintf(output, "Object is a point : index %d in node", cur->index);
1459 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1460 fprintf(output, "\n");
1461 break;
1462 case XPATH_RANGE:
1463 if ((cur->user2 == NULL) ||
1464 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1465 fprintf(output, "Object is a collapsed range :\n");
1466 fprintf(output, "%s", shift);
1467 if (cur->index >= 0)
1468 fprintf(output, "index %d in ", cur->index);
1469 fprintf(output, "node\n");
1470 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1471 depth + 1);
1472 } else {
1473 fprintf(output, "Object is a range :\n");
1474 fprintf(output, "%s", shift);
1475 fprintf(output, "From ");
1476 if (cur->index >= 0)
1477 fprintf(output, "index %d in ", cur->index);
1478 fprintf(output, "node\n");
1479 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1480 depth + 1);
1481 fprintf(output, "%s", shift);
1482 fprintf(output, "To ");
1483 if (cur->index2 >= 0)
1484 fprintf(output, "index %d in ", cur->index2);
1485 fprintf(output, "node\n");
1486 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1487 depth + 1);
1488 fprintf(output, "\n");
1489 }
1490 break;
1491 case XPATH_LOCATIONSET:
1492 #if defined(LIBXML_XPTR_ENABLED)
1493 fprintf(output, "Object is a Location Set:\n");
1494 xmlXPathDebugDumpLocationSet(output,
1495 (xmlLocationSetPtr) cur->user, depth);
1496 #endif
1497 break;
1498 case XPATH_USERS:
1499 fprintf(output, "Object is user defined\n");
1500 break;
1501 }
1502 }
1503
1504 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1505 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1506 xmlXPathStepOpPtr op, int depth) {
1507 int i;
1508 char shift[100];
1509
1510 for (i = 0;((i < depth) && (i < 25));i++)
1511 shift[2 * i] = shift[2 * i + 1] = ' ';
1512 shift[2 * i] = shift[2 * i + 1] = 0;
1513
1514 fprintf(output, "%s", shift);
1515 if (op == NULL) {
1516 fprintf(output, "Step is NULL\n");
1517 return;
1518 }
1519 switch (op->op) {
1520 case XPATH_OP_END:
1521 fprintf(output, "END"); break;
1522 case XPATH_OP_AND:
1523 fprintf(output, "AND"); break;
1524 case XPATH_OP_OR:
1525 fprintf(output, "OR"); break;
1526 case XPATH_OP_EQUAL:
1527 if (op->value)
1528 fprintf(output, "EQUAL =");
1529 else
1530 fprintf(output, "EQUAL !=");
1531 break;
1532 case XPATH_OP_CMP:
1533 if (op->value)
1534 fprintf(output, "CMP <");
1535 else
1536 fprintf(output, "CMP >");
1537 if (!op->value2)
1538 fprintf(output, "=");
1539 break;
1540 case XPATH_OP_PLUS:
1541 if (op->value == 0)
1542 fprintf(output, "PLUS -");
1543 else if (op->value == 1)
1544 fprintf(output, "PLUS +");
1545 else if (op->value == 2)
1546 fprintf(output, "PLUS unary -");
1547 else if (op->value == 3)
1548 fprintf(output, "PLUS unary - -");
1549 break;
1550 case XPATH_OP_MULT:
1551 if (op->value == 0)
1552 fprintf(output, "MULT *");
1553 else if (op->value == 1)
1554 fprintf(output, "MULT div");
1555 else
1556 fprintf(output, "MULT mod");
1557 break;
1558 case XPATH_OP_UNION:
1559 fprintf(output, "UNION"); break;
1560 case XPATH_OP_ROOT:
1561 fprintf(output, "ROOT"); break;
1562 case XPATH_OP_NODE:
1563 fprintf(output, "NODE"); break;
1564 case XPATH_OP_SORT:
1565 fprintf(output, "SORT"); break;
1566 case XPATH_OP_COLLECT: {
1567 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1568 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1569 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1570 const xmlChar *prefix = op->value4;
1571 const xmlChar *name = op->value5;
1572
1573 fprintf(output, "COLLECT ");
1574 switch (axis) {
1575 case AXIS_ANCESTOR:
1576 fprintf(output, " 'ancestors' "); break;
1577 case AXIS_ANCESTOR_OR_SELF:
1578 fprintf(output, " 'ancestors-or-self' "); break;
1579 case AXIS_ATTRIBUTE:
1580 fprintf(output, " 'attributes' "); break;
1581 case AXIS_CHILD:
1582 fprintf(output, " 'child' "); break;
1583 case AXIS_DESCENDANT:
1584 fprintf(output, " 'descendant' "); break;
1585 case AXIS_DESCENDANT_OR_SELF:
1586 fprintf(output, " 'descendant-or-self' "); break;
1587 case AXIS_FOLLOWING:
1588 fprintf(output, " 'following' "); break;
1589 case AXIS_FOLLOWING_SIBLING:
1590 fprintf(output, " 'following-siblings' "); break;
1591 case AXIS_NAMESPACE:
1592 fprintf(output, " 'namespace' "); break;
1593 case AXIS_PARENT:
1594 fprintf(output, " 'parent' "); break;
1595 case AXIS_PRECEDING:
1596 fprintf(output, " 'preceding' "); break;
1597 case AXIS_PRECEDING_SIBLING:
1598 fprintf(output, " 'preceding-sibling' "); break;
1599 case AXIS_SELF:
1600 fprintf(output, " 'self' "); break;
1601 }
1602 switch (test) {
1603 case NODE_TEST_NONE:
1604 fprintf(output, "'none' "); break;
1605 case NODE_TEST_TYPE:
1606 fprintf(output, "'type' "); break;
1607 case NODE_TEST_PI:
1608 fprintf(output, "'PI' "); break;
1609 case NODE_TEST_ALL:
1610 fprintf(output, "'all' "); break;
1611 case NODE_TEST_NS:
1612 fprintf(output, "'namespace' "); break;
1613 case NODE_TEST_NAME:
1614 fprintf(output, "'name' "); break;
1615 }
1616 switch (type) {
1617 case NODE_TYPE_NODE:
1618 fprintf(output, "'node' "); break;
1619 case NODE_TYPE_COMMENT:
1620 fprintf(output, "'comment' "); break;
1621 case NODE_TYPE_TEXT:
1622 fprintf(output, "'text' "); break;
1623 case NODE_TYPE_PI:
1624 fprintf(output, "'PI' "); break;
1625 }
1626 if (prefix != NULL)
1627 fprintf(output, "%s:", prefix);
1628 if (name != NULL)
1629 fprintf(output, "%s", (const char *) name);
1630 break;
1631
1632 }
1633 case XPATH_OP_VALUE: {
1634 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1635
1636 fprintf(output, "ELEM ");
1637 xmlXPathDebugDumpObject(output, object, 0);
1638 goto finish;
1639 }
1640 case XPATH_OP_VARIABLE: {
1641 const xmlChar *prefix = op->value5;
1642 const xmlChar *name = op->value4;
1643
1644 if (prefix != NULL)
1645 fprintf(output, "VARIABLE %s:%s", prefix, name);
1646 else
1647 fprintf(output, "VARIABLE %s", name);
1648 break;
1649 }
1650 case XPATH_OP_FUNCTION: {
1651 int nbargs = op->value;
1652 const xmlChar *prefix = op->value5;
1653 const xmlChar *name = op->value4;
1654
1655 if (prefix != NULL)
1656 fprintf(output, "FUNCTION %s:%s(%d args)",
1657 prefix, name, nbargs);
1658 else
1659 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1660 break;
1661 }
1662 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1663 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1664 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1665 #ifdef LIBXML_XPTR_ENABLED
1666 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1667 #endif
1668 default:
1669 fprintf(output, "UNKNOWN %d\n", op->op); return;
1670 }
1671 fprintf(output, "\n");
1672 finish:
1673 if (op->ch1 >= 0)
1674 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1675 if (op->ch2 >= 0)
1676 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1677 }
1678
1679 /**
1680 * xmlXPathDebugDumpCompExpr:
1681 * @output: the FILE * for the output
1682 * @comp: the precompiled XPath expression
1683 * @depth: the indentation level.
1684 *
1685 * Dumps the tree of the compiled XPath expression.
1686 */
1687 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1688 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1689 int depth) {
1690 int i;
1691 char shift[100];
1692
1693 if ((output == NULL) || (comp == NULL)) return;
1694
1695 for (i = 0;((i < depth) && (i < 25));i++)
1696 shift[2 * i] = shift[2 * i + 1] = ' ';
1697 shift[2 * i] = shift[2 * i + 1] = 0;
1698
1699 fprintf(output, "%s", shift);
1700
1701 #ifdef XPATH_STREAMING
1702 if (comp->stream) {
1703 fprintf(output, "Streaming Expression\n");
1704 } else
1705 #endif
1706 {
1707 fprintf(output, "Compiled Expression : %d elements\n",
1708 comp->nbStep);
1709 i = comp->last;
1710 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1711 }
1712 }
1713
1714 #ifdef XP_DEBUG_OBJ_USAGE
1715
1716 /*
1717 * XPath object usage related debugging variables.
1718 */
1719 static int xmlXPathDebugObjCounterUndefined = 0;
1720 static int xmlXPathDebugObjCounterNodeset = 0;
1721 static int xmlXPathDebugObjCounterBool = 0;
1722 static int xmlXPathDebugObjCounterNumber = 0;
1723 static int xmlXPathDebugObjCounterString = 0;
1724 static int xmlXPathDebugObjCounterPoint = 0;
1725 static int xmlXPathDebugObjCounterRange = 0;
1726 static int xmlXPathDebugObjCounterLocset = 0;
1727 static int xmlXPathDebugObjCounterUsers = 0;
1728 static int xmlXPathDebugObjCounterXSLTTree = 0;
1729 static int xmlXPathDebugObjCounterAll = 0;
1730
1731 static int xmlXPathDebugObjTotalUndefined = 0;
1732 static int xmlXPathDebugObjTotalNodeset = 0;
1733 static int xmlXPathDebugObjTotalBool = 0;
1734 static int xmlXPathDebugObjTotalNumber = 0;
1735 static int xmlXPathDebugObjTotalString = 0;
1736 static int xmlXPathDebugObjTotalPoint = 0;
1737 static int xmlXPathDebugObjTotalRange = 0;
1738 static int xmlXPathDebugObjTotalLocset = 0;
1739 static int xmlXPathDebugObjTotalUsers = 0;
1740 static int xmlXPathDebugObjTotalXSLTTree = 0;
1741 static int xmlXPathDebugObjTotalAll = 0;
1742
1743 static int xmlXPathDebugObjMaxUndefined = 0;
1744 static int xmlXPathDebugObjMaxNodeset = 0;
1745 static int xmlXPathDebugObjMaxBool = 0;
1746 static int xmlXPathDebugObjMaxNumber = 0;
1747 static int xmlXPathDebugObjMaxString = 0;
1748 static int xmlXPathDebugObjMaxPoint = 0;
1749 static int xmlXPathDebugObjMaxRange = 0;
1750 static int xmlXPathDebugObjMaxLocset = 0;
1751 static int xmlXPathDebugObjMaxUsers = 0;
1752 static int xmlXPathDebugObjMaxXSLTTree = 0;
1753 static int xmlXPathDebugObjMaxAll = 0;
1754
1755 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1756 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1757 {
1758 if (ctxt != NULL) {
1759 if (ctxt->cache != NULL) {
1760 xmlXPathContextCachePtr cache =
1761 (xmlXPathContextCachePtr) ctxt->cache;
1762
1763 cache->dbgCachedAll = 0;
1764 cache->dbgCachedNodeset = 0;
1765 cache->dbgCachedString = 0;
1766 cache->dbgCachedBool = 0;
1767 cache->dbgCachedNumber = 0;
1768 cache->dbgCachedPoint = 0;
1769 cache->dbgCachedRange = 0;
1770 cache->dbgCachedLocset = 0;
1771 cache->dbgCachedUsers = 0;
1772 cache->dbgCachedXSLTTree = 0;
1773 cache->dbgCachedUndefined = 0;
1774
1775 cache->dbgReusedAll = 0;
1776 cache->dbgReusedNodeset = 0;
1777 cache->dbgReusedString = 0;
1778 cache->dbgReusedBool = 0;
1779 cache->dbgReusedNumber = 0;
1780 cache->dbgReusedPoint = 0;
1781 cache->dbgReusedRange = 0;
1782 cache->dbgReusedLocset = 0;
1783 cache->dbgReusedUsers = 0;
1784 cache->dbgReusedXSLTTree = 0;
1785 cache->dbgReusedUndefined = 0;
1786 }
1787 }
1788
1789 xmlXPathDebugObjCounterUndefined = 0;
1790 xmlXPathDebugObjCounterNodeset = 0;
1791 xmlXPathDebugObjCounterBool = 0;
1792 xmlXPathDebugObjCounterNumber = 0;
1793 xmlXPathDebugObjCounterString = 0;
1794 xmlXPathDebugObjCounterPoint = 0;
1795 xmlXPathDebugObjCounterRange = 0;
1796 xmlXPathDebugObjCounterLocset = 0;
1797 xmlXPathDebugObjCounterUsers = 0;
1798 xmlXPathDebugObjCounterXSLTTree = 0;
1799 xmlXPathDebugObjCounterAll = 0;
1800
1801 xmlXPathDebugObjTotalUndefined = 0;
1802 xmlXPathDebugObjTotalNodeset = 0;
1803 xmlXPathDebugObjTotalBool = 0;
1804 xmlXPathDebugObjTotalNumber = 0;
1805 xmlXPathDebugObjTotalString = 0;
1806 xmlXPathDebugObjTotalPoint = 0;
1807 xmlXPathDebugObjTotalRange = 0;
1808 xmlXPathDebugObjTotalLocset = 0;
1809 xmlXPathDebugObjTotalUsers = 0;
1810 xmlXPathDebugObjTotalXSLTTree = 0;
1811 xmlXPathDebugObjTotalAll = 0;
1812
1813 xmlXPathDebugObjMaxUndefined = 0;
1814 xmlXPathDebugObjMaxNodeset = 0;
1815 xmlXPathDebugObjMaxBool = 0;
1816 xmlXPathDebugObjMaxNumber = 0;
1817 xmlXPathDebugObjMaxString = 0;
1818 xmlXPathDebugObjMaxPoint = 0;
1819 xmlXPathDebugObjMaxRange = 0;
1820 xmlXPathDebugObjMaxLocset = 0;
1821 xmlXPathDebugObjMaxUsers = 0;
1822 xmlXPathDebugObjMaxXSLTTree = 0;
1823 xmlXPathDebugObjMaxAll = 0;
1824
1825 }
1826
1827 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1828 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1829 xmlXPathObjectType objType)
1830 {
1831 int isCached = 0;
1832
1833 if (ctxt != NULL) {
1834 if (ctxt->cache != NULL) {
1835 xmlXPathContextCachePtr cache =
1836 (xmlXPathContextCachePtr) ctxt->cache;
1837
1838 isCached = 1;
1839
1840 cache->dbgReusedAll++;
1841 switch (objType) {
1842 case XPATH_UNDEFINED:
1843 cache->dbgReusedUndefined++;
1844 break;
1845 case XPATH_NODESET:
1846 cache->dbgReusedNodeset++;
1847 break;
1848 case XPATH_BOOLEAN:
1849 cache->dbgReusedBool++;
1850 break;
1851 case XPATH_NUMBER:
1852 cache->dbgReusedNumber++;
1853 break;
1854 case XPATH_STRING:
1855 cache->dbgReusedString++;
1856 break;
1857 case XPATH_POINT:
1858 cache->dbgReusedPoint++;
1859 break;
1860 case XPATH_RANGE:
1861 cache->dbgReusedRange++;
1862 break;
1863 case XPATH_LOCATIONSET:
1864 cache->dbgReusedLocset++;
1865 break;
1866 case XPATH_USERS:
1867 cache->dbgReusedUsers++;
1868 break;
1869 case XPATH_XSLT_TREE:
1870 cache->dbgReusedXSLTTree++;
1871 break;
1872 default:
1873 break;
1874 }
1875 }
1876 }
1877
1878 switch (objType) {
1879 case XPATH_UNDEFINED:
1880 if (! isCached)
1881 xmlXPathDebugObjTotalUndefined++;
1882 xmlXPathDebugObjCounterUndefined++;
1883 if (xmlXPathDebugObjCounterUndefined >
1884 xmlXPathDebugObjMaxUndefined)
1885 xmlXPathDebugObjMaxUndefined =
1886 xmlXPathDebugObjCounterUndefined;
1887 break;
1888 case XPATH_NODESET:
1889 if (! isCached)
1890 xmlXPathDebugObjTotalNodeset++;
1891 xmlXPathDebugObjCounterNodeset++;
1892 if (xmlXPathDebugObjCounterNodeset >
1893 xmlXPathDebugObjMaxNodeset)
1894 xmlXPathDebugObjMaxNodeset =
1895 xmlXPathDebugObjCounterNodeset;
1896 break;
1897 case XPATH_BOOLEAN:
1898 if (! isCached)
1899 xmlXPathDebugObjTotalBool++;
1900 xmlXPathDebugObjCounterBool++;
1901 if (xmlXPathDebugObjCounterBool >
1902 xmlXPathDebugObjMaxBool)
1903 xmlXPathDebugObjMaxBool =
1904 xmlXPathDebugObjCounterBool;
1905 break;
1906 case XPATH_NUMBER:
1907 if (! isCached)
1908 xmlXPathDebugObjTotalNumber++;
1909 xmlXPathDebugObjCounterNumber++;
1910 if (xmlXPathDebugObjCounterNumber >
1911 xmlXPathDebugObjMaxNumber)
1912 xmlXPathDebugObjMaxNumber =
1913 xmlXPathDebugObjCounterNumber;
1914 break;
1915 case XPATH_STRING:
1916 if (! isCached)
1917 xmlXPathDebugObjTotalString++;
1918 xmlXPathDebugObjCounterString++;
1919 if (xmlXPathDebugObjCounterString >
1920 xmlXPathDebugObjMaxString)
1921 xmlXPathDebugObjMaxString =
1922 xmlXPathDebugObjCounterString;
1923 break;
1924 case XPATH_POINT:
1925 if (! isCached)
1926 xmlXPathDebugObjTotalPoint++;
1927 xmlXPathDebugObjCounterPoint++;
1928 if (xmlXPathDebugObjCounterPoint >
1929 xmlXPathDebugObjMaxPoint)
1930 xmlXPathDebugObjMaxPoint =
1931 xmlXPathDebugObjCounterPoint;
1932 break;
1933 case XPATH_RANGE:
1934 if (! isCached)
1935 xmlXPathDebugObjTotalRange++;
1936 xmlXPathDebugObjCounterRange++;
1937 if (xmlXPathDebugObjCounterRange >
1938 xmlXPathDebugObjMaxRange)
1939 xmlXPathDebugObjMaxRange =
1940 xmlXPathDebugObjCounterRange;
1941 break;
1942 case XPATH_LOCATIONSET:
1943 if (! isCached)
1944 xmlXPathDebugObjTotalLocset++;
1945 xmlXPathDebugObjCounterLocset++;
1946 if (xmlXPathDebugObjCounterLocset >
1947 xmlXPathDebugObjMaxLocset)
1948 xmlXPathDebugObjMaxLocset =
1949 xmlXPathDebugObjCounterLocset;
1950 break;
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 case XPATH_POINT:
2012 cache->dbgCachedPoint++;
2013 break;
2014 case XPATH_RANGE:
2015 cache->dbgCachedRange++;
2016 break;
2017 case XPATH_LOCATIONSET:
2018 cache->dbgCachedLocset++;
2019 break;
2020 case XPATH_USERS:
2021 cache->dbgCachedUsers++;
2022 break;
2023 case XPATH_XSLT_TREE:
2024 cache->dbgCachedXSLTTree++;
2025 break;
2026 default:
2027 break;
2028 }
2029
2030 }
2031 }
2032 switch (objType) {
2033 case XPATH_UNDEFINED:
2034 xmlXPathDebugObjCounterUndefined--;
2035 break;
2036 case XPATH_NODESET:
2037 xmlXPathDebugObjCounterNodeset--;
2038 break;
2039 case XPATH_BOOLEAN:
2040 xmlXPathDebugObjCounterBool--;
2041 break;
2042 case XPATH_NUMBER:
2043 xmlXPathDebugObjCounterNumber--;
2044 break;
2045 case XPATH_STRING:
2046 xmlXPathDebugObjCounterString--;
2047 break;
2048 case XPATH_POINT:
2049 xmlXPathDebugObjCounterPoint--;
2050 break;
2051 case XPATH_RANGE:
2052 xmlXPathDebugObjCounterRange--;
2053 break;
2054 case XPATH_LOCATIONSET:
2055 xmlXPathDebugObjCounterLocset--;
2056 break;
2057 case XPATH_USERS:
2058 xmlXPathDebugObjCounterUsers--;
2059 break;
2060 case XPATH_XSLT_TREE:
2061 xmlXPathDebugObjCounterXSLTTree--;
2062 break;
2063 default:
2064 break;
2065 }
2066 xmlXPathDebugObjCounterAll--;
2067 }
2068
2069 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2070 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2071 {
2072 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2073 reqXSLTTree, reqUndefined;
2074 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2075 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2076 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2077 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2078 int leftObjs = xmlXPathDebugObjCounterAll;
2079
2080 reqAll = xmlXPathDebugObjTotalAll;
2081 reqNodeset = xmlXPathDebugObjTotalNodeset;
2082 reqString = xmlXPathDebugObjTotalString;
2083 reqBool = xmlXPathDebugObjTotalBool;
2084 reqNumber = xmlXPathDebugObjTotalNumber;
2085 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2086 reqUndefined = xmlXPathDebugObjTotalUndefined;
2087
2088 printf("# XPath object usage:\n");
2089
2090 if (ctxt != NULL) {
2091 if (ctxt->cache != NULL) {
2092 xmlXPathContextCachePtr cache =
2093 (xmlXPathContextCachePtr) ctxt->cache;
2094
2095 reAll = cache->dbgReusedAll;
2096 reqAll += reAll;
2097 reNodeset = cache->dbgReusedNodeset;
2098 reqNodeset += reNodeset;
2099 reString = cache->dbgReusedString;
2100 reqString += reString;
2101 reBool = cache->dbgReusedBool;
2102 reqBool += reBool;
2103 reNumber = cache->dbgReusedNumber;
2104 reqNumber += reNumber;
2105 reXSLTTree = cache->dbgReusedXSLTTree;
2106 reqXSLTTree += reXSLTTree;
2107 reUndefined = cache->dbgReusedUndefined;
2108 reqUndefined += reUndefined;
2109
2110 caAll = cache->dbgCachedAll;
2111 caBool = cache->dbgCachedBool;
2112 caNodeset = cache->dbgCachedNodeset;
2113 caString = cache->dbgCachedString;
2114 caNumber = cache->dbgCachedNumber;
2115 caXSLTTree = cache->dbgCachedXSLTTree;
2116 caUndefined = cache->dbgCachedUndefined;
2117
2118 if (cache->nodesetObjs)
2119 leftObjs -= cache->nodesetObjs->number;
2120 if (cache->stringObjs)
2121 leftObjs -= cache->stringObjs->number;
2122 if (cache->booleanObjs)
2123 leftObjs -= cache->booleanObjs->number;
2124 if (cache->numberObjs)
2125 leftObjs -= cache->numberObjs->number;
2126 if (cache->miscObjs)
2127 leftObjs -= cache->miscObjs->number;
2128 }
2129 }
2130
2131 printf("# all\n");
2132 printf("# total : %d\n", reqAll);
2133 printf("# left : %d\n", leftObjs);
2134 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2135 printf("# reused : %d\n", reAll);
2136 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2137
2138 printf("# node-sets\n");
2139 printf("# total : %d\n", reqNodeset);
2140 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2141 printf("# reused : %d\n", reNodeset);
2142 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2143
2144 printf("# strings\n");
2145 printf("# total : %d\n", reqString);
2146 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2147 printf("# reused : %d\n", reString);
2148 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2149
2150 printf("# booleans\n");
2151 printf("# total : %d\n", reqBool);
2152 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2153 printf("# reused : %d\n", reBool);
2154 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2155
2156 printf("# numbers\n");
2157 printf("# total : %d\n", reqNumber);
2158 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2159 printf("# reused : %d\n", reNumber);
2160 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2161
2162 printf("# XSLT result tree fragments\n");
2163 printf("# total : %d\n", reqXSLTTree);
2164 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2165 printf("# reused : %d\n", reXSLTTree);
2166 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2167
2168 printf("# undefined\n");
2169 printf("# total : %d\n", reqUndefined);
2170 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2171 printf("# reused : %d\n", reUndefined);
2172 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2173
2174 }
2175
2176 #endif /* XP_DEBUG_OBJ_USAGE */
2177
2178 #endif /* LIBXML_DEBUG_ENABLED */
2179
2180 /************************************************************************
2181 * *
2182 * XPath object caching *
2183 * *
2184 ************************************************************************/
2185
2186 /**
2187 * xmlXPathNewCache:
2188 *
2189 * Create a new object cache
2190 *
2191 * Returns the xmlXPathCache just allocated.
2192 */
2193 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2194 xmlXPathNewCache(void)
2195 {
2196 xmlXPathContextCachePtr ret;
2197
2198 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2199 if (ret == NULL) {
2200 xmlXPathErrMemory(NULL, "creating object cache\n");
2201 return(NULL);
2202 }
2203 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2204 ret->maxNodeset = 100;
2205 ret->maxString = 100;
2206 ret->maxBoolean = 100;
2207 ret->maxNumber = 100;
2208 ret->maxMisc = 100;
2209 return(ret);
2210 }
2211
2212 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2213 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2214 {
2215 int i;
2216 xmlXPathObjectPtr obj;
2217
2218 if (list == NULL)
2219 return;
2220
2221 for (i = 0; i < list->number; i++) {
2222 obj = list->items[i];
2223 /*
2224 * Note that it is already assured that we don't need to
2225 * look out for namespace nodes in the node-set.
2226 */
2227 if (obj->nodesetval != NULL) {
2228 if (obj->nodesetval->nodeTab != NULL)
2229 xmlFree(obj->nodesetval->nodeTab);
2230 xmlFree(obj->nodesetval);
2231 }
2232 xmlFree(obj);
2233 #ifdef XP_DEBUG_OBJ_USAGE
2234 xmlXPathDebugObjCounterAll--;
2235 #endif
2236 }
2237 xmlPointerListFree(list);
2238 }
2239
2240 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2241 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2242 {
2243 if (cache == NULL)
2244 return;
2245 if (cache->nodesetObjs)
2246 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2247 if (cache->stringObjs)
2248 xmlXPathCacheFreeObjectList(cache->stringObjs);
2249 if (cache->booleanObjs)
2250 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2251 if (cache->numberObjs)
2252 xmlXPathCacheFreeObjectList(cache->numberObjs);
2253 if (cache->miscObjs)
2254 xmlXPathCacheFreeObjectList(cache->miscObjs);
2255 xmlFree(cache);
2256 }
2257
2258 /**
2259 * xmlXPathContextSetCache:
2260 *
2261 * @ctxt: the XPath context
2262 * @active: enables/disables (creates/frees) the cache
2263 * @value: a value with semantics dependent on @options
2264 * @options: options (currently only the value 0 is used)
2265 *
2266 * Creates/frees an object cache on the XPath context.
2267 * If activates XPath objects (xmlXPathObject) will be cached internally
2268 * to be reused.
2269 * @options:
2270 * 0: This will set the XPath object caching:
2271 * @value:
2272 * This will set the maximum number of XPath objects
2273 * to be cached per slot
2274 * There are 5 slots for: node-set, string, number, boolean, and
2275 * misc objects. Use <0 for the default number (100).
2276 * Other values for @options have currently no effect.
2277 *
2278 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2279 */
2280 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2281 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2282 int active,
2283 int value,
2284 int options)
2285 {
2286 if (ctxt == NULL)
2287 return(-1);
2288 if (active) {
2289 xmlXPathContextCachePtr cache;
2290
2291 if (ctxt->cache == NULL) {
2292 ctxt->cache = xmlXPathNewCache();
2293 if (ctxt->cache == NULL)
2294 return(-1);
2295 }
2296 cache = (xmlXPathContextCachePtr) ctxt->cache;
2297 if (options == 0) {
2298 if (value < 0)
2299 value = 100;
2300 cache->maxNodeset = value;
2301 cache->maxString = value;
2302 cache->maxNumber = value;
2303 cache->maxBoolean = value;
2304 cache->maxMisc = value;
2305 }
2306 } else if (ctxt->cache != NULL) {
2307 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2308 ctxt->cache = NULL;
2309 }
2310 return(0);
2311 }
2312
2313 /**
2314 * xmlXPathCacheWrapNodeSet:
2315 * @ctxt: the XPath context
2316 * @val: the NodePtr value
2317 *
2318 * This is the cached version of xmlXPathWrapNodeSet().
2319 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2320 *
2321 * Returns the created or reused object.
2322 */
2323 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2324 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2325 {
2326 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2327 xmlXPathContextCachePtr cache =
2328 (xmlXPathContextCachePtr) ctxt->cache;
2329
2330 if ((cache->miscObjs != NULL) &&
2331 (cache->miscObjs->number != 0))
2332 {
2333 xmlXPathObjectPtr ret;
2334
2335 ret = (xmlXPathObjectPtr)
2336 cache->miscObjs->items[--cache->miscObjs->number];
2337 ret->type = XPATH_NODESET;
2338 ret->nodesetval = val;
2339 #ifdef XP_DEBUG_OBJ_USAGE
2340 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2341 #endif
2342 return(ret);
2343 }
2344 }
2345
2346 return(xmlXPathWrapNodeSet(val));
2347
2348 }
2349
2350 /**
2351 * xmlXPathCacheWrapString:
2352 * @ctxt: the XPath context
2353 * @val: the xmlChar * value
2354 *
2355 * This is the cached version of xmlXPathWrapString().
2356 * Wraps the @val string into an XPath object.
2357 *
2358 * Returns the created or reused object.
2359 */
2360 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2361 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2362 {
2363 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2364 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2365
2366 if ((cache->stringObjs != NULL) &&
2367 (cache->stringObjs->number != 0))
2368 {
2369
2370 xmlXPathObjectPtr ret;
2371
2372 ret = (xmlXPathObjectPtr)
2373 cache->stringObjs->items[--cache->stringObjs->number];
2374 ret->type = XPATH_STRING;
2375 ret->stringval = val;
2376 #ifdef XP_DEBUG_OBJ_USAGE
2377 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2378 #endif
2379 return(ret);
2380 } else if ((cache->miscObjs != NULL) &&
2381 (cache->miscObjs->number != 0))
2382 {
2383 xmlXPathObjectPtr ret;
2384 /*
2385 * Fallback to misc-cache.
2386 */
2387 ret = (xmlXPathObjectPtr)
2388 cache->miscObjs->items[--cache->miscObjs->number];
2389
2390 ret->type = XPATH_STRING;
2391 ret->stringval = val;
2392 #ifdef XP_DEBUG_OBJ_USAGE
2393 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394 #endif
2395 return(ret);
2396 }
2397 }
2398 return(xmlXPathWrapString(val));
2399 }
2400
2401 /**
2402 * xmlXPathCacheNewNodeSet:
2403 * @ctxt: the XPath context
2404 * @val: the NodePtr value
2405 *
2406 * This is the cached version of xmlXPathNewNodeSet().
2407 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2408 * it with the single Node @val
2409 *
2410 * Returns the created or reused object.
2411 */
2412 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2413 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2414 {
2415 if ((ctxt != NULL) && (ctxt->cache)) {
2416 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2417
2418 if ((cache->nodesetObjs != NULL) &&
2419 (cache->nodesetObjs->number != 0))
2420 {
2421 xmlXPathObjectPtr ret;
2422 /*
2423 * Use the nodeset-cache.
2424 */
2425 ret = (xmlXPathObjectPtr)
2426 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2427 ret->type = XPATH_NODESET;
2428 ret->boolval = 0;
2429 if (val) {
2430 if ((ret->nodesetval->nodeMax == 0) ||
2431 (val->type == XML_NAMESPACE_DECL))
2432 {
2433 /* TODO: Check memory error. */
2434 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2435 } else {
2436 ret->nodesetval->nodeTab[0] = val;
2437 ret->nodesetval->nodeNr = 1;
2438 }
2439 }
2440 #ifdef XP_DEBUG_OBJ_USAGE
2441 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2442 #endif
2443 return(ret);
2444 } else if ((cache->miscObjs != NULL) &&
2445 (cache->miscObjs->number != 0))
2446 {
2447 xmlXPathObjectPtr ret;
2448 /*
2449 * Fallback to misc-cache.
2450 */
2451
2452 ret = (xmlXPathObjectPtr)
2453 cache->miscObjs->items[--cache->miscObjs->number];
2454
2455 ret->type = XPATH_NODESET;
2456 ret->boolval = 0;
2457 ret->nodesetval = xmlXPathNodeSetCreate(val);
2458 if (ret->nodesetval == NULL) {
2459 ctxt->lastError.domain = XML_FROM_XPATH;
2460 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2461 return(NULL);
2462 }
2463 #ifdef XP_DEBUG_OBJ_USAGE
2464 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2465 #endif
2466 return(ret);
2467 }
2468 }
2469 return(xmlXPathNewNodeSet(val));
2470 }
2471
2472 /**
2473 * xmlXPathCacheNewCString:
2474 * @ctxt: the XPath context
2475 * @val: the char * value
2476 *
2477 * This is the cached version of xmlXPathNewCString().
2478 * Acquire an xmlXPathObjectPtr of type string and of value @val
2479 *
2480 * Returns the created or reused object.
2481 */
2482 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2483 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2484 {
2485 if ((ctxt != NULL) && (ctxt->cache)) {
2486 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2487
2488 if ((cache->stringObjs != NULL) &&
2489 (cache->stringObjs->number != 0))
2490 {
2491 xmlXPathObjectPtr ret;
2492
2493 ret = (xmlXPathObjectPtr)
2494 cache->stringObjs->items[--cache->stringObjs->number];
2495
2496 ret->type = XPATH_STRING;
2497 ret->stringval = xmlStrdup(BAD_CAST val);
2498 #ifdef XP_DEBUG_OBJ_USAGE
2499 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2500 #endif
2501 return(ret);
2502 } else if ((cache->miscObjs != NULL) &&
2503 (cache->miscObjs->number != 0))
2504 {
2505 xmlXPathObjectPtr ret;
2506
2507 ret = (xmlXPathObjectPtr)
2508 cache->miscObjs->items[--cache->miscObjs->number];
2509
2510 ret->type = XPATH_STRING;
2511 ret->stringval = xmlStrdup(BAD_CAST val);
2512 #ifdef XP_DEBUG_OBJ_USAGE
2513 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2514 #endif
2515 return(ret);
2516 }
2517 }
2518 return(xmlXPathNewCString(val));
2519 }
2520
2521 /**
2522 * xmlXPathCacheNewString:
2523 * @ctxt: the XPath context
2524 * @val: the xmlChar * value
2525 *
2526 * This is the cached version of xmlXPathNewString().
2527 * Acquire an xmlXPathObjectPtr of type string and of value @val
2528 *
2529 * Returns the created or reused object.
2530 */
2531 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2532 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2533 {
2534 if ((ctxt != NULL) && (ctxt->cache)) {
2535 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2536
2537 if ((cache->stringObjs != NULL) &&
2538 (cache->stringObjs->number != 0))
2539 {
2540 xmlXPathObjectPtr ret;
2541
2542 ret = (xmlXPathObjectPtr)
2543 cache->stringObjs->items[--cache->stringObjs->number];
2544 ret->type = XPATH_STRING;
2545 if (val != NULL)
2546 ret->stringval = xmlStrdup(val);
2547 else
2548 ret->stringval = xmlStrdup((const xmlChar *)"");
2549 #ifdef XP_DEBUG_OBJ_USAGE
2550 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2551 #endif
2552 return(ret);
2553 } else if ((cache->miscObjs != NULL) &&
2554 (cache->miscObjs->number != 0))
2555 {
2556 xmlXPathObjectPtr ret;
2557
2558 ret = (xmlXPathObjectPtr)
2559 cache->miscObjs->items[--cache->miscObjs->number];
2560
2561 ret->type = XPATH_STRING;
2562 if (val != NULL)
2563 ret->stringval = xmlStrdup(val);
2564 else
2565 ret->stringval = xmlStrdup((const xmlChar *)"");
2566 #ifdef XP_DEBUG_OBJ_USAGE
2567 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2568 #endif
2569 return(ret);
2570 }
2571 }
2572 return(xmlXPathNewString(val));
2573 }
2574
2575 /**
2576 * xmlXPathCacheNewBoolean:
2577 * @ctxt: the XPath context
2578 * @val: the boolean value
2579 *
2580 * This is the cached version of xmlXPathNewBoolean().
2581 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2582 *
2583 * Returns the created or reused object.
2584 */
2585 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2586 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2587 {
2588 if ((ctxt != NULL) && (ctxt->cache)) {
2589 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2590
2591 if ((cache->booleanObjs != NULL) &&
2592 (cache->booleanObjs->number != 0))
2593 {
2594 xmlXPathObjectPtr ret;
2595
2596 ret = (xmlXPathObjectPtr)
2597 cache->booleanObjs->items[--cache->booleanObjs->number];
2598 ret->type = XPATH_BOOLEAN;
2599 ret->boolval = (val != 0);
2600 #ifdef XP_DEBUG_OBJ_USAGE
2601 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2602 #endif
2603 return(ret);
2604 } else if ((cache->miscObjs != NULL) &&
2605 (cache->miscObjs->number != 0))
2606 {
2607 xmlXPathObjectPtr ret;
2608
2609 ret = (xmlXPathObjectPtr)
2610 cache->miscObjs->items[--cache->miscObjs->number];
2611
2612 ret->type = XPATH_BOOLEAN;
2613 ret->boolval = (val != 0);
2614 #ifdef XP_DEBUG_OBJ_USAGE
2615 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2616 #endif
2617 return(ret);
2618 }
2619 }
2620 return(xmlXPathNewBoolean(val));
2621 }
2622
2623 /**
2624 * xmlXPathCacheNewFloat:
2625 * @ctxt: the XPath context
2626 * @val: the double value
2627 *
2628 * This is the cached version of xmlXPathNewFloat().
2629 * Acquires an xmlXPathObjectPtr of type double and of value @val
2630 *
2631 * Returns the created or reused object.
2632 */
2633 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2634 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2635 {
2636 if ((ctxt != NULL) && (ctxt->cache)) {
2637 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2638
2639 if ((cache->numberObjs != NULL) &&
2640 (cache->numberObjs->number != 0))
2641 {
2642 xmlXPathObjectPtr ret;
2643
2644 ret = (xmlXPathObjectPtr)
2645 cache->numberObjs->items[--cache->numberObjs->number];
2646 ret->type = XPATH_NUMBER;
2647 ret->floatval = val;
2648 #ifdef XP_DEBUG_OBJ_USAGE
2649 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2650 #endif
2651 return(ret);
2652 } else if ((cache->miscObjs != NULL) &&
2653 (cache->miscObjs->number != 0))
2654 {
2655 xmlXPathObjectPtr ret;
2656
2657 ret = (xmlXPathObjectPtr)
2658 cache->miscObjs->items[--cache->miscObjs->number];
2659
2660 ret->type = XPATH_NUMBER;
2661 ret->floatval = val;
2662 #ifdef XP_DEBUG_OBJ_USAGE
2663 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2664 #endif
2665 return(ret);
2666 }
2667 }
2668 return(xmlXPathNewFloat(val));
2669 }
2670
2671 /**
2672 * xmlXPathCacheConvertString:
2673 * @ctxt: the XPath context
2674 * @val: an XPath object
2675 *
2676 * This is the cached version of xmlXPathConvertString().
2677 * Converts an existing object to its string() equivalent
2678 *
2679 * Returns a created or reused object, the old one is freed (cached)
2680 * (or the operation is done directly on @val)
2681 */
2682
2683 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2684 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2685 xmlChar *res = NULL;
2686
2687 if (val == NULL)
2688 return(xmlXPathCacheNewCString(ctxt, ""));
2689
2690 switch (val->type) {
2691 case XPATH_UNDEFINED:
2692 #ifdef DEBUG_EXPR
2693 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2694 #endif
2695 break;
2696 case XPATH_NODESET:
2697 case XPATH_XSLT_TREE:
2698 res = xmlXPathCastNodeSetToString(val->nodesetval);
2699 break;
2700 case XPATH_STRING:
2701 return(val);
2702 case XPATH_BOOLEAN:
2703 res = xmlXPathCastBooleanToString(val->boolval);
2704 break;
2705 case XPATH_NUMBER:
2706 res = xmlXPathCastNumberToString(val->floatval);
2707 break;
2708 case XPATH_USERS:
2709 case XPATH_POINT:
2710 case XPATH_RANGE:
2711 case XPATH_LOCATIONSET:
2712 TODO;
2713 break;
2714 }
2715 xmlXPathReleaseObject(ctxt, val);
2716 if (res == NULL)
2717 return(xmlXPathCacheNewCString(ctxt, ""));
2718 return(xmlXPathCacheWrapString(ctxt, res));
2719 }
2720
2721 /**
2722 * xmlXPathCacheObjectCopy:
2723 * @ctxt: the XPath context
2724 * @val: the original object
2725 *
2726 * This is the cached version of xmlXPathObjectCopy().
2727 * Acquire a copy of a given object
2728 *
2729 * Returns a created or reused created object.
2730 */
2731 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2732 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2733 {
2734 if (val == NULL)
2735 return(NULL);
2736
2737 if (XP_HAS_CACHE(ctxt)) {
2738 switch (val->type) {
2739 case XPATH_NODESET:
2740 return(xmlXPathCacheWrapNodeSet(ctxt,
2741 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2742 case XPATH_STRING:
2743 return(xmlXPathCacheNewString(ctxt, val->stringval));
2744 case XPATH_BOOLEAN:
2745 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2746 case XPATH_NUMBER:
2747 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2748 default:
2749 break;
2750 }
2751 }
2752 return(xmlXPathObjectCopy(val));
2753 }
2754
2755 /**
2756 * xmlXPathCacheConvertBoolean:
2757 * @ctxt: the XPath context
2758 * @val: an XPath object
2759 *
2760 * This is the cached version of xmlXPathConvertBoolean().
2761 * Converts an existing object to its boolean() equivalent
2762 *
2763 * Returns a created or reused object, the old one is freed (or the operation
2764 * is done directly on @val)
2765 */
2766 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2767 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2768 xmlXPathObjectPtr ret;
2769
2770 if (val == NULL)
2771 return(xmlXPathCacheNewBoolean(ctxt, 0));
2772 if (val->type == XPATH_BOOLEAN)
2773 return(val);
2774 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2775 xmlXPathReleaseObject(ctxt, val);
2776 return(ret);
2777 }
2778
2779 /**
2780 * xmlXPathCacheConvertNumber:
2781 * @ctxt: the XPath context
2782 * @val: an XPath object
2783 *
2784 * This is the cached version of xmlXPathConvertNumber().
2785 * Converts an existing object to its number() equivalent
2786 *
2787 * Returns a created or reused object, the old one is freed (or the operation
2788 * is done directly on @val)
2789 */
2790 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2791 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2792 xmlXPathObjectPtr ret;
2793
2794 if (val == NULL)
2795 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2796 if (val->type == XPATH_NUMBER)
2797 return(val);
2798 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2799 xmlXPathReleaseObject(ctxt, val);
2800 return(ret);
2801 }
2802
2803 /************************************************************************
2804 * *
2805 * Parser stacks related functions and macros *
2806 * *
2807 ************************************************************************/
2808
2809 /**
2810 * xmlXPathSetFrame:
2811 * @ctxt: an XPath parser context
2812 *
2813 * Set the callee evaluation frame
2814 *
2815 * Returns the previous frame value to be restored once done
2816 */
2817 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2818 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2819 int ret;
2820
2821 if (ctxt == NULL)
2822 return(0);
2823 ret = ctxt->valueFrame;
2824 ctxt->valueFrame = ctxt->valueNr;
2825 return(ret);
2826 }
2827
2828 /**
2829 * xmlXPathPopFrame:
2830 * @ctxt: an XPath parser context
2831 * @frame: the previous frame value
2832 *
2833 * Remove the callee evaluation frame
2834 */
2835 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2836 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2837 if (ctxt == NULL)
2838 return;
2839 if (ctxt->valueNr < ctxt->valueFrame) {
2840 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2841 }
2842 ctxt->valueFrame = frame;
2843 }
2844
2845 /**
2846 * valuePop:
2847 * @ctxt: an XPath evaluation context
2848 *
2849 * Pops the top XPath object from the value stack
2850 *
2851 * Returns the XPath object just removed
2852 */
2853 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2854 valuePop(xmlXPathParserContextPtr ctxt)
2855 {
2856 xmlXPathObjectPtr ret;
2857
2858 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2859 return (NULL);
2860
2861 if (ctxt->valueNr <= ctxt->valueFrame) {
2862 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2863 return (NULL);
2864 }
2865
2866 ctxt->valueNr--;
2867 if (ctxt->valueNr > 0)
2868 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2869 else
2870 ctxt->value = NULL;
2871 ret = ctxt->valueTab[ctxt->valueNr];
2872 ctxt->valueTab[ctxt->valueNr] = NULL;
2873 return (ret);
2874 }
2875 /**
2876 * valuePush:
2877 * @ctxt: an XPath evaluation context
2878 * @value: the XPath object
2879 *
2880 * Pushes a new XPath object on top of the value stack. If value is NULL,
2881 * a memory error is recorded in the parser context.
2882 *
2883 * Returns the number of items on the value stack, or -1 in case of error.
2884 */
2885 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2886 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2887 {
2888 if (ctxt == NULL) return(-1);
2889 if (value == NULL) {
2890 /*
2891 * A NULL value typically indicates that a memory allocation failed,
2892 * so we set ctxt->error here to propagate the error.
2893 */
2894 ctxt->error = XPATH_MEMORY_ERROR;
2895 return(-1);
2896 }
2897 if (ctxt->valueNr >= ctxt->valueMax) {
2898 xmlXPathObjectPtr *tmp;
2899
2900 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2901 xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2902 return (-1);
2903 }
2904 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2905 2 * ctxt->valueMax *
2906 sizeof(ctxt->valueTab[0]));
2907 if (tmp == NULL) {
2908 xmlXPathPErrMemory(ctxt, "pushing value\n");
2909 return (-1);
2910 }
2911 ctxt->valueMax *= 2;
2912 ctxt->valueTab = tmp;
2913 }
2914 ctxt->valueTab[ctxt->valueNr] = value;
2915 ctxt->value = value;
2916 return (ctxt->valueNr++);
2917 }
2918
2919 /**
2920 * xmlXPathPopBoolean:
2921 * @ctxt: an XPath parser context
2922 *
2923 * Pops a boolean from the stack, handling conversion if needed.
2924 * Check error with #xmlXPathCheckError.
2925 *
2926 * Returns the boolean
2927 */
2928 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2929 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2930 xmlXPathObjectPtr obj;
2931 int ret;
2932
2933 obj = valuePop(ctxt);
2934 if (obj == NULL) {
2935 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2936 return(0);
2937 }
2938 if (obj->type != XPATH_BOOLEAN)
2939 ret = xmlXPathCastToBoolean(obj);
2940 else
2941 ret = obj->boolval;
2942 xmlXPathReleaseObject(ctxt->context, obj);
2943 return(ret);
2944 }
2945
2946 /**
2947 * xmlXPathPopNumber:
2948 * @ctxt: an XPath parser context
2949 *
2950 * Pops a number from the stack, handling conversion if needed.
2951 * Check error with #xmlXPathCheckError.
2952 *
2953 * Returns the number
2954 */
2955 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2956 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2957 xmlXPathObjectPtr obj;
2958 double ret;
2959
2960 obj = valuePop(ctxt);
2961 if (obj == NULL) {
2962 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2963 return(0);
2964 }
2965 if (obj->type != XPATH_NUMBER)
2966 ret = xmlXPathCastToNumber(obj);
2967 else
2968 ret = obj->floatval;
2969 xmlXPathReleaseObject(ctxt->context, obj);
2970 return(ret);
2971 }
2972
2973 /**
2974 * xmlXPathPopString:
2975 * @ctxt: an XPath parser context
2976 *
2977 * Pops a string from the stack, handling conversion if needed.
2978 * Check error with #xmlXPathCheckError.
2979 *
2980 * Returns the string
2981 */
2982 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2983 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2984 xmlXPathObjectPtr obj;
2985 xmlChar * ret;
2986
2987 obj = valuePop(ctxt);
2988 if (obj == NULL) {
2989 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2990 return(NULL);
2991 }
2992 ret = xmlXPathCastToString(obj); /* this does required strdup */
2993 /* TODO: needs refactoring somewhere else */
2994 if (obj->stringval == ret)
2995 obj->stringval = NULL;
2996 xmlXPathReleaseObject(ctxt->context, obj);
2997 return(ret);
2998 }
2999
3000 /**
3001 * xmlXPathPopNodeSet:
3002 * @ctxt: an XPath parser context
3003 *
3004 * Pops a node-set from the stack, handling conversion if needed.
3005 * Check error with #xmlXPathCheckError.
3006 *
3007 * Returns the node-set
3008 */
3009 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)3010 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3011 xmlXPathObjectPtr obj;
3012 xmlNodeSetPtr ret;
3013
3014 if (ctxt == NULL) return(NULL);
3015 if (ctxt->value == NULL) {
3016 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3017 return(NULL);
3018 }
3019 if (!xmlXPathStackIsNodeSet(ctxt)) {
3020 xmlXPathSetTypeError(ctxt);
3021 return(NULL);
3022 }
3023 obj = valuePop(ctxt);
3024 ret = obj->nodesetval;
3025 #if 0
3026 /* to fix memory leak of not clearing obj->user */
3027 if (obj->boolval && obj->user != NULL)
3028 xmlFreeNodeList((xmlNodePtr) obj->user);
3029 #endif
3030 obj->nodesetval = NULL;
3031 xmlXPathReleaseObject(ctxt->context, obj);
3032 return(ret);
3033 }
3034
3035 /**
3036 * xmlXPathPopExternal:
3037 * @ctxt: an XPath parser context
3038 *
3039 * Pops an external object from the stack, handling conversion if needed.
3040 * Check error with #xmlXPathCheckError.
3041 *
3042 * Returns the object
3043 */
3044 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3045 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3046 xmlXPathObjectPtr obj;
3047 void * ret;
3048
3049 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3050 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3051 return(NULL);
3052 }
3053 if (ctxt->value->type != XPATH_USERS) {
3054 xmlXPathSetTypeError(ctxt);
3055 return(NULL);
3056 }
3057 obj = valuePop(ctxt);
3058 ret = obj->user;
3059 obj->user = NULL;
3060 xmlXPathReleaseObject(ctxt->context, obj);
3061 return(ret);
3062 }
3063
3064 /*
3065 * Macros for accessing the content. Those should be used only by the parser,
3066 * and not exported.
3067 *
3068 * Dirty macros, i.e. one need to make assumption on the context to use them
3069 *
3070 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3071 * CUR returns the current xmlChar value, i.e. a 8 bit value
3072 * in ISO-Latin or UTF-8.
3073 * This should be used internally by the parser
3074 * only to compare to ASCII values otherwise it would break when
3075 * running with UTF-8 encoding.
3076 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3077 * to compare on ASCII based substring.
3078 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3079 * strings within the parser.
3080 * CURRENT Returns the current char value, with the full decoding of
3081 * UTF-8 if we are using this mode. It returns an int.
3082 * NEXT Skip to the next character, this does the proper decoding
3083 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3084 * It returns the pointer to the current xmlChar.
3085 */
3086
3087 #define CUR (*ctxt->cur)
3088 #define SKIP(val) ctxt->cur += (val)
3089 #define NXT(val) ctxt->cur[(val)]
3090 #define CUR_PTR ctxt->cur
3091 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3092
3093 #define COPY_BUF(l,b,i,v) \
3094 if (l == 1) b[i++] = (xmlChar) v; \
3095 else i += xmlCopyChar(l,&b[i],v)
3096
3097 #define NEXTL(l) ctxt->cur += l
3098
3099 #define SKIP_BLANKS \
3100 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3101
3102 #define CURRENT (*ctxt->cur)
3103 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3104
3105
3106 #ifndef DBL_DIG
3107 #define DBL_DIG 16
3108 #endif
3109 #ifndef DBL_EPSILON
3110 #define DBL_EPSILON 1E-9
3111 #endif
3112
3113 #define UPPER_DOUBLE 1E9
3114 #define LOWER_DOUBLE 1E-5
3115 #define LOWER_DOUBLE_EXP 5
3116
3117 #define INTEGER_DIGITS DBL_DIG
3118 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3119 #define EXPONENT_DIGITS (3 + 2)
3120
3121 /**
3122 * xmlXPathFormatNumber:
3123 * @number: number to format
3124 * @buffer: output buffer
3125 * @buffersize: size of output buffer
3126 *
3127 * Convert the number into a string representation.
3128 */
3129 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3130 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3131 {
3132 switch (xmlXPathIsInf(number)) {
3133 case 1:
3134 if (buffersize > (int)sizeof("Infinity"))
3135 snprintf(buffer, buffersize, "Infinity");
3136 break;
3137 case -1:
3138 if (buffersize > (int)sizeof("-Infinity"))
3139 snprintf(buffer, buffersize, "-Infinity");
3140 break;
3141 default:
3142 if (xmlXPathIsNaN(number)) {
3143 if (buffersize > (int)sizeof("NaN"))
3144 snprintf(buffer, buffersize, "NaN");
3145 } else if (number == 0) {
3146 /* Omit sign for negative zero. */
3147 snprintf(buffer, buffersize, "0");
3148 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3149 (number == (int) number)) {
3150 char work[30];
3151 char *ptr, *cur;
3152 int value = (int) number;
3153
3154 ptr = &buffer[0];
3155 if (value == 0) {
3156 *ptr++ = '0';
3157 } else {
3158 snprintf(work, 29, "%d", value);
3159 cur = &work[0];
3160 while ((*cur) && (ptr - buffer < buffersize)) {
3161 *ptr++ = *cur++;
3162 }
3163 }
3164 if (ptr - buffer < buffersize) {
3165 *ptr = 0;
3166 } else if (buffersize > 0) {
3167 ptr--;
3168 *ptr = 0;
3169 }
3170 } else {
3171 /*
3172 For the dimension of work,
3173 DBL_DIG is number of significant digits
3174 EXPONENT is only needed for "scientific notation"
3175 3 is sign, decimal point, and terminating zero
3176 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3177 Note that this dimension is slightly (a few characters)
3178 larger than actually necessary.
3179 */
3180 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3181 int integer_place, fraction_place;
3182 char *ptr;
3183 char *after_fraction;
3184 double absolute_value;
3185 int size;
3186
3187 absolute_value = fabs(number);
3188
3189 /*
3190 * First choose format - scientific or regular floating point.
3191 * In either case, result is in work, and after_fraction points
3192 * just past the fractional part.
3193 */
3194 if ( ((absolute_value > UPPER_DOUBLE) ||
3195 (absolute_value < LOWER_DOUBLE)) &&
3196 (absolute_value != 0.0) ) {
3197 /* Use scientific notation */
3198 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3199 fraction_place = DBL_DIG - 1;
3200 size = snprintf(work, sizeof(work),"%*.*e",
3201 integer_place, fraction_place, number);
3202 while ((size > 0) && (work[size] != 'e')) size--;
3203
3204 }
3205 else {
3206 /* Use regular notation */
3207 if (absolute_value > 0.0) {
3208 integer_place = (int)log10(absolute_value);
3209 if (integer_place > 0)
3210 fraction_place = DBL_DIG - integer_place - 1;
3211 else
3212 fraction_place = DBL_DIG - integer_place;
3213 } else {
3214 fraction_place = 1;
3215 }
3216 size = snprintf(work, sizeof(work), "%0.*f",
3217 fraction_place, number);
3218 }
3219
3220 /* Remove leading spaces sometimes inserted by snprintf */
3221 while (work[0] == ' ') {
3222 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3223 size--;
3224 }
3225
3226 /* Remove fractional trailing zeroes */
3227 after_fraction = work + size;
3228 ptr = after_fraction;
3229 while (*(--ptr) == '0')
3230 ;
3231 if (*ptr != '.')
3232 ptr++;
3233 while ((*ptr++ = *after_fraction++) != 0);
3234
3235 /* Finally copy result back to caller */
3236 size = strlen(work) + 1;
3237 if (size > buffersize) {
3238 work[buffersize - 1] = 0;
3239 size = buffersize;
3240 }
3241 memmove(buffer, work, size);
3242 }
3243 break;
3244 }
3245 }
3246
3247
3248 /************************************************************************
3249 * *
3250 * Routines to handle NodeSets *
3251 * *
3252 ************************************************************************/
3253
3254 /**
3255 * xmlXPathOrderDocElems:
3256 * @doc: an input document
3257 *
3258 * Call this routine to speed up XPath computation on static documents.
3259 * This stamps all the element nodes with the document order
3260 * Like for line information, the order is kept in the element->content
3261 * field, the value stored is actually - the node number (starting at -1)
3262 * to be able to differentiate from line numbers.
3263 *
3264 * Returns the number of elements found in the document or -1 in case
3265 * of error.
3266 */
3267 long
xmlXPathOrderDocElems(xmlDocPtr doc)3268 xmlXPathOrderDocElems(xmlDocPtr doc) {
3269 ptrdiff_t count = 0;
3270 xmlNodePtr cur;
3271
3272 if (doc == NULL)
3273 return(-1);
3274 cur = doc->children;
3275 while (cur != NULL) {
3276 if (cur->type == XML_ELEMENT_NODE) {
3277 cur->content = (void *) (-(++count));
3278 if (cur->children != NULL) {
3279 cur = cur->children;
3280 continue;
3281 }
3282 }
3283 if (cur->next != NULL) {
3284 cur = cur->next;
3285 continue;
3286 }
3287 do {
3288 cur = cur->parent;
3289 if (cur == NULL)
3290 break;
3291 if (cur == (xmlNodePtr) doc) {
3292 cur = NULL;
3293 break;
3294 }
3295 if (cur->next != NULL) {
3296 cur = cur->next;
3297 break;
3298 }
3299 } while (cur != NULL);
3300 }
3301 return((long) count);
3302 }
3303
3304 /**
3305 * xmlXPathCmpNodes:
3306 * @node1: the first node
3307 * @node2: the second node
3308 *
3309 * Compare two nodes w.r.t document order
3310 *
3311 * Returns -2 in case of error 1 if first point < second point, 0 if
3312 * it's the same node, -1 otherwise
3313 */
3314 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3315 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3316 int depth1, depth2;
3317 int attr1 = 0, attr2 = 0;
3318 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3319 xmlNodePtr cur, root;
3320
3321 if ((node1 == NULL) || (node2 == NULL))
3322 return(-2);
3323 /*
3324 * a couple of optimizations which will avoid computations in most cases
3325 */
3326 if (node1 == node2) /* trivial case */
3327 return(0);
3328 if (node1->type == XML_ATTRIBUTE_NODE) {
3329 attr1 = 1;
3330 attrNode1 = node1;
3331 node1 = node1->parent;
3332 }
3333 if (node2->type == XML_ATTRIBUTE_NODE) {
3334 attr2 = 1;
3335 attrNode2 = node2;
3336 node2 = node2->parent;
3337 }
3338 if (node1 == node2) {
3339 if (attr1 == attr2) {
3340 /* not required, but we keep attributes in order */
3341 if (attr1 != 0) {
3342 cur = attrNode2->prev;
3343 while (cur != NULL) {
3344 if (cur == attrNode1)
3345 return (1);
3346 cur = cur->prev;
3347 }
3348 return (-1);
3349 }
3350 return(0);
3351 }
3352 if (attr2 == 1)
3353 return(1);
3354 return(-1);
3355 }
3356 if ((node1->type == XML_NAMESPACE_DECL) ||
3357 (node2->type == XML_NAMESPACE_DECL))
3358 return(1);
3359 if (node1 == node2->prev)
3360 return(1);
3361 if (node1 == node2->next)
3362 return(-1);
3363
3364 /*
3365 * Speedup using document order if available.
3366 */
3367 if ((node1->type == XML_ELEMENT_NODE) &&
3368 (node2->type == XML_ELEMENT_NODE) &&
3369 (0 > (ptrdiff_t) node1->content) &&
3370 (0 > (ptrdiff_t) node2->content) &&
3371 (node1->doc == node2->doc)) {
3372 ptrdiff_t l1, l2;
3373
3374 l1 = -((ptrdiff_t) node1->content);
3375 l2 = -((ptrdiff_t) node2->content);
3376 if (l1 < l2)
3377 return(1);
3378 if (l1 > l2)
3379 return(-1);
3380 }
3381
3382 /*
3383 * compute depth to root
3384 */
3385 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3386 if (cur->parent == node1)
3387 return(1);
3388 depth2++;
3389 }
3390 root = cur;
3391 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3392 if (cur->parent == node2)
3393 return(-1);
3394 depth1++;
3395 }
3396 /*
3397 * Distinct document (or distinct entities :-( ) case.
3398 */
3399 if (root != cur) {
3400 return(-2);
3401 }
3402 /*
3403 * get the nearest common ancestor.
3404 */
3405 while (depth1 > depth2) {
3406 depth1--;
3407 node1 = node1->parent;
3408 }
3409 while (depth2 > depth1) {
3410 depth2--;
3411 node2 = node2->parent;
3412 }
3413 while (node1->parent != node2->parent) {
3414 node1 = node1->parent;
3415 node2 = node2->parent;
3416 /* should not happen but just in case ... */
3417 if ((node1 == NULL) || (node2 == NULL))
3418 return(-2);
3419 }
3420 /*
3421 * Find who's first.
3422 */
3423 if (node1 == node2->prev)
3424 return(1);
3425 if (node1 == node2->next)
3426 return(-1);
3427 /*
3428 * Speedup using document order if available.
3429 */
3430 if ((node1->type == XML_ELEMENT_NODE) &&
3431 (node2->type == XML_ELEMENT_NODE) &&
3432 (0 > (ptrdiff_t) node1->content) &&
3433 (0 > (ptrdiff_t) node2->content) &&
3434 (node1->doc == node2->doc)) {
3435 ptrdiff_t l1, l2;
3436
3437 l1 = -((ptrdiff_t) node1->content);
3438 l2 = -((ptrdiff_t) node2->content);
3439 if (l1 < l2)
3440 return(1);
3441 if (l1 > l2)
3442 return(-1);
3443 }
3444
3445 for (cur = node1->next;cur != NULL;cur = cur->next)
3446 if (cur == node2)
3447 return(1);
3448 return(-1); /* assume there is no sibling list corruption */
3449 }
3450
3451 /**
3452 * xmlXPathNodeSetSort:
3453 * @set: the node set
3454 *
3455 * Sort the node set in document order
3456 */
3457 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3458 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3459 #ifndef WITH_TIM_SORT
3460 int i, j, incr, len;
3461 xmlNodePtr tmp;
3462 #endif
3463
3464 if (set == NULL)
3465 return;
3466
3467 #ifndef WITH_TIM_SORT
3468 /*
3469 * Use the old Shell's sort implementation to sort the node-set
3470 * Timsort ought to be quite faster
3471 */
3472 len = set->nodeNr;
3473 for (incr = len / 2; incr > 0; incr /= 2) {
3474 for (i = incr; i < len; i++) {
3475 j = i - incr;
3476 while (j >= 0) {
3477 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3478 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3479 set->nodeTab[j + incr]) == -1)
3480 #else
3481 if (xmlXPathCmpNodes(set->nodeTab[j],
3482 set->nodeTab[j + incr]) == -1)
3483 #endif
3484 {
3485 tmp = set->nodeTab[j];
3486 set->nodeTab[j] = set->nodeTab[j + incr];
3487 set->nodeTab[j + incr] = tmp;
3488 j -= incr;
3489 } else
3490 break;
3491 }
3492 }
3493 }
3494 #else /* WITH_TIM_SORT */
3495 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3496 #endif /* WITH_TIM_SORT */
3497 }
3498
3499 #define XML_NODESET_DEFAULT 10
3500 /**
3501 * xmlXPathNodeSetDupNs:
3502 * @node: the parent node of the namespace XPath node
3503 * @ns: the libxml namespace declaration node.
3504 *
3505 * Namespace node in libxml don't match the XPath semantic. In a node set
3506 * the namespace nodes are duplicated and the next pointer is set to the
3507 * parent node in the XPath semantic.
3508 *
3509 * Returns the newly created object.
3510 */
3511 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3512 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3513 xmlNsPtr cur;
3514
3515 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3516 return(NULL);
3517 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3518 return((xmlNodePtr) ns);
3519
3520 /*
3521 * Allocate a new Namespace and fill the fields.
3522 */
3523 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3524 if (cur == NULL) {
3525 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3526 return(NULL);
3527 }
3528 memset(cur, 0, sizeof(xmlNs));
3529 cur->type = XML_NAMESPACE_DECL;
3530 if (ns->href != NULL)
3531 cur->href = xmlStrdup(ns->href);
3532 if (ns->prefix != NULL)
3533 cur->prefix = xmlStrdup(ns->prefix);
3534 cur->next = (xmlNsPtr) node;
3535 return((xmlNodePtr) cur);
3536 }
3537
3538 /**
3539 * xmlXPathNodeSetFreeNs:
3540 * @ns: the XPath namespace node found in a nodeset.
3541 *
3542 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3543 * the namespace nodes are duplicated and the next pointer is set to the
3544 * parent node in the XPath semantic. Check if such a node needs to be freed
3545 */
3546 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3547 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3548 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3549 return;
3550
3551 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3552 if (ns->href != NULL)
3553 xmlFree((xmlChar *)ns->href);
3554 if (ns->prefix != NULL)
3555 xmlFree((xmlChar *)ns->prefix);
3556 xmlFree(ns);
3557 }
3558 }
3559
3560 /**
3561 * xmlXPathNodeSetCreate:
3562 * @val: an initial xmlNodePtr, or NULL
3563 *
3564 * Create a new xmlNodeSetPtr of type double and of value @val
3565 *
3566 * Returns the newly created object.
3567 */
3568 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3569 xmlXPathNodeSetCreate(xmlNodePtr val) {
3570 xmlNodeSetPtr ret;
3571
3572 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3573 if (ret == NULL) {
3574 xmlXPathErrMemory(NULL, "creating nodeset\n");
3575 return(NULL);
3576 }
3577 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3578 if (val != NULL) {
3579 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3580 sizeof(xmlNodePtr));
3581 if (ret->nodeTab == NULL) {
3582 xmlXPathErrMemory(NULL, "creating nodeset\n");
3583 xmlFree(ret);
3584 return(NULL);
3585 }
3586 memset(ret->nodeTab, 0 ,
3587 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3588 ret->nodeMax = XML_NODESET_DEFAULT;
3589 if (val->type == XML_NAMESPACE_DECL) {
3590 xmlNsPtr ns = (xmlNsPtr) val;
3591
3592 /* TODO: Check memory error. */
3593 ret->nodeTab[ret->nodeNr++] =
3594 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3595 } else
3596 ret->nodeTab[ret->nodeNr++] = val;
3597 }
3598 return(ret);
3599 }
3600
3601 /**
3602 * xmlXPathNodeSetContains:
3603 * @cur: the node-set
3604 * @val: the node
3605 *
3606 * checks whether @cur contains @val
3607 *
3608 * Returns true (1) if @cur contains @val, false (0) otherwise
3609 */
3610 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3611 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3612 int i;
3613
3614 if ((cur == NULL) || (val == NULL)) return(0);
3615 if (val->type == XML_NAMESPACE_DECL) {
3616 for (i = 0; i < cur->nodeNr; i++) {
3617 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3618 xmlNsPtr ns1, ns2;
3619
3620 ns1 = (xmlNsPtr) val;
3621 ns2 = (xmlNsPtr) cur->nodeTab[i];
3622 if (ns1 == ns2)
3623 return(1);
3624 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3625 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3626 return(1);
3627 }
3628 }
3629 } else {
3630 for (i = 0; i < cur->nodeNr; i++) {
3631 if (cur->nodeTab[i] == val)
3632 return(1);
3633 }
3634 }
3635 return(0);
3636 }
3637
3638 /**
3639 * xmlXPathNodeSetAddNs:
3640 * @cur: the initial node set
3641 * @node: the hosting node
3642 * @ns: a the namespace node
3643 *
3644 * add a new namespace node to an existing NodeSet
3645 *
3646 * Returns 0 in case of success and -1 in case of error
3647 */
3648 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3649 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3650 int i;
3651
3652
3653 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3654 (ns->type != XML_NAMESPACE_DECL) ||
3655 (node->type != XML_ELEMENT_NODE))
3656 return(-1);
3657
3658 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3659 /*
3660 * prevent duplicates
3661 */
3662 for (i = 0;i < cur->nodeNr;i++) {
3663 if ((cur->nodeTab[i] != NULL) &&
3664 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3665 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3666 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3667 return(0);
3668 }
3669
3670 /*
3671 * grow the nodeTab if needed
3672 */
3673 if (cur->nodeMax == 0) {
3674 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3675 sizeof(xmlNodePtr));
3676 if (cur->nodeTab == NULL) {
3677 xmlXPathErrMemory(NULL, "growing nodeset\n");
3678 return(-1);
3679 }
3680 memset(cur->nodeTab, 0 ,
3681 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3682 cur->nodeMax = XML_NODESET_DEFAULT;
3683 } else if (cur->nodeNr == cur->nodeMax) {
3684 xmlNodePtr *temp;
3685
3686 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3687 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3688 return(-1);
3689 }
3690 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3691 sizeof(xmlNodePtr));
3692 if (temp == NULL) {
3693 xmlXPathErrMemory(NULL, "growing nodeset\n");
3694 return(-1);
3695 }
3696 cur->nodeMax *= 2;
3697 cur->nodeTab = temp;
3698 }
3699 /* TODO: Check memory error. */
3700 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3701 return(0);
3702 }
3703
3704 /**
3705 * xmlXPathNodeSetAdd:
3706 * @cur: the initial node set
3707 * @val: a new xmlNodePtr
3708 *
3709 * add a new xmlNodePtr to an existing NodeSet
3710 *
3711 * Returns 0 in case of success, and -1 in case of error
3712 */
3713 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3714 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3715 int i;
3716
3717 if ((cur == NULL) || (val == NULL)) return(-1);
3718
3719 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3720 /*
3721 * prevent duplicates
3722 */
3723 for (i = 0;i < cur->nodeNr;i++)
3724 if (cur->nodeTab[i] == val) return(0);
3725
3726 /*
3727 * grow the nodeTab if needed
3728 */
3729 if (cur->nodeMax == 0) {
3730 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3731 sizeof(xmlNodePtr));
3732 if (cur->nodeTab == NULL) {
3733 xmlXPathErrMemory(NULL, "growing nodeset\n");
3734 return(-1);
3735 }
3736 memset(cur->nodeTab, 0 ,
3737 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3738 cur->nodeMax = XML_NODESET_DEFAULT;
3739 } else if (cur->nodeNr == cur->nodeMax) {
3740 xmlNodePtr *temp;
3741
3742 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3743 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3744 return(-1);
3745 }
3746 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3747 sizeof(xmlNodePtr));
3748 if (temp == NULL) {
3749 xmlXPathErrMemory(NULL, "growing nodeset\n");
3750 return(-1);
3751 }
3752 cur->nodeMax *= 2;
3753 cur->nodeTab = temp;
3754 }
3755 if (val->type == XML_NAMESPACE_DECL) {
3756 xmlNsPtr ns = (xmlNsPtr) val;
3757
3758 /* TODO: Check memory error. */
3759 cur->nodeTab[cur->nodeNr++] =
3760 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3761 } else
3762 cur->nodeTab[cur->nodeNr++] = val;
3763 return(0);
3764 }
3765
3766 /**
3767 * xmlXPathNodeSetAddUnique:
3768 * @cur: the initial node set
3769 * @val: a new xmlNodePtr
3770 *
3771 * add a new xmlNodePtr to an existing NodeSet, optimized version
3772 * when we are sure the node is not already in the set.
3773 *
3774 * Returns 0 in case of success and -1 in case of failure
3775 */
3776 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3777 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3778 if ((cur == NULL) || (val == NULL)) return(-1);
3779
3780 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3781 /*
3782 * grow the nodeTab if needed
3783 */
3784 if (cur->nodeMax == 0) {
3785 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3786 sizeof(xmlNodePtr));
3787 if (cur->nodeTab == NULL) {
3788 xmlXPathErrMemory(NULL, "growing nodeset\n");
3789 return(-1);
3790 }
3791 memset(cur->nodeTab, 0 ,
3792 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3793 cur->nodeMax = XML_NODESET_DEFAULT;
3794 } else if (cur->nodeNr == cur->nodeMax) {
3795 xmlNodePtr *temp;
3796
3797 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3798 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3799 return(-1);
3800 }
3801 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3802 sizeof(xmlNodePtr));
3803 if (temp == NULL) {
3804 xmlXPathErrMemory(NULL, "growing nodeset\n");
3805 return(-1);
3806 }
3807 cur->nodeTab = temp;
3808 cur->nodeMax *= 2;
3809 }
3810 if (val->type == XML_NAMESPACE_DECL) {
3811 xmlNsPtr ns = (xmlNsPtr) val;
3812
3813 /* TODO: Check memory error. */
3814 cur->nodeTab[cur->nodeNr++] =
3815 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3816 } else
3817 cur->nodeTab[cur->nodeNr++] = val;
3818 return(0);
3819 }
3820
3821 /**
3822 * xmlXPathNodeSetMerge:
3823 * @val1: the first NodeSet or NULL
3824 * @val2: the second NodeSet
3825 *
3826 * Merges two nodesets, all nodes from @val2 are added to @val1
3827 * if @val1 is NULL, a new set is created and copied from @val2
3828 *
3829 * Returns @val1 once extended or NULL in case of error.
3830 */
3831 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3832 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3833 int i, j, initNr, skip;
3834 xmlNodePtr n1, n2;
3835
3836 if (val2 == NULL) return(val1);
3837 if (val1 == NULL) {
3838 val1 = xmlXPathNodeSetCreate(NULL);
3839 if (val1 == NULL)
3840 return (NULL);
3841 #if 0
3842 /*
3843 * TODO: The optimization won't work in every case, since
3844 * those nasty namespace nodes need to be added with
3845 * xmlXPathNodeSetDupNs() to the set; thus a pure
3846 * memcpy is not possible.
3847 * If there was a flag on the nodesetval, indicating that
3848 * some temporary nodes are in, that would be helpful.
3849 */
3850 /*
3851 * Optimization: Create an equally sized node-set
3852 * and memcpy the content.
3853 */
3854 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3855 if (val1 == NULL)
3856 return(NULL);
3857 if (val2->nodeNr != 0) {
3858 if (val2->nodeNr == 1)
3859 *(val1->nodeTab) = *(val2->nodeTab);
3860 else {
3861 memcpy(val1->nodeTab, val2->nodeTab,
3862 val2->nodeNr * sizeof(xmlNodePtr));
3863 }
3864 val1->nodeNr = val2->nodeNr;
3865 }
3866 return(val1);
3867 #endif
3868 }
3869
3870 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3871 initNr = val1->nodeNr;
3872
3873 for (i = 0;i < val2->nodeNr;i++) {
3874 n2 = val2->nodeTab[i];
3875 /*
3876 * check against duplicates
3877 */
3878 skip = 0;
3879 for (j = 0; j < initNr; j++) {
3880 n1 = val1->nodeTab[j];
3881 if (n1 == n2) {
3882 skip = 1;
3883 break;
3884 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3885 (n2->type == XML_NAMESPACE_DECL)) {
3886 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3887 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3888 ((xmlNsPtr) n2)->prefix)))
3889 {
3890 skip = 1;
3891 break;
3892 }
3893 }
3894 }
3895 if (skip)
3896 continue;
3897
3898 /*
3899 * grow the nodeTab if needed
3900 */
3901 if (val1->nodeMax == 0) {
3902 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3903 sizeof(xmlNodePtr));
3904 if (val1->nodeTab == NULL) {
3905 xmlXPathErrMemory(NULL, "merging nodeset\n");
3906 return(NULL);
3907 }
3908 memset(val1->nodeTab, 0 ,
3909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3910 val1->nodeMax = XML_NODESET_DEFAULT;
3911 } else if (val1->nodeNr == val1->nodeMax) {
3912 xmlNodePtr *temp;
3913
3914 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3915 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3916 return(NULL);
3917 }
3918 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3919 sizeof(xmlNodePtr));
3920 if (temp == NULL) {
3921 xmlXPathErrMemory(NULL, "merging nodeset\n");
3922 return(NULL);
3923 }
3924 val1->nodeTab = temp;
3925 val1->nodeMax *= 2;
3926 }
3927 if (n2->type == XML_NAMESPACE_DECL) {
3928 xmlNsPtr ns = (xmlNsPtr) n2;
3929
3930 /* TODO: Check memory error. */
3931 val1->nodeTab[val1->nodeNr++] =
3932 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933 } else
3934 val1->nodeTab[val1->nodeNr++] = n2;
3935 }
3936
3937 return(val1);
3938 }
3939
3940
3941 /**
3942 * xmlXPathNodeSetMergeAndClear:
3943 * @set1: the first NodeSet or NULL
3944 * @set2: the second NodeSet
3945 *
3946 * Merges two nodesets, all nodes from @set2 are added to @set1.
3947 * Checks for duplicate nodes. Clears set2.
3948 *
3949 * Returns @set1 once extended or NULL in case of error.
3950 */
3951 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2)3952 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3953 {
3954 {
3955 int i, j, initNbSet1;
3956 xmlNodePtr n1, n2;
3957
3958 initNbSet1 = set1->nodeNr;
3959 for (i = 0;i < set2->nodeNr;i++) {
3960 n2 = set2->nodeTab[i];
3961 /*
3962 * Skip duplicates.
3963 */
3964 for (j = 0; j < initNbSet1; j++) {
3965 n1 = set1->nodeTab[j];
3966 if (n1 == n2) {
3967 goto skip_node;
3968 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3969 (n2->type == XML_NAMESPACE_DECL))
3970 {
3971 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3972 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3973 ((xmlNsPtr) n2)->prefix)))
3974 {
3975 /*
3976 * Free the namespace node.
3977 */
3978 set2->nodeTab[i] = NULL;
3979 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3980 goto skip_node;
3981 }
3982 }
3983 }
3984 /*
3985 * grow the nodeTab if needed
3986 */
3987 if (set1->nodeMax == 0) {
3988 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3989 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3990 if (set1->nodeTab == NULL) {
3991 xmlXPathErrMemory(NULL, "merging nodeset\n");
3992 return(NULL);
3993 }
3994 memset(set1->nodeTab, 0,
3995 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3996 set1->nodeMax = XML_NODESET_DEFAULT;
3997 } else if (set1->nodeNr >= set1->nodeMax) {
3998 xmlNodePtr *temp;
3999
4000 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4001 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4002 return(NULL);
4003 }
4004 temp = (xmlNodePtr *) xmlRealloc(
4005 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4006 if (temp == NULL) {
4007 xmlXPathErrMemory(NULL, "merging nodeset\n");
4008 return(NULL);
4009 }
4010 set1->nodeTab = temp;
4011 set1->nodeMax *= 2;
4012 }
4013 set1->nodeTab[set1->nodeNr++] = n2;
4014 skip_node:
4015 {}
4016 }
4017 }
4018 set2->nodeNr = 0;
4019 return(set1);
4020 }
4021
4022 /**
4023 * xmlXPathNodeSetMergeAndClearNoDupls:
4024 * @set1: the first NodeSet or NULL
4025 * @set2: the second NodeSet
4026 *
4027 * Merges two nodesets, all nodes from @set2 are added to @set1.
4028 * Doesn't check for duplicate nodes. Clears set2.
4029 *
4030 * Returns @set1 once extended or NULL in case of error.
4031 */
4032 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2)4033 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4034 {
4035 {
4036 int i;
4037 xmlNodePtr n2;
4038
4039 for (i = 0;i < set2->nodeNr;i++) {
4040 n2 = set2->nodeTab[i];
4041 if (set1->nodeMax == 0) {
4042 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4043 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4044 if (set1->nodeTab == NULL) {
4045 xmlXPathErrMemory(NULL, "merging nodeset\n");
4046 return(NULL);
4047 }
4048 memset(set1->nodeTab, 0,
4049 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4050 set1->nodeMax = XML_NODESET_DEFAULT;
4051 } else if (set1->nodeNr >= set1->nodeMax) {
4052 xmlNodePtr *temp;
4053
4054 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4055 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4056 return(NULL);
4057 }
4058 temp = (xmlNodePtr *) xmlRealloc(
4059 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4060 if (temp == NULL) {
4061 xmlXPathErrMemory(NULL, "merging nodeset\n");
4062 return(NULL);
4063 }
4064 set1->nodeTab = temp;
4065 set1->nodeMax *= 2;
4066 }
4067 set1->nodeTab[set1->nodeNr++] = n2;
4068 }
4069 }
4070 set2->nodeNr = 0;
4071 return(set1);
4072 }
4073
4074 /**
4075 * xmlXPathNodeSetDel:
4076 * @cur: the initial node set
4077 * @val: an xmlNodePtr
4078 *
4079 * Removes an xmlNodePtr from an existing NodeSet
4080 */
4081 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4082 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4083 int i;
4084
4085 if (cur == NULL) return;
4086 if (val == NULL) return;
4087
4088 /*
4089 * find node in nodeTab
4090 */
4091 for (i = 0;i < cur->nodeNr;i++)
4092 if (cur->nodeTab[i] == val) break;
4093
4094 if (i >= cur->nodeNr) { /* not found */
4095 #ifdef DEBUG
4096 xmlGenericError(xmlGenericErrorContext,
4097 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4098 val->name);
4099 #endif
4100 return;
4101 }
4102 if ((cur->nodeTab[i] != NULL) &&
4103 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4104 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4105 cur->nodeNr--;
4106 for (;i < cur->nodeNr;i++)
4107 cur->nodeTab[i] = cur->nodeTab[i + 1];
4108 cur->nodeTab[cur->nodeNr] = NULL;
4109 }
4110
4111 /**
4112 * xmlXPathNodeSetRemove:
4113 * @cur: the initial node set
4114 * @val: the index to remove
4115 *
4116 * Removes an entry from an existing NodeSet list.
4117 */
4118 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4119 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4120 if (cur == NULL) return;
4121 if (val >= cur->nodeNr) return;
4122 if ((cur->nodeTab[val] != NULL) &&
4123 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4124 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4125 cur->nodeNr--;
4126 for (;val < cur->nodeNr;val++)
4127 cur->nodeTab[val] = cur->nodeTab[val + 1];
4128 cur->nodeTab[cur->nodeNr] = NULL;
4129 }
4130
4131 /**
4132 * xmlXPathFreeNodeSet:
4133 * @obj: the xmlNodeSetPtr to free
4134 *
4135 * Free the NodeSet compound (not the actual nodes !).
4136 */
4137 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4138 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4139 if (obj == NULL) return;
4140 if (obj->nodeTab != NULL) {
4141 int i;
4142
4143 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4144 for (i = 0;i < obj->nodeNr;i++)
4145 if ((obj->nodeTab[i] != NULL) &&
4146 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4147 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4148 xmlFree(obj->nodeTab);
4149 }
4150 xmlFree(obj);
4151 }
4152
4153 /**
4154 * xmlXPathNodeSetClearFromPos:
4155 * @set: the node set to be cleared
4156 * @pos: the start position to clear from
4157 *
4158 * Clears the list from temporary XPath objects (e.g. namespace nodes
4159 * are feed) starting with the entry at @pos, but does *not* free the list
4160 * itself. Sets the length of the list to @pos.
4161 */
4162 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4163 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4164 {
4165 if ((set == NULL) || (pos >= set->nodeNr))
4166 return;
4167 else if ((hasNsNodes)) {
4168 int i;
4169 xmlNodePtr node;
4170
4171 for (i = pos; i < set->nodeNr; i++) {
4172 node = set->nodeTab[i];
4173 if ((node != NULL) &&
4174 (node->type == XML_NAMESPACE_DECL))
4175 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4176 }
4177 }
4178 set->nodeNr = pos;
4179 }
4180
4181 /**
4182 * xmlXPathNodeSetClear:
4183 * @set: the node set to clear
4184 *
4185 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4186 * are feed), but does *not* free the list itself. Sets the length of the
4187 * list to 0.
4188 */
4189 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4190 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4191 {
4192 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4193 }
4194
4195 /**
4196 * xmlXPathNodeSetKeepLast:
4197 * @set: the node set to be cleared
4198 *
4199 * Move the last node to the first position and clear temporary XPath objects
4200 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4201 * to 1.
4202 */
4203 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4204 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4205 {
4206 int i;
4207 xmlNodePtr node;
4208
4209 if ((set == NULL) || (set->nodeNr <= 1))
4210 return;
4211 for (i = 0; i < set->nodeNr - 1; i++) {
4212 node = set->nodeTab[i];
4213 if ((node != NULL) &&
4214 (node->type == XML_NAMESPACE_DECL))
4215 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4216 }
4217 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4218 set->nodeNr = 1;
4219 }
4220
4221 /**
4222 * xmlXPathFreeValueTree:
4223 * @obj: the xmlNodeSetPtr to free
4224 *
4225 * Free the NodeSet compound and the actual tree, this is different
4226 * from xmlXPathFreeNodeSet()
4227 */
4228 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4229 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4230 int i;
4231
4232 if (obj == NULL) return;
4233
4234 if (obj->nodeTab != NULL) {
4235 for (i = 0;i < obj->nodeNr;i++) {
4236 if (obj->nodeTab[i] != NULL) {
4237 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4238 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4239 } else {
4240 xmlFreeNodeList(obj->nodeTab[i]);
4241 }
4242 }
4243 }
4244 xmlFree(obj->nodeTab);
4245 }
4246 xmlFree(obj);
4247 }
4248
4249 #if defined(DEBUG) || defined(DEBUG_STEP)
4250 /**
4251 * xmlGenericErrorContextNodeSet:
4252 * @output: a FILE * for the output
4253 * @obj: the xmlNodeSetPtr to display
4254 *
4255 * Quick display of a NodeSet
4256 */
4257 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4258 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4259 int i;
4260
4261 if (output == NULL) output = xmlGenericErrorContext;
4262 if (obj == NULL) {
4263 fprintf(output, "NodeSet == NULL !\n");
4264 return;
4265 }
4266 if (obj->nodeNr == 0) {
4267 fprintf(output, "NodeSet is empty\n");
4268 return;
4269 }
4270 if (obj->nodeTab == NULL) {
4271 fprintf(output, " nodeTab == NULL !\n");
4272 return;
4273 }
4274 for (i = 0; i < obj->nodeNr; i++) {
4275 if (obj->nodeTab[i] == NULL) {
4276 fprintf(output, " NULL !\n");
4277 return;
4278 }
4279 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4280 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4281 fprintf(output, " /");
4282 else if (obj->nodeTab[i]->name == NULL)
4283 fprintf(output, " noname!");
4284 else fprintf(output, " %s", obj->nodeTab[i]->name);
4285 }
4286 fprintf(output, "\n");
4287 }
4288 #endif
4289
4290 /**
4291 * xmlXPathNewNodeSet:
4292 * @val: the NodePtr value
4293 *
4294 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4295 * it with the single Node @val
4296 *
4297 * Returns the newly created object.
4298 */
4299 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4300 xmlXPathNewNodeSet(xmlNodePtr val) {
4301 xmlXPathObjectPtr ret;
4302
4303 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304 if (ret == NULL) {
4305 xmlXPathErrMemory(NULL, "creating nodeset\n");
4306 return(NULL);
4307 }
4308 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4309 ret->type = XPATH_NODESET;
4310 ret->boolval = 0;
4311 /* TODO: Check memory error. */
4312 ret->nodesetval = xmlXPathNodeSetCreate(val);
4313 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4314 #ifdef XP_DEBUG_OBJ_USAGE
4315 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4316 #endif
4317 return(ret);
4318 }
4319
4320 /**
4321 * xmlXPathNewValueTree:
4322 * @val: the NodePtr value
4323 *
4324 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4325 * it with the tree root @val
4326 *
4327 * Returns the newly created object.
4328 */
4329 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4330 xmlXPathNewValueTree(xmlNodePtr val) {
4331 xmlXPathObjectPtr ret;
4332
4333 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4334 if (ret == NULL) {
4335 xmlXPathErrMemory(NULL, "creating result value tree\n");
4336 return(NULL);
4337 }
4338 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4339 ret->type = XPATH_XSLT_TREE;
4340 ret->boolval = 1;
4341 ret->user = (void *) val;
4342 ret->nodesetval = xmlXPathNodeSetCreate(val);
4343 #ifdef XP_DEBUG_OBJ_USAGE
4344 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4345 #endif
4346 return(ret);
4347 }
4348
4349 /**
4350 * xmlXPathNewNodeSetList:
4351 * @val: an existing NodeSet
4352 *
4353 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4354 * it with the Nodeset @val
4355 *
4356 * Returns the newly created object.
4357 */
4358 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4359 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4360 {
4361 xmlXPathObjectPtr ret;
4362 int i;
4363
4364 if (val == NULL)
4365 ret = NULL;
4366 else if (val->nodeTab == NULL)
4367 ret = xmlXPathNewNodeSet(NULL);
4368 else {
4369 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4370 if (ret) {
4371 for (i = 1; i < val->nodeNr; ++i) {
4372 /* TODO: Propagate memory error. */
4373 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4374 < 0) break;
4375 }
4376 }
4377 }
4378
4379 return (ret);
4380 }
4381
4382 /**
4383 * xmlXPathWrapNodeSet:
4384 * @val: the NodePtr value
4385 *
4386 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4387 *
4388 * Returns the newly created object.
4389 */
4390 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4391 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4392 xmlXPathObjectPtr ret;
4393
4394 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4395 if (ret == NULL) {
4396 xmlXPathErrMemory(NULL, "creating node set object\n");
4397 return(NULL);
4398 }
4399 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4400 ret->type = XPATH_NODESET;
4401 ret->nodesetval = val;
4402 #ifdef XP_DEBUG_OBJ_USAGE
4403 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4404 #endif
4405 return(ret);
4406 }
4407
4408 /**
4409 * xmlXPathFreeNodeSetList:
4410 * @obj: an existing NodeSetList object
4411 *
4412 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4413 * the list contrary to xmlXPathFreeObject().
4414 */
4415 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4416 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4417 if (obj == NULL) return;
4418 #ifdef XP_DEBUG_OBJ_USAGE
4419 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4420 #endif
4421 xmlFree(obj);
4422 }
4423
4424 /**
4425 * xmlXPathDifference:
4426 * @nodes1: a node-set
4427 * @nodes2: a node-set
4428 *
4429 * Implements the EXSLT - Sets difference() function:
4430 * node-set set:difference (node-set, node-set)
4431 *
4432 * Returns the difference between the two node sets, or nodes1 if
4433 * nodes2 is empty
4434 */
4435 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4436 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4437 xmlNodeSetPtr ret;
4438 int i, l1;
4439 xmlNodePtr cur;
4440
4441 if (xmlXPathNodeSetIsEmpty(nodes2))
4442 return(nodes1);
4443
4444 /* TODO: Check memory error. */
4445 ret = xmlXPathNodeSetCreate(NULL);
4446 if (xmlXPathNodeSetIsEmpty(nodes1))
4447 return(ret);
4448
4449 l1 = xmlXPathNodeSetGetLength(nodes1);
4450
4451 for (i = 0; i < l1; i++) {
4452 cur = xmlXPathNodeSetItem(nodes1, i);
4453 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4454 /* TODO: Propagate memory error. */
4455 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4456 break;
4457 }
4458 }
4459 return(ret);
4460 }
4461
4462 /**
4463 * xmlXPathIntersection:
4464 * @nodes1: a node-set
4465 * @nodes2: a node-set
4466 *
4467 * Implements the EXSLT - Sets intersection() function:
4468 * node-set set:intersection (node-set, node-set)
4469 *
4470 * Returns a node set comprising the nodes that are within both the
4471 * node sets passed as arguments
4472 */
4473 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4474 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4476 int i, l1;
4477 xmlNodePtr cur;
4478
4479 if (ret == NULL)
4480 return(ret);
4481 if (xmlXPathNodeSetIsEmpty(nodes1))
4482 return(ret);
4483 if (xmlXPathNodeSetIsEmpty(nodes2))
4484 return(ret);
4485
4486 l1 = xmlXPathNodeSetGetLength(nodes1);
4487
4488 for (i = 0; i < l1; i++) {
4489 cur = xmlXPathNodeSetItem(nodes1, i);
4490 if (xmlXPathNodeSetContains(nodes2, cur)) {
4491 /* TODO: Propagate memory error. */
4492 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4493 break;
4494 }
4495 }
4496 return(ret);
4497 }
4498
4499 /**
4500 * xmlXPathDistinctSorted:
4501 * @nodes: a node-set, sorted by document order
4502 *
4503 * Implements the EXSLT - Sets distinct() function:
4504 * node-set set:distinct (node-set)
4505 *
4506 * Returns a subset of the nodes contained in @nodes, or @nodes if
4507 * it is empty
4508 */
4509 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4510 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4511 xmlNodeSetPtr ret;
4512 xmlHashTablePtr hash;
4513 int i, l;
4514 xmlChar * strval;
4515 xmlNodePtr cur;
4516
4517 if (xmlXPathNodeSetIsEmpty(nodes))
4518 return(nodes);
4519
4520 ret = xmlXPathNodeSetCreate(NULL);
4521 if (ret == NULL)
4522 return(ret);
4523 l = xmlXPathNodeSetGetLength(nodes);
4524 hash = xmlHashCreate (l);
4525 for (i = 0; i < l; i++) {
4526 cur = xmlXPathNodeSetItem(nodes, i);
4527 strval = xmlXPathCastNodeToString(cur);
4528 if (xmlHashLookup(hash, strval) == NULL) {
4529 xmlHashAddEntry(hash, strval, strval);
4530 /* TODO: Propagate memory error. */
4531 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4532 break;
4533 } else {
4534 xmlFree(strval);
4535 }
4536 }
4537 xmlHashFree(hash, xmlHashDefaultDeallocator);
4538 return(ret);
4539 }
4540
4541 /**
4542 * xmlXPathDistinct:
4543 * @nodes: a node-set
4544 *
4545 * Implements the EXSLT - Sets distinct() function:
4546 * node-set set:distinct (node-set)
4547 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4548 * is called with the sorted node-set
4549 *
4550 * Returns a subset of the nodes contained in @nodes, or @nodes if
4551 * it is empty
4552 */
4553 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4554 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4555 if (xmlXPathNodeSetIsEmpty(nodes))
4556 return(nodes);
4557
4558 xmlXPathNodeSetSort(nodes);
4559 return(xmlXPathDistinctSorted(nodes));
4560 }
4561
4562 /**
4563 * xmlXPathHasSameNodes:
4564 * @nodes1: a node-set
4565 * @nodes2: a node-set
4566 *
4567 * Implements the EXSLT - Sets has-same-nodes function:
4568 * boolean set:has-same-node(node-set, node-set)
4569 *
4570 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4571 * otherwise
4572 */
4573 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4574 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4575 int i, l;
4576 xmlNodePtr cur;
4577
4578 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4579 xmlXPathNodeSetIsEmpty(nodes2))
4580 return(0);
4581
4582 l = xmlXPathNodeSetGetLength(nodes1);
4583 for (i = 0; i < l; i++) {
4584 cur = xmlXPathNodeSetItem(nodes1, i);
4585 if (xmlXPathNodeSetContains(nodes2, cur))
4586 return(1);
4587 }
4588 return(0);
4589 }
4590
4591 /**
4592 * xmlXPathNodeLeadingSorted:
4593 * @nodes: a node-set, sorted by document order
4594 * @node: a node
4595 *
4596 * Implements the EXSLT - Sets leading() function:
4597 * node-set set:leading (node-set, node-set)
4598 *
4599 * Returns the nodes in @nodes that precede @node in document order,
4600 * @nodes if @node is NULL or an empty node-set if @nodes
4601 * doesn't contain @node
4602 */
4603 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4604 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4605 int i, l;
4606 xmlNodePtr cur;
4607 xmlNodeSetPtr ret;
4608
4609 if (node == NULL)
4610 return(nodes);
4611
4612 ret = xmlXPathNodeSetCreate(NULL);
4613 if (ret == NULL)
4614 return(ret);
4615 if (xmlXPathNodeSetIsEmpty(nodes) ||
4616 (!xmlXPathNodeSetContains(nodes, node)))
4617 return(ret);
4618
4619 l = xmlXPathNodeSetGetLength(nodes);
4620 for (i = 0; i < l; i++) {
4621 cur = xmlXPathNodeSetItem(nodes, i);
4622 if (cur == node)
4623 break;
4624 /* TODO: Propagate memory error. */
4625 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4626 break;
4627 }
4628 return(ret);
4629 }
4630
4631 /**
4632 * xmlXPathNodeLeading:
4633 * @nodes: a node-set
4634 * @node: a node
4635 *
4636 * Implements the EXSLT - Sets leading() function:
4637 * node-set set:leading (node-set, node-set)
4638 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4639 * is called.
4640 *
4641 * Returns the nodes in @nodes that precede @node in document order,
4642 * @nodes if @node is NULL or an empty node-set if @nodes
4643 * doesn't contain @node
4644 */
4645 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4646 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4647 xmlXPathNodeSetSort(nodes);
4648 return(xmlXPathNodeLeadingSorted(nodes, node));
4649 }
4650
4651 /**
4652 * xmlXPathLeadingSorted:
4653 * @nodes1: a node-set, sorted by document order
4654 * @nodes2: a node-set, sorted by document order
4655 *
4656 * Implements the EXSLT - Sets leading() function:
4657 * node-set set:leading (node-set, node-set)
4658 *
4659 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4660 * in document order, @nodes1 if @nodes2 is NULL or empty or
4661 * an empty node-set if @nodes1 doesn't contain @nodes2
4662 */
4663 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4664 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4665 if (xmlXPathNodeSetIsEmpty(nodes2))
4666 return(nodes1);
4667 return(xmlXPathNodeLeadingSorted(nodes1,
4668 xmlXPathNodeSetItem(nodes2, 1)));
4669 }
4670
4671 /**
4672 * xmlXPathLeading:
4673 * @nodes1: a node-set
4674 * @nodes2: a node-set
4675 *
4676 * Implements the EXSLT - Sets leading() function:
4677 * node-set set:leading (node-set, node-set)
4678 * @nodes1 and @nodes2 are sorted by document order, then
4679 * #exslSetsLeadingSorted is called.
4680 *
4681 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4682 * in document order, @nodes1 if @nodes2 is NULL or empty or
4683 * an empty node-set if @nodes1 doesn't contain @nodes2
4684 */
4685 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4686 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4687 if (xmlXPathNodeSetIsEmpty(nodes2))
4688 return(nodes1);
4689 if (xmlXPathNodeSetIsEmpty(nodes1))
4690 return(xmlXPathNodeSetCreate(NULL));
4691 xmlXPathNodeSetSort(nodes1);
4692 xmlXPathNodeSetSort(nodes2);
4693 return(xmlXPathNodeLeadingSorted(nodes1,
4694 xmlXPathNodeSetItem(nodes2, 1)));
4695 }
4696
4697 /**
4698 * xmlXPathNodeTrailingSorted:
4699 * @nodes: a node-set, sorted by document order
4700 * @node: a node
4701 *
4702 * Implements the EXSLT - Sets trailing() function:
4703 * node-set set:trailing (node-set, node-set)
4704 *
4705 * Returns the nodes in @nodes that follow @node in document order,
4706 * @nodes if @node is NULL or an empty node-set if @nodes
4707 * doesn't contain @node
4708 */
4709 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4710 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4711 int i, l;
4712 xmlNodePtr cur;
4713 xmlNodeSetPtr ret;
4714
4715 if (node == NULL)
4716 return(nodes);
4717
4718 ret = xmlXPathNodeSetCreate(NULL);
4719 if (ret == NULL)
4720 return(ret);
4721 if (xmlXPathNodeSetIsEmpty(nodes) ||
4722 (!xmlXPathNodeSetContains(nodes, node)))
4723 return(ret);
4724
4725 l = xmlXPathNodeSetGetLength(nodes);
4726 for (i = l - 1; i >= 0; i--) {
4727 cur = xmlXPathNodeSetItem(nodes, i);
4728 if (cur == node)
4729 break;
4730 /* TODO: Propagate memory error. */
4731 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4732 break;
4733 }
4734 xmlXPathNodeSetSort(ret); /* bug 413451 */
4735 return(ret);
4736 }
4737
4738 /**
4739 * xmlXPathNodeTrailing:
4740 * @nodes: a node-set
4741 * @node: a node
4742 *
4743 * Implements the EXSLT - Sets trailing() function:
4744 * node-set set:trailing (node-set, node-set)
4745 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4746 * is called.
4747 *
4748 * Returns the nodes in @nodes that follow @node in document order,
4749 * @nodes if @node is NULL or an empty node-set if @nodes
4750 * doesn't contain @node
4751 */
4752 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4753 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4754 xmlXPathNodeSetSort(nodes);
4755 return(xmlXPathNodeTrailingSorted(nodes, node));
4756 }
4757
4758 /**
4759 * xmlXPathTrailingSorted:
4760 * @nodes1: a node-set, sorted by document order
4761 * @nodes2: a node-set, sorted by document order
4762 *
4763 * Implements the EXSLT - Sets trailing() function:
4764 * node-set set:trailing (node-set, node-set)
4765 *
4766 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4767 * in document order, @nodes1 if @nodes2 is NULL or empty or
4768 * an empty node-set if @nodes1 doesn't contain @nodes2
4769 */
4770 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4771 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4772 if (xmlXPathNodeSetIsEmpty(nodes2))
4773 return(nodes1);
4774 return(xmlXPathNodeTrailingSorted(nodes1,
4775 xmlXPathNodeSetItem(nodes2, 0)));
4776 }
4777
4778 /**
4779 * xmlXPathTrailing:
4780 * @nodes1: a node-set
4781 * @nodes2: a node-set
4782 *
4783 * Implements the EXSLT - Sets trailing() function:
4784 * node-set set:trailing (node-set, node-set)
4785 * @nodes1 and @nodes2 are sorted by document order, then
4786 * #xmlXPathTrailingSorted is called.
4787 *
4788 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4789 * in document order, @nodes1 if @nodes2 is NULL or empty or
4790 * an empty node-set if @nodes1 doesn't contain @nodes2
4791 */
4792 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4793 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4794 if (xmlXPathNodeSetIsEmpty(nodes2))
4795 return(nodes1);
4796 if (xmlXPathNodeSetIsEmpty(nodes1))
4797 return(xmlXPathNodeSetCreate(NULL));
4798 xmlXPathNodeSetSort(nodes1);
4799 xmlXPathNodeSetSort(nodes2);
4800 return(xmlXPathNodeTrailingSorted(nodes1,
4801 xmlXPathNodeSetItem(nodes2, 0)));
4802 }
4803
4804 /************************************************************************
4805 * *
4806 * Routines to handle extra functions *
4807 * *
4808 ************************************************************************/
4809
4810 /**
4811 * xmlXPathRegisterFunc:
4812 * @ctxt: the XPath context
4813 * @name: the function name
4814 * @f: the function implementation or NULL
4815 *
4816 * Register a new function. If @f is NULL it unregisters the function
4817 *
4818 * Returns 0 in case of success, -1 in case of error
4819 */
4820 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4821 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4822 xmlXPathFunction f) {
4823 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4824 }
4825
4826 /**
4827 * xmlXPathRegisterFuncNS:
4828 * @ctxt: the XPath context
4829 * @name: the function name
4830 * @ns_uri: the function namespace URI
4831 * @f: the function implementation or NULL
4832 *
4833 * Register a new function. If @f is NULL it unregisters the function
4834 *
4835 * Returns 0 in case of success, -1 in case of error
4836 */
4837 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4838 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4839 const xmlChar *ns_uri, xmlXPathFunction f) {
4840 if (ctxt == NULL)
4841 return(-1);
4842 if (name == NULL)
4843 return(-1);
4844
4845 if (ctxt->funcHash == NULL)
4846 ctxt->funcHash = xmlHashCreate(0);
4847 if (ctxt->funcHash == NULL)
4848 return(-1);
4849 if (f == NULL)
4850 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4851 XML_IGNORE_PEDANTIC_WARNINGS
4852 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4853 XML_POP_WARNINGS
4854 }
4855
4856 /**
4857 * xmlXPathRegisterFuncLookup:
4858 * @ctxt: the XPath context
4859 * @f: the lookup function
4860 * @funcCtxt: the lookup data
4861 *
4862 * Registers an external mechanism to do function lookup.
4863 */
4864 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4865 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4866 xmlXPathFuncLookupFunc f,
4867 void *funcCtxt) {
4868 if (ctxt == NULL)
4869 return;
4870 ctxt->funcLookupFunc = f;
4871 ctxt->funcLookupData = funcCtxt;
4872 }
4873
4874 /**
4875 * xmlXPathFunctionLookup:
4876 * @ctxt: the XPath context
4877 * @name: the function name
4878 *
4879 * Search in the Function array of the context for the given
4880 * function.
4881 *
4882 * Returns the xmlXPathFunction or NULL if not found
4883 */
4884 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4885 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4886 if (ctxt == NULL)
4887 return (NULL);
4888
4889 if (ctxt->funcLookupFunc != NULL) {
4890 xmlXPathFunction ret;
4891 xmlXPathFuncLookupFunc f;
4892
4893 f = ctxt->funcLookupFunc;
4894 ret = f(ctxt->funcLookupData, name, NULL);
4895 if (ret != NULL)
4896 return(ret);
4897 }
4898 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4899 }
4900
4901 /**
4902 * xmlXPathFunctionLookupNS:
4903 * @ctxt: the XPath context
4904 * @name: the function name
4905 * @ns_uri: the function namespace URI
4906 *
4907 * Search in the Function array of the context for the given
4908 * function.
4909 *
4910 * Returns the xmlXPathFunction or NULL if not found
4911 */
4912 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4913 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4914 const xmlChar *ns_uri) {
4915 xmlXPathFunction ret;
4916
4917 if (ctxt == NULL)
4918 return(NULL);
4919 if (name == NULL)
4920 return(NULL);
4921
4922 if (ctxt->funcLookupFunc != NULL) {
4923 xmlXPathFuncLookupFunc f;
4924
4925 f = ctxt->funcLookupFunc;
4926 ret = f(ctxt->funcLookupData, name, ns_uri);
4927 if (ret != NULL)
4928 return(ret);
4929 }
4930
4931 if (ctxt->funcHash == NULL)
4932 return(NULL);
4933
4934 XML_IGNORE_PEDANTIC_WARNINGS
4935 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4936 XML_POP_WARNINGS
4937 return(ret);
4938 }
4939
4940 /**
4941 * xmlXPathRegisteredFuncsCleanup:
4942 * @ctxt: the XPath context
4943 *
4944 * Cleanup the XPath context data associated to registered functions
4945 */
4946 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)4947 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4948 if (ctxt == NULL)
4949 return;
4950
4951 xmlHashFree(ctxt->funcHash, NULL);
4952 ctxt->funcHash = NULL;
4953 }
4954
4955 /************************************************************************
4956 * *
4957 * Routines to handle Variables *
4958 * *
4959 ************************************************************************/
4960
4961 /**
4962 * xmlXPathRegisterVariable:
4963 * @ctxt: the XPath context
4964 * @name: the variable name
4965 * @value: the variable value or NULL
4966 *
4967 * Register a new variable value. If @value is NULL it unregisters
4968 * the variable
4969 *
4970 * Returns 0 in case of success, -1 in case of error
4971 */
4972 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)4973 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4974 xmlXPathObjectPtr value) {
4975 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4976 }
4977
4978 /**
4979 * xmlXPathRegisterVariableNS:
4980 * @ctxt: the XPath context
4981 * @name: the variable name
4982 * @ns_uri: the variable namespace URI
4983 * @value: the variable value or NULL
4984 *
4985 * Register a new variable value. If @value is NULL it unregisters
4986 * the variable
4987 *
4988 * Returns 0 in case of success, -1 in case of error
4989 */
4990 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)4991 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4992 const xmlChar *ns_uri,
4993 xmlXPathObjectPtr value) {
4994 if (ctxt == NULL)
4995 return(-1);
4996 if (name == NULL)
4997 return(-1);
4998
4999 if (ctxt->varHash == NULL)
5000 ctxt->varHash = xmlHashCreate(0);
5001 if (ctxt->varHash == NULL)
5002 return(-1);
5003 if (value == NULL)
5004 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5005 xmlXPathFreeObjectEntry));
5006 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5007 (void *) value, xmlXPathFreeObjectEntry));
5008 }
5009
5010 /**
5011 * xmlXPathRegisterVariableLookup:
5012 * @ctxt: the XPath context
5013 * @f: the lookup function
5014 * @data: the lookup data
5015 *
5016 * register an external mechanism to do variable lookup
5017 */
5018 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5019 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5020 xmlXPathVariableLookupFunc f, void *data) {
5021 if (ctxt == NULL)
5022 return;
5023 ctxt->varLookupFunc = f;
5024 ctxt->varLookupData = data;
5025 }
5026
5027 /**
5028 * xmlXPathVariableLookup:
5029 * @ctxt: the XPath context
5030 * @name: the variable name
5031 *
5032 * Search in the Variable array of the context for the given
5033 * variable value.
5034 *
5035 * Returns a copy of the value or NULL if not found
5036 */
5037 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5038 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5039 if (ctxt == NULL)
5040 return(NULL);
5041
5042 if (ctxt->varLookupFunc != NULL) {
5043 xmlXPathObjectPtr ret;
5044
5045 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5046 (ctxt->varLookupData, name, NULL);
5047 return(ret);
5048 }
5049 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5050 }
5051
5052 /**
5053 * xmlXPathVariableLookupNS:
5054 * @ctxt: the XPath context
5055 * @name: the variable name
5056 * @ns_uri: the variable namespace URI
5057 *
5058 * Search in the Variable array of the context for the given
5059 * variable value.
5060 *
5061 * Returns the a copy of the value or NULL if not found
5062 */
5063 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5064 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5065 const xmlChar *ns_uri) {
5066 if (ctxt == NULL)
5067 return(NULL);
5068
5069 if (ctxt->varLookupFunc != NULL) {
5070 xmlXPathObjectPtr ret;
5071
5072 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5073 (ctxt->varLookupData, name, ns_uri);
5074 if (ret != NULL) return(ret);
5075 }
5076
5077 if (ctxt->varHash == NULL)
5078 return(NULL);
5079 if (name == NULL)
5080 return(NULL);
5081
5082 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5083 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5084 }
5085
5086 /**
5087 * xmlXPathRegisteredVariablesCleanup:
5088 * @ctxt: the XPath context
5089 *
5090 * Cleanup the XPath context data associated to registered variables
5091 */
5092 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5093 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5094 if (ctxt == NULL)
5095 return;
5096
5097 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5098 ctxt->varHash = NULL;
5099 }
5100
5101 /**
5102 * xmlXPathRegisterNs:
5103 * @ctxt: the XPath context
5104 * @prefix: the namespace prefix cannot be NULL or empty string
5105 * @ns_uri: the namespace name
5106 *
5107 * Register a new namespace. If @ns_uri is NULL it unregisters
5108 * the namespace
5109 *
5110 * Returns 0 in case of success, -1 in case of error
5111 */
5112 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5113 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5114 const xmlChar *ns_uri) {
5115 if (ctxt == NULL)
5116 return(-1);
5117 if (prefix == NULL)
5118 return(-1);
5119 if (prefix[0] == 0)
5120 return(-1);
5121
5122 if (ctxt->nsHash == NULL)
5123 ctxt->nsHash = xmlHashCreate(10);
5124 if (ctxt->nsHash == NULL)
5125 return(-1);
5126 if (ns_uri == NULL)
5127 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5128 xmlHashDefaultDeallocator));
5129 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5130 xmlHashDefaultDeallocator));
5131 }
5132
5133 /**
5134 * xmlXPathNsLookup:
5135 * @ctxt: the XPath context
5136 * @prefix: the namespace prefix value
5137 *
5138 * Search in the namespace declaration array of the context for the given
5139 * namespace name associated to the given prefix
5140 *
5141 * Returns the value or NULL if not found
5142 */
5143 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5144 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5145 if (ctxt == NULL)
5146 return(NULL);
5147 if (prefix == NULL)
5148 return(NULL);
5149
5150 #ifdef XML_XML_NAMESPACE
5151 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5152 return(XML_XML_NAMESPACE);
5153 #endif
5154
5155 if (ctxt->namespaces != NULL) {
5156 int i;
5157
5158 for (i = 0;i < ctxt->nsNr;i++) {
5159 if ((ctxt->namespaces[i] != NULL) &&
5160 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5161 return(ctxt->namespaces[i]->href);
5162 }
5163 }
5164
5165 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5166 }
5167
5168 /**
5169 * xmlXPathRegisteredNsCleanup:
5170 * @ctxt: the XPath context
5171 *
5172 * Cleanup the XPath context data associated to registered variables
5173 */
5174 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5175 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5176 if (ctxt == NULL)
5177 return;
5178
5179 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5180 ctxt->nsHash = NULL;
5181 }
5182
5183 /************************************************************************
5184 * *
5185 * Routines to handle Values *
5186 * *
5187 ************************************************************************/
5188
5189 /* Allocations are terrible, one needs to optimize all this !!! */
5190
5191 /**
5192 * xmlXPathNewFloat:
5193 * @val: the double value
5194 *
5195 * Create a new xmlXPathObjectPtr of type double and of value @val
5196 *
5197 * Returns the newly created object.
5198 */
5199 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5200 xmlXPathNewFloat(double val) {
5201 xmlXPathObjectPtr ret;
5202
5203 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5204 if (ret == NULL) {
5205 xmlXPathErrMemory(NULL, "creating float object\n");
5206 return(NULL);
5207 }
5208 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5209 ret->type = XPATH_NUMBER;
5210 ret->floatval = val;
5211 #ifdef XP_DEBUG_OBJ_USAGE
5212 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5213 #endif
5214 return(ret);
5215 }
5216
5217 /**
5218 * xmlXPathNewBoolean:
5219 * @val: the boolean value
5220 *
5221 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5222 *
5223 * Returns the newly created object.
5224 */
5225 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5226 xmlXPathNewBoolean(int val) {
5227 xmlXPathObjectPtr ret;
5228
5229 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5230 if (ret == NULL) {
5231 xmlXPathErrMemory(NULL, "creating boolean object\n");
5232 return(NULL);
5233 }
5234 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5235 ret->type = XPATH_BOOLEAN;
5236 ret->boolval = (val != 0);
5237 #ifdef XP_DEBUG_OBJ_USAGE
5238 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5239 #endif
5240 return(ret);
5241 }
5242
5243 /**
5244 * xmlXPathNewString:
5245 * @val: the xmlChar * value
5246 *
5247 * Create a new xmlXPathObjectPtr of type string and of value @val
5248 *
5249 * Returns the newly created object.
5250 */
5251 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5252 xmlXPathNewString(const xmlChar *val) {
5253 xmlXPathObjectPtr ret;
5254
5255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5256 if (ret == NULL) {
5257 xmlXPathErrMemory(NULL, "creating string object\n");
5258 return(NULL);
5259 }
5260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5261 ret->type = XPATH_STRING;
5262 if (val != NULL)
5263 ret->stringval = xmlStrdup(val);
5264 else
5265 ret->stringval = xmlStrdup((const xmlChar *)"");
5266 #ifdef XP_DEBUG_OBJ_USAGE
5267 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5268 #endif
5269 return(ret);
5270 }
5271
5272 /**
5273 * xmlXPathWrapString:
5274 * @val: the xmlChar * value
5275 *
5276 * Wraps the @val string into an XPath object.
5277 *
5278 * Returns the newly created object.
5279 */
5280 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5281 xmlXPathWrapString (xmlChar *val) {
5282 xmlXPathObjectPtr ret;
5283
5284 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5285 if (ret == NULL) {
5286 xmlXPathErrMemory(NULL, "creating string object\n");
5287 return(NULL);
5288 }
5289 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5290 ret->type = XPATH_STRING;
5291 ret->stringval = val;
5292 #ifdef XP_DEBUG_OBJ_USAGE
5293 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5294 #endif
5295 return(ret);
5296 }
5297
5298 /**
5299 * xmlXPathNewCString:
5300 * @val: the char * value
5301 *
5302 * Create a new xmlXPathObjectPtr of type string and of value @val
5303 *
5304 * Returns the newly created object.
5305 */
5306 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5307 xmlXPathNewCString(const char *val) {
5308 xmlXPathObjectPtr ret;
5309
5310 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5311 if (ret == NULL) {
5312 xmlXPathErrMemory(NULL, "creating string object\n");
5313 return(NULL);
5314 }
5315 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5316 ret->type = XPATH_STRING;
5317 ret->stringval = xmlStrdup(BAD_CAST val);
5318 #ifdef XP_DEBUG_OBJ_USAGE
5319 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5320 #endif
5321 return(ret);
5322 }
5323
5324 /**
5325 * xmlXPathWrapCString:
5326 * @val: the char * value
5327 *
5328 * Wraps a string into an XPath object.
5329 *
5330 * Returns the newly created object.
5331 */
5332 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5333 xmlXPathWrapCString (char * val) {
5334 return(xmlXPathWrapString((xmlChar *)(val)));
5335 }
5336
5337 /**
5338 * xmlXPathWrapExternal:
5339 * @val: the user data
5340 *
5341 * Wraps the @val data into an XPath object.
5342 *
5343 * Returns the newly created object.
5344 */
5345 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5346 xmlXPathWrapExternal (void *val) {
5347 xmlXPathObjectPtr ret;
5348
5349 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5350 if (ret == NULL) {
5351 xmlXPathErrMemory(NULL, "creating user object\n");
5352 return(NULL);
5353 }
5354 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5355 ret->type = XPATH_USERS;
5356 ret->user = val;
5357 #ifdef XP_DEBUG_OBJ_USAGE
5358 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5359 #endif
5360 return(ret);
5361 }
5362
5363 /**
5364 * xmlXPathObjectCopy:
5365 * @val: the original object
5366 *
5367 * allocate a new copy of a given object
5368 *
5369 * Returns the newly created object.
5370 */
5371 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5372 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5373 xmlXPathObjectPtr ret;
5374
5375 if (val == NULL)
5376 return(NULL);
5377
5378 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5379 if (ret == NULL) {
5380 xmlXPathErrMemory(NULL, "copying object\n");
5381 return(NULL);
5382 }
5383 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5384 #ifdef XP_DEBUG_OBJ_USAGE
5385 xmlXPathDebugObjUsageRequested(NULL, val->type);
5386 #endif
5387 switch (val->type) {
5388 case XPATH_BOOLEAN:
5389 case XPATH_NUMBER:
5390 case XPATH_POINT:
5391 case XPATH_RANGE:
5392 break;
5393 case XPATH_STRING:
5394 ret->stringval = xmlStrdup(val->stringval);
5395 break;
5396 case XPATH_XSLT_TREE:
5397 #if 0
5398 /*
5399 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5400 this previous handling is no longer correct, and can cause some serious
5401 problems (ref. bug 145547)
5402 */
5403 if ((val->nodesetval != NULL) &&
5404 (val->nodesetval->nodeTab != NULL)) {
5405 xmlNodePtr cur, tmp;
5406 xmlDocPtr top;
5407
5408 ret->boolval = 1;
5409 top = xmlNewDoc(NULL);
5410 top->name = (char *)
5411 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5412 ret->user = top;
5413 if (top != NULL) {
5414 top->doc = top;
5415 cur = val->nodesetval->nodeTab[0]->children;
5416 while (cur != NULL) {
5417 tmp = xmlDocCopyNode(cur, top, 1);
5418 xmlAddChild((xmlNodePtr) top, tmp);
5419 cur = cur->next;
5420 }
5421 }
5422
5423 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5424 } else
5425 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5426 /* Deallocate the copied tree value */
5427 break;
5428 #endif
5429 case XPATH_NODESET:
5430 /* TODO: Check memory error. */
5431 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5432 /* Do not deallocate the copied tree value */
5433 ret->boolval = 0;
5434 break;
5435 case XPATH_LOCATIONSET:
5436 #ifdef LIBXML_XPTR_ENABLED
5437 {
5438 xmlLocationSetPtr loc = val->user;
5439 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5440 break;
5441 }
5442 #endif
5443 case XPATH_USERS:
5444 ret->user = val->user;
5445 break;
5446 case XPATH_UNDEFINED:
5447 xmlGenericError(xmlGenericErrorContext,
5448 "xmlXPathObjectCopy: unsupported type %d\n",
5449 val->type);
5450 break;
5451 }
5452 return(ret);
5453 }
5454
5455 /**
5456 * xmlXPathFreeObject:
5457 * @obj: the object to free
5458 *
5459 * Free up an xmlXPathObjectPtr object.
5460 */
5461 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5462 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5463 if (obj == NULL) return;
5464 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5465 if (obj->boolval) {
5466 #if 0
5467 if (obj->user != NULL) {
5468 xmlXPathFreeNodeSet(obj->nodesetval);
5469 xmlFreeNodeList((xmlNodePtr) obj->user);
5470 } else
5471 #endif
5472 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5473 if (obj->nodesetval != NULL)
5474 xmlXPathFreeValueTree(obj->nodesetval);
5475 } else {
5476 if (obj->nodesetval != NULL)
5477 xmlXPathFreeNodeSet(obj->nodesetval);
5478 }
5479 #ifdef LIBXML_XPTR_ENABLED
5480 } else if (obj->type == XPATH_LOCATIONSET) {
5481 if (obj->user != NULL)
5482 xmlXPtrFreeLocationSet(obj->user);
5483 #endif
5484 } else if (obj->type == XPATH_STRING) {
5485 if (obj->stringval != NULL)
5486 xmlFree(obj->stringval);
5487 }
5488 #ifdef XP_DEBUG_OBJ_USAGE
5489 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5490 #endif
5491 xmlFree(obj);
5492 }
5493
5494 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5495 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5496 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5497 }
5498
5499 /**
5500 * xmlXPathReleaseObject:
5501 * @obj: the xmlXPathObjectPtr to free or to cache
5502 *
5503 * Depending on the state of the cache this frees the given
5504 * XPath object or stores it in the cache.
5505 */
5506 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5507 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5508 {
5509 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5510 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5511 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5512
5513 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5514
5515 if (obj == NULL)
5516 return;
5517 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5518 xmlXPathFreeObject(obj);
5519 } else {
5520 xmlXPathContextCachePtr cache =
5521 (xmlXPathContextCachePtr) ctxt->cache;
5522
5523 switch (obj->type) {
5524 case XPATH_NODESET:
5525 case XPATH_XSLT_TREE:
5526 if (obj->nodesetval != NULL) {
5527 if (obj->boolval) {
5528 /*
5529 * It looks like the @boolval is used for
5530 * evaluation if this an XSLT Result Tree Fragment.
5531 * TODO: Check if this assumption is correct.
5532 */
5533 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5534 xmlXPathFreeValueTree(obj->nodesetval);
5535 obj->nodesetval = NULL;
5536 } else if ((obj->nodesetval->nodeMax <= 40) &&
5537 (XP_CACHE_WANTS(cache->nodesetObjs,
5538 cache->maxNodeset)))
5539 {
5540 XP_CACHE_ADD(cache->nodesetObjs, obj);
5541 goto obj_cached;
5542 } else {
5543 xmlXPathFreeNodeSet(obj->nodesetval);
5544 obj->nodesetval = NULL;
5545 }
5546 }
5547 break;
5548 case XPATH_STRING:
5549 if (obj->stringval != NULL)
5550 xmlFree(obj->stringval);
5551
5552 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5553 XP_CACHE_ADD(cache->stringObjs, obj);
5554 goto obj_cached;
5555 }
5556 break;
5557 case XPATH_BOOLEAN:
5558 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5559 XP_CACHE_ADD(cache->booleanObjs, obj);
5560 goto obj_cached;
5561 }
5562 break;
5563 case XPATH_NUMBER:
5564 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5565 XP_CACHE_ADD(cache->numberObjs, obj);
5566 goto obj_cached;
5567 }
5568 break;
5569 #ifdef LIBXML_XPTR_ENABLED
5570 case XPATH_LOCATIONSET:
5571 if (obj->user != NULL) {
5572 xmlXPtrFreeLocationSet(obj->user);
5573 }
5574 goto free_obj;
5575 #endif
5576 default:
5577 goto free_obj;
5578 }
5579
5580 /*
5581 * Fallback to adding to the misc-objects slot.
5582 */
5583 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5584 XP_CACHE_ADD(cache->miscObjs, obj);
5585 } else
5586 goto free_obj;
5587
5588 obj_cached:
5589
5590 #ifdef XP_DEBUG_OBJ_USAGE
5591 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5592 #endif
5593
5594 if (obj->nodesetval != NULL) {
5595 xmlNodeSetPtr tmpset = obj->nodesetval;
5596
5597 /*
5598 * TODO: Due to those nasty ns-nodes, we need to traverse
5599 * the list and free the ns-nodes.
5600 * URGENT TODO: Check if it's actually slowing things down.
5601 * Maybe we shouldn't try to preserve the list.
5602 */
5603 if (tmpset->nodeNr > 1) {
5604 int i;
5605 xmlNodePtr node;
5606
5607 for (i = 0; i < tmpset->nodeNr; i++) {
5608 node = tmpset->nodeTab[i];
5609 if ((node != NULL) &&
5610 (node->type == XML_NAMESPACE_DECL))
5611 {
5612 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5613 }
5614 }
5615 } else if (tmpset->nodeNr == 1) {
5616 if ((tmpset->nodeTab[0] != NULL) &&
5617 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5618 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5619 }
5620 tmpset->nodeNr = 0;
5621 memset(obj, 0, sizeof(xmlXPathObject));
5622 obj->nodesetval = tmpset;
5623 } else
5624 memset(obj, 0, sizeof(xmlXPathObject));
5625
5626 return;
5627
5628 free_obj:
5629 /*
5630 * Cache is full; free the object.
5631 */
5632 if (obj->nodesetval != NULL)
5633 xmlXPathFreeNodeSet(obj->nodesetval);
5634 #ifdef XP_DEBUG_OBJ_USAGE
5635 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5636 #endif
5637 xmlFree(obj);
5638 }
5639 return;
5640 }
5641
5642
5643 /************************************************************************
5644 * *
5645 * Type Casting Routines *
5646 * *
5647 ************************************************************************/
5648
5649 /**
5650 * xmlXPathCastBooleanToString:
5651 * @val: a boolean
5652 *
5653 * Converts a boolean to its string value.
5654 *
5655 * Returns a newly allocated string.
5656 */
5657 xmlChar *
xmlXPathCastBooleanToString(int val)5658 xmlXPathCastBooleanToString (int val) {
5659 xmlChar *ret;
5660 if (val)
5661 ret = xmlStrdup((const xmlChar *) "true");
5662 else
5663 ret = xmlStrdup((const xmlChar *) "false");
5664 return(ret);
5665 }
5666
5667 /**
5668 * xmlXPathCastNumberToString:
5669 * @val: a number
5670 *
5671 * Converts a number to its string value.
5672 *
5673 * Returns a newly allocated string.
5674 */
5675 xmlChar *
xmlXPathCastNumberToString(double val)5676 xmlXPathCastNumberToString (double val) {
5677 xmlChar *ret;
5678 switch (xmlXPathIsInf(val)) {
5679 case 1:
5680 ret = xmlStrdup((const xmlChar *) "Infinity");
5681 break;
5682 case -1:
5683 ret = xmlStrdup((const xmlChar *) "-Infinity");
5684 break;
5685 default:
5686 if (xmlXPathIsNaN(val)) {
5687 ret = xmlStrdup((const xmlChar *) "NaN");
5688 } else if (val == 0) {
5689 /* Omit sign for negative zero. */
5690 ret = xmlStrdup((const xmlChar *) "0");
5691 } else {
5692 /* could be improved */
5693 char buf[100];
5694 xmlXPathFormatNumber(val, buf, 99);
5695 buf[99] = 0;
5696 ret = xmlStrdup((const xmlChar *) buf);
5697 }
5698 }
5699 return(ret);
5700 }
5701
5702 /**
5703 * xmlXPathCastNodeToString:
5704 * @node: a node
5705 *
5706 * Converts a node to its string value.
5707 *
5708 * Returns a newly allocated string.
5709 */
5710 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5711 xmlXPathCastNodeToString (xmlNodePtr node) {
5712 xmlChar *ret;
5713 if ((ret = xmlNodeGetContent(node)) == NULL)
5714 ret = xmlStrdup((const xmlChar *) "");
5715 return(ret);
5716 }
5717
5718 /**
5719 * xmlXPathCastNodeSetToString:
5720 * @ns: a node-set
5721 *
5722 * Converts a node-set to its string value.
5723 *
5724 * Returns a newly allocated string.
5725 */
5726 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5727 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5728 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5729 return(xmlStrdup((const xmlChar *) ""));
5730
5731 if (ns->nodeNr > 1)
5732 xmlXPathNodeSetSort(ns);
5733 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5734 }
5735
5736 /**
5737 * xmlXPathCastToString:
5738 * @val: an XPath object
5739 *
5740 * Converts an existing object to its string() equivalent
5741 *
5742 * Returns the allocated string value of the object, NULL in case of error.
5743 * It's up to the caller to free the string memory with xmlFree().
5744 */
5745 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5746 xmlXPathCastToString(xmlXPathObjectPtr val) {
5747 xmlChar *ret = NULL;
5748
5749 if (val == NULL)
5750 return(xmlStrdup((const xmlChar *) ""));
5751 switch (val->type) {
5752 case XPATH_UNDEFINED:
5753 #ifdef DEBUG_EXPR
5754 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5755 #endif
5756 ret = xmlStrdup((const xmlChar *) "");
5757 break;
5758 case XPATH_NODESET:
5759 case XPATH_XSLT_TREE:
5760 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5761 break;
5762 case XPATH_STRING:
5763 return(xmlStrdup(val->stringval));
5764 case XPATH_BOOLEAN:
5765 ret = xmlXPathCastBooleanToString(val->boolval);
5766 break;
5767 case XPATH_NUMBER: {
5768 ret = xmlXPathCastNumberToString(val->floatval);
5769 break;
5770 }
5771 case XPATH_USERS:
5772 case XPATH_POINT:
5773 case XPATH_RANGE:
5774 case XPATH_LOCATIONSET:
5775 TODO
5776 ret = xmlStrdup((const xmlChar *) "");
5777 break;
5778 }
5779 return(ret);
5780 }
5781
5782 /**
5783 * xmlXPathConvertString:
5784 * @val: an XPath object
5785 *
5786 * Converts an existing object to its string() equivalent
5787 *
5788 * Returns the new object, the old one is freed (or the operation
5789 * is done directly on @val)
5790 */
5791 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5792 xmlXPathConvertString(xmlXPathObjectPtr val) {
5793 xmlChar *res = NULL;
5794
5795 if (val == NULL)
5796 return(xmlXPathNewCString(""));
5797
5798 switch (val->type) {
5799 case XPATH_UNDEFINED:
5800 #ifdef DEBUG_EXPR
5801 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5802 #endif
5803 break;
5804 case XPATH_NODESET:
5805 case XPATH_XSLT_TREE:
5806 res = xmlXPathCastNodeSetToString(val->nodesetval);
5807 break;
5808 case XPATH_STRING:
5809 return(val);
5810 case XPATH_BOOLEAN:
5811 res = xmlXPathCastBooleanToString(val->boolval);
5812 break;
5813 case XPATH_NUMBER:
5814 res = xmlXPathCastNumberToString(val->floatval);
5815 break;
5816 case XPATH_USERS:
5817 case XPATH_POINT:
5818 case XPATH_RANGE:
5819 case XPATH_LOCATIONSET:
5820 TODO;
5821 break;
5822 }
5823 xmlXPathFreeObject(val);
5824 if (res == NULL)
5825 return(xmlXPathNewCString(""));
5826 return(xmlXPathWrapString(res));
5827 }
5828
5829 /**
5830 * xmlXPathCastBooleanToNumber:
5831 * @val: a boolean
5832 *
5833 * Converts a boolean to its number value
5834 *
5835 * Returns the number value
5836 */
5837 double
xmlXPathCastBooleanToNumber(int val)5838 xmlXPathCastBooleanToNumber(int val) {
5839 if (val)
5840 return(1.0);
5841 return(0.0);
5842 }
5843
5844 /**
5845 * xmlXPathCastStringToNumber:
5846 * @val: a string
5847 *
5848 * Converts a string to its number value
5849 *
5850 * Returns the number value
5851 */
5852 double
xmlXPathCastStringToNumber(const xmlChar * val)5853 xmlXPathCastStringToNumber(const xmlChar * val) {
5854 return(xmlXPathStringEvalNumber(val));
5855 }
5856
5857 /**
5858 * xmlXPathCastNodeToNumber:
5859 * @node: a node
5860 *
5861 * Converts a node to its number value
5862 *
5863 * Returns the number value
5864 */
5865 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5866 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5867 xmlChar *strval;
5868 double ret;
5869
5870 if (node == NULL)
5871 return(xmlXPathNAN);
5872 strval = xmlXPathCastNodeToString(node);
5873 if (strval == NULL)
5874 return(xmlXPathNAN);
5875 ret = xmlXPathCastStringToNumber(strval);
5876 xmlFree(strval);
5877
5878 return(ret);
5879 }
5880
5881 /**
5882 * xmlXPathCastNodeSetToNumber:
5883 * @ns: a node-set
5884 *
5885 * Converts a node-set to its number value
5886 *
5887 * Returns the number value
5888 */
5889 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5890 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5891 xmlChar *str;
5892 double ret;
5893
5894 if (ns == NULL)
5895 return(xmlXPathNAN);
5896 str = xmlXPathCastNodeSetToString(ns);
5897 ret = xmlXPathCastStringToNumber(str);
5898 xmlFree(str);
5899 return(ret);
5900 }
5901
5902 /**
5903 * xmlXPathCastToNumber:
5904 * @val: an XPath object
5905 *
5906 * Converts an XPath object to its number value
5907 *
5908 * Returns the number value
5909 */
5910 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5911 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5912 double ret = 0.0;
5913
5914 if (val == NULL)
5915 return(xmlXPathNAN);
5916 switch (val->type) {
5917 case XPATH_UNDEFINED:
5918 #ifdef DEBUG_EXPR
5919 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5920 #endif
5921 ret = xmlXPathNAN;
5922 break;
5923 case XPATH_NODESET:
5924 case XPATH_XSLT_TREE:
5925 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5926 break;
5927 case XPATH_STRING:
5928 ret = xmlXPathCastStringToNumber(val->stringval);
5929 break;
5930 case XPATH_NUMBER:
5931 ret = val->floatval;
5932 break;
5933 case XPATH_BOOLEAN:
5934 ret = xmlXPathCastBooleanToNumber(val->boolval);
5935 break;
5936 case XPATH_USERS:
5937 case XPATH_POINT:
5938 case XPATH_RANGE:
5939 case XPATH_LOCATIONSET:
5940 TODO;
5941 ret = xmlXPathNAN;
5942 break;
5943 }
5944 return(ret);
5945 }
5946
5947 /**
5948 * xmlXPathConvertNumber:
5949 * @val: an XPath object
5950 *
5951 * Converts an existing object to its number() equivalent
5952 *
5953 * Returns the new object, the old one is freed (or the operation
5954 * is done directly on @val)
5955 */
5956 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)5957 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5958 xmlXPathObjectPtr ret;
5959
5960 if (val == NULL)
5961 return(xmlXPathNewFloat(0.0));
5962 if (val->type == XPATH_NUMBER)
5963 return(val);
5964 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5965 xmlXPathFreeObject(val);
5966 return(ret);
5967 }
5968
5969 /**
5970 * xmlXPathCastNumberToBoolean:
5971 * @val: a number
5972 *
5973 * Converts a number to its boolean value
5974 *
5975 * Returns the boolean value
5976 */
5977 int
xmlXPathCastNumberToBoolean(double val)5978 xmlXPathCastNumberToBoolean (double val) {
5979 if (xmlXPathIsNaN(val) || (val == 0.0))
5980 return(0);
5981 return(1);
5982 }
5983
5984 /**
5985 * xmlXPathCastStringToBoolean:
5986 * @val: a string
5987 *
5988 * Converts a string to its boolean value
5989 *
5990 * Returns the boolean value
5991 */
5992 int
xmlXPathCastStringToBoolean(const xmlChar * val)5993 xmlXPathCastStringToBoolean (const xmlChar *val) {
5994 if ((val == NULL) || (xmlStrlen(val) == 0))
5995 return(0);
5996 return(1);
5997 }
5998
5999 /**
6000 * xmlXPathCastNodeSetToBoolean:
6001 * @ns: a node-set
6002 *
6003 * Converts a node-set to its boolean value
6004 *
6005 * Returns the boolean value
6006 */
6007 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6008 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6009 if ((ns == NULL) || (ns->nodeNr == 0))
6010 return(0);
6011 return(1);
6012 }
6013
6014 /**
6015 * xmlXPathCastToBoolean:
6016 * @val: an XPath object
6017 *
6018 * Converts an XPath object to its boolean value
6019 *
6020 * Returns the boolean value
6021 */
6022 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6023 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6024 int ret = 0;
6025
6026 if (val == NULL)
6027 return(0);
6028 switch (val->type) {
6029 case XPATH_UNDEFINED:
6030 #ifdef DEBUG_EXPR
6031 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6032 #endif
6033 ret = 0;
6034 break;
6035 case XPATH_NODESET:
6036 case XPATH_XSLT_TREE:
6037 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6038 break;
6039 case XPATH_STRING:
6040 ret = xmlXPathCastStringToBoolean(val->stringval);
6041 break;
6042 case XPATH_NUMBER:
6043 ret = xmlXPathCastNumberToBoolean(val->floatval);
6044 break;
6045 case XPATH_BOOLEAN:
6046 ret = val->boolval;
6047 break;
6048 case XPATH_USERS:
6049 case XPATH_POINT:
6050 case XPATH_RANGE:
6051 case XPATH_LOCATIONSET:
6052 TODO;
6053 ret = 0;
6054 break;
6055 }
6056 return(ret);
6057 }
6058
6059
6060 /**
6061 * xmlXPathConvertBoolean:
6062 * @val: an XPath object
6063 *
6064 * Converts an existing object to its boolean() equivalent
6065 *
6066 * Returns the new object, the old one is freed (or the operation
6067 * is done directly on @val)
6068 */
6069 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6070 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6071 xmlXPathObjectPtr ret;
6072
6073 if (val == NULL)
6074 return(xmlXPathNewBoolean(0));
6075 if (val->type == XPATH_BOOLEAN)
6076 return(val);
6077 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6078 xmlXPathFreeObject(val);
6079 return(ret);
6080 }
6081
6082 /************************************************************************
6083 * *
6084 * Routines to handle XPath contexts *
6085 * *
6086 ************************************************************************/
6087
6088 /**
6089 * xmlXPathNewContext:
6090 * @doc: the XML document
6091 *
6092 * Create a new xmlXPathContext
6093 *
6094 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6095 */
6096 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6097 xmlXPathNewContext(xmlDocPtr doc) {
6098 xmlXPathContextPtr ret;
6099
6100 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6101 if (ret == NULL) {
6102 xmlXPathErrMemory(NULL, "creating context\n");
6103 return(NULL);
6104 }
6105 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6106 ret->doc = doc;
6107 ret->node = NULL;
6108
6109 ret->varHash = NULL;
6110
6111 ret->nb_types = 0;
6112 ret->max_types = 0;
6113 ret->types = NULL;
6114
6115 ret->funcHash = xmlHashCreate(0);
6116
6117 ret->nb_axis = 0;
6118 ret->max_axis = 0;
6119 ret->axis = NULL;
6120
6121 ret->nsHash = NULL;
6122 ret->user = NULL;
6123
6124 ret->contextSize = -1;
6125 ret->proximityPosition = -1;
6126
6127 #ifdef XP_DEFAULT_CACHE_ON
6128 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6129 xmlXPathFreeContext(ret);
6130 return(NULL);
6131 }
6132 #endif
6133
6134 xmlXPathRegisterAllFunctions(ret);
6135
6136 return(ret);
6137 }
6138
6139 /**
6140 * xmlXPathFreeContext:
6141 * @ctxt: the context to free
6142 *
6143 * Free up an xmlXPathContext
6144 */
6145 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6146 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6147 if (ctxt == NULL) return;
6148
6149 if (ctxt->cache != NULL)
6150 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6151 xmlXPathRegisteredNsCleanup(ctxt);
6152 xmlXPathRegisteredFuncsCleanup(ctxt);
6153 xmlXPathRegisteredVariablesCleanup(ctxt);
6154 xmlResetError(&ctxt->lastError);
6155 xmlFree(ctxt);
6156 }
6157
6158 /************************************************************************
6159 * *
6160 * Routines to handle XPath parser contexts *
6161 * *
6162 ************************************************************************/
6163
6164 #define CHECK_CTXT(ctxt) \
6165 if (ctxt == NULL) { \
6166 __xmlRaiseError(NULL, NULL, NULL, \
6167 NULL, NULL, XML_FROM_XPATH, \
6168 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6169 __FILE__, __LINE__, \
6170 NULL, NULL, NULL, 0, 0, \
6171 "NULL context pointer\n"); \
6172 return(NULL); \
6173 } \
6174
6175 #define CHECK_CTXT_NEG(ctxt) \
6176 if (ctxt == NULL) { \
6177 __xmlRaiseError(NULL, NULL, NULL, \
6178 NULL, NULL, XML_FROM_XPATH, \
6179 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6180 __FILE__, __LINE__, \
6181 NULL, NULL, NULL, 0, 0, \
6182 "NULL context pointer\n"); \
6183 return(-1); \
6184 } \
6185
6186
6187 #define CHECK_CONTEXT(ctxt) \
6188 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6189 (ctxt->doc->children == NULL)) { \
6190 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6191 return(NULL); \
6192 }
6193
6194
6195 /**
6196 * xmlXPathNewParserContext:
6197 * @str: the XPath expression
6198 * @ctxt: the XPath context
6199 *
6200 * Create a new xmlXPathParserContext
6201 *
6202 * Returns the xmlXPathParserContext just allocated.
6203 */
6204 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6205 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6206 xmlXPathParserContextPtr ret;
6207
6208 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6209 if (ret == NULL) {
6210 xmlXPathErrMemory(ctxt, "creating parser context\n");
6211 return(NULL);
6212 }
6213 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6214 ret->cur = ret->base = str;
6215 ret->context = ctxt;
6216
6217 ret->comp = xmlXPathNewCompExpr();
6218 if (ret->comp == NULL) {
6219 xmlFree(ret->valueTab);
6220 xmlFree(ret);
6221 return(NULL);
6222 }
6223 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6224 ret->comp->dict = ctxt->dict;
6225 xmlDictReference(ret->comp->dict);
6226 }
6227
6228 return(ret);
6229 }
6230
6231 /**
6232 * xmlXPathCompParserContext:
6233 * @comp: the XPath compiled expression
6234 * @ctxt: the XPath context
6235 *
6236 * Create a new xmlXPathParserContext when processing a compiled expression
6237 *
6238 * Returns the xmlXPathParserContext just allocated.
6239 */
6240 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6241 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6242 xmlXPathParserContextPtr ret;
6243
6244 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245 if (ret == NULL) {
6246 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6247 return(NULL);
6248 }
6249 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250
6251 /* Allocate the value stack */
6252 ret->valueTab = (xmlXPathObjectPtr *)
6253 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6254 if (ret->valueTab == NULL) {
6255 xmlFree(ret);
6256 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6257 return(NULL);
6258 }
6259 ret->valueNr = 0;
6260 ret->valueMax = 10;
6261 ret->value = NULL;
6262 ret->valueFrame = 0;
6263
6264 ret->context = ctxt;
6265 ret->comp = comp;
6266
6267 return(ret);
6268 }
6269
6270 /**
6271 * xmlXPathFreeParserContext:
6272 * @ctxt: the context to free
6273 *
6274 * Free up an xmlXPathParserContext
6275 */
6276 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6277 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6278 int i;
6279
6280 if (ctxt->valueTab != NULL) {
6281 for (i = 0; i < ctxt->valueNr; i++) {
6282 if (ctxt->context)
6283 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6284 else
6285 xmlXPathFreeObject(ctxt->valueTab[i]);
6286 }
6287 xmlFree(ctxt->valueTab);
6288 }
6289 if (ctxt->comp != NULL) {
6290 #ifdef XPATH_STREAMING
6291 if (ctxt->comp->stream != NULL) {
6292 xmlFreePatternList(ctxt->comp->stream);
6293 ctxt->comp->stream = NULL;
6294 }
6295 #endif
6296 xmlXPathFreeCompExpr(ctxt->comp);
6297 }
6298 xmlFree(ctxt);
6299 }
6300
6301 /************************************************************************
6302 * *
6303 * The implicit core function library *
6304 * *
6305 ************************************************************************/
6306
6307 /**
6308 * xmlXPathNodeValHash:
6309 * @node: a node pointer
6310 *
6311 * Function computing the beginning of the string value of the node,
6312 * used to speed up comparisons
6313 *
6314 * Returns an int usable as a hash
6315 */
6316 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6317 xmlXPathNodeValHash(xmlNodePtr node) {
6318 int len = 2;
6319 const xmlChar * string = NULL;
6320 xmlNodePtr tmp = NULL;
6321 unsigned int ret = 0;
6322
6323 if (node == NULL)
6324 return(0);
6325
6326 if (node->type == XML_DOCUMENT_NODE) {
6327 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6328 if (tmp == NULL)
6329 node = node->children;
6330 else
6331 node = tmp;
6332
6333 if (node == NULL)
6334 return(0);
6335 }
6336
6337 switch (node->type) {
6338 case XML_COMMENT_NODE:
6339 case XML_PI_NODE:
6340 case XML_CDATA_SECTION_NODE:
6341 case XML_TEXT_NODE:
6342 string = node->content;
6343 if (string == NULL)
6344 return(0);
6345 if (string[0] == 0)
6346 return(0);
6347 return(((unsigned int) string[0]) +
6348 (((unsigned int) string[1]) << 8));
6349 case XML_NAMESPACE_DECL:
6350 string = ((xmlNsPtr)node)->href;
6351 if (string == NULL)
6352 return(0);
6353 if (string[0] == 0)
6354 return(0);
6355 return(((unsigned int) string[0]) +
6356 (((unsigned int) string[1]) << 8));
6357 case XML_ATTRIBUTE_NODE:
6358 tmp = ((xmlAttrPtr) node)->children;
6359 break;
6360 case XML_ELEMENT_NODE:
6361 tmp = node->children;
6362 break;
6363 default:
6364 return(0);
6365 }
6366 while (tmp != NULL) {
6367 switch (tmp->type) {
6368 case XML_CDATA_SECTION_NODE:
6369 case XML_TEXT_NODE:
6370 string = tmp->content;
6371 break;
6372 default:
6373 string = NULL;
6374 break;
6375 }
6376 if ((string != NULL) && (string[0] != 0)) {
6377 if (len == 1) {
6378 return(ret + (((unsigned int) string[0]) << 8));
6379 }
6380 if (string[1] == 0) {
6381 len = 1;
6382 ret = (unsigned int) string[0];
6383 } else {
6384 return(((unsigned int) string[0]) +
6385 (((unsigned int) string[1]) << 8));
6386 }
6387 }
6388 /*
6389 * Skip to next node
6390 */
6391 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6392 if (tmp->children->type != XML_ENTITY_DECL) {
6393 tmp = tmp->children;
6394 continue;
6395 }
6396 }
6397 if (tmp == node)
6398 break;
6399
6400 if (tmp->next != NULL) {
6401 tmp = tmp->next;
6402 continue;
6403 }
6404
6405 do {
6406 tmp = tmp->parent;
6407 if (tmp == NULL)
6408 break;
6409 if (tmp == node) {
6410 tmp = NULL;
6411 break;
6412 }
6413 if (tmp->next != NULL) {
6414 tmp = tmp->next;
6415 break;
6416 }
6417 } while (tmp != NULL);
6418 }
6419 return(ret);
6420 }
6421
6422 /**
6423 * xmlXPathStringHash:
6424 * @string: a string
6425 *
6426 * Function computing the beginning of the string value of the node,
6427 * used to speed up comparisons
6428 *
6429 * Returns an int usable as a hash
6430 */
6431 static unsigned int
xmlXPathStringHash(const xmlChar * string)6432 xmlXPathStringHash(const xmlChar * string) {
6433 if (string == NULL)
6434 return((unsigned int) 0);
6435 if (string[0] == 0)
6436 return(0);
6437 return(((unsigned int) string[0]) +
6438 (((unsigned int) string[1]) << 8));
6439 }
6440
6441 /**
6442 * xmlXPathCompareNodeSetFloat:
6443 * @ctxt: the XPath Parser context
6444 * @inf: less than (1) or greater than (0)
6445 * @strict: is the comparison strict
6446 * @arg: the node set
6447 * @f: the value
6448 *
6449 * Implement the compare operation between a nodeset and a number
6450 * @ns < @val (1, 1, ...
6451 * @ns <= @val (1, 0, ...
6452 * @ns > @val (0, 1, ...
6453 * @ns >= @val (0, 0, ...
6454 *
6455 * If one object to be compared is a node-set and the other is a number,
6456 * then the comparison will be true if and only if there is a node in the
6457 * node-set such that the result of performing the comparison on the number
6458 * to be compared and on the result of converting the string-value of that
6459 * node to a number using the number function is true.
6460 *
6461 * Returns 0 or 1 depending on the results of the test.
6462 */
6463 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6464 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6465 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6466 int i, ret = 0;
6467 xmlNodeSetPtr ns;
6468 xmlChar *str2;
6469
6470 if ((f == NULL) || (arg == NULL) ||
6471 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6472 xmlXPathReleaseObject(ctxt->context, arg);
6473 xmlXPathReleaseObject(ctxt->context, f);
6474 return(0);
6475 }
6476 ns = arg->nodesetval;
6477 if (ns != NULL) {
6478 for (i = 0;i < ns->nodeNr;i++) {
6479 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6480 if (str2 != NULL) {
6481 valuePush(ctxt,
6482 xmlXPathCacheNewString(ctxt->context, str2));
6483 xmlFree(str2);
6484 xmlXPathNumberFunction(ctxt, 1);
6485 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6486 ret = xmlXPathCompareValues(ctxt, inf, strict);
6487 if (ret)
6488 break;
6489 }
6490 }
6491 }
6492 xmlXPathReleaseObject(ctxt->context, arg);
6493 xmlXPathReleaseObject(ctxt->context, f);
6494 return(ret);
6495 }
6496
6497 /**
6498 * xmlXPathCompareNodeSetString:
6499 * @ctxt: the XPath Parser context
6500 * @inf: less than (1) or greater than (0)
6501 * @strict: is the comparison strict
6502 * @arg: the node set
6503 * @s: the value
6504 *
6505 * Implement the compare operation between a nodeset and a string
6506 * @ns < @val (1, 1, ...
6507 * @ns <= @val (1, 0, ...
6508 * @ns > @val (0, 1, ...
6509 * @ns >= @val (0, 0, ...
6510 *
6511 * If one object to be compared is a node-set and the other is a string,
6512 * then the comparison will be true if and only if there is a node in
6513 * the node-set such that the result of performing the comparison on the
6514 * string-value of the node and the other string is true.
6515 *
6516 * Returns 0 or 1 depending on the results of the test.
6517 */
6518 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6519 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6520 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6521 int i, ret = 0;
6522 xmlNodeSetPtr ns;
6523 xmlChar *str2;
6524
6525 if ((s == NULL) || (arg == NULL) ||
6526 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6527 xmlXPathReleaseObject(ctxt->context, arg);
6528 xmlXPathReleaseObject(ctxt->context, s);
6529 return(0);
6530 }
6531 ns = arg->nodesetval;
6532 if (ns != NULL) {
6533 for (i = 0;i < ns->nodeNr;i++) {
6534 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6535 if (str2 != NULL) {
6536 valuePush(ctxt,
6537 xmlXPathCacheNewString(ctxt->context, str2));
6538 xmlFree(str2);
6539 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6540 ret = xmlXPathCompareValues(ctxt, inf, strict);
6541 if (ret)
6542 break;
6543 }
6544 }
6545 }
6546 xmlXPathReleaseObject(ctxt->context, arg);
6547 xmlXPathReleaseObject(ctxt->context, s);
6548 return(ret);
6549 }
6550
6551 /**
6552 * xmlXPathCompareNodeSets:
6553 * @inf: less than (1) or greater than (0)
6554 * @strict: is the comparison strict
6555 * @arg1: the first node set object
6556 * @arg2: the second node set object
6557 *
6558 * Implement the compare operation on nodesets:
6559 *
6560 * If both objects to be compared are node-sets, then the comparison
6561 * will be true if and only if there is a node in the first node-set
6562 * and a node in the second node-set such that the result of performing
6563 * the comparison on the string-values of the two nodes is true.
6564 * ....
6565 * When neither object to be compared is a node-set and the operator
6566 * is <=, <, >= or >, then the objects are compared by converting both
6567 * objects to numbers and comparing the numbers according to IEEE 754.
6568 * ....
6569 * The number function converts its argument to a number as follows:
6570 * - a string that consists of optional whitespace followed by an
6571 * optional minus sign followed by a Number followed by whitespace
6572 * is converted to the IEEE 754 number that is nearest (according
6573 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6574 * represented by the string; any other string is converted to NaN
6575 *
6576 * Conclusion all nodes need to be converted first to their string value
6577 * and then the comparison must be done when possible
6578 */
6579 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6580 xmlXPathCompareNodeSets(int inf, int strict,
6581 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6582 int i, j, init = 0;
6583 double val1;
6584 double *values2;
6585 int ret = 0;
6586 xmlNodeSetPtr ns1;
6587 xmlNodeSetPtr ns2;
6588
6589 if ((arg1 == NULL) ||
6590 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6591 xmlXPathFreeObject(arg2);
6592 return(0);
6593 }
6594 if ((arg2 == NULL) ||
6595 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6596 xmlXPathFreeObject(arg1);
6597 xmlXPathFreeObject(arg2);
6598 return(0);
6599 }
6600
6601 ns1 = arg1->nodesetval;
6602 ns2 = arg2->nodesetval;
6603
6604 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6605 xmlXPathFreeObject(arg1);
6606 xmlXPathFreeObject(arg2);
6607 return(0);
6608 }
6609 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6610 xmlXPathFreeObject(arg1);
6611 xmlXPathFreeObject(arg2);
6612 return(0);
6613 }
6614
6615 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6616 if (values2 == NULL) {
6617 /* TODO: Propagate memory error. */
6618 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6619 xmlXPathFreeObject(arg1);
6620 xmlXPathFreeObject(arg2);
6621 return(0);
6622 }
6623 for (i = 0;i < ns1->nodeNr;i++) {
6624 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6625 if (xmlXPathIsNaN(val1))
6626 continue;
6627 for (j = 0;j < ns2->nodeNr;j++) {
6628 if (init == 0) {
6629 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6630 }
6631 if (xmlXPathIsNaN(values2[j]))
6632 continue;
6633 if (inf && strict)
6634 ret = (val1 < values2[j]);
6635 else if (inf && !strict)
6636 ret = (val1 <= values2[j]);
6637 else if (!inf && strict)
6638 ret = (val1 > values2[j]);
6639 else if (!inf && !strict)
6640 ret = (val1 >= values2[j]);
6641 if (ret)
6642 break;
6643 }
6644 if (ret)
6645 break;
6646 init = 1;
6647 }
6648 xmlFree(values2);
6649 xmlXPathFreeObject(arg1);
6650 xmlXPathFreeObject(arg2);
6651 return(ret);
6652 }
6653
6654 /**
6655 * xmlXPathCompareNodeSetValue:
6656 * @ctxt: the XPath Parser context
6657 * @inf: less than (1) or greater than (0)
6658 * @strict: is the comparison strict
6659 * @arg: the node set
6660 * @val: the value
6661 *
6662 * Implement the compare operation between a nodeset and a value
6663 * @ns < @val (1, 1, ...
6664 * @ns <= @val (1, 0, ...
6665 * @ns > @val (0, 1, ...
6666 * @ns >= @val (0, 0, ...
6667 *
6668 * If one object to be compared is a node-set and the other is a boolean,
6669 * then the comparison will be true if and only if the result of performing
6670 * the comparison on the boolean and on the result of converting
6671 * the node-set to a boolean using the boolean function is true.
6672 *
6673 * Returns 0 or 1 depending on the results of the test.
6674 */
6675 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6676 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6677 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6678 if ((val == NULL) || (arg == NULL) ||
6679 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6680 return(0);
6681
6682 switch(val->type) {
6683 case XPATH_NUMBER:
6684 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6685 case XPATH_NODESET:
6686 case XPATH_XSLT_TREE:
6687 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6688 case XPATH_STRING:
6689 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6690 case XPATH_BOOLEAN:
6691 valuePush(ctxt, arg);
6692 xmlXPathBooleanFunction(ctxt, 1);
6693 valuePush(ctxt, val);
6694 return(xmlXPathCompareValues(ctxt, inf, strict));
6695 default:
6696 xmlGenericError(xmlGenericErrorContext,
6697 "xmlXPathCompareNodeSetValue: Can't compare node set "
6698 "and object of type %d\n",
6699 val->type);
6700 xmlXPathReleaseObject(ctxt->context, arg);
6701 xmlXPathReleaseObject(ctxt->context, val);
6702 XP_ERROR0(XPATH_INVALID_TYPE);
6703 }
6704 return(0);
6705 }
6706
6707 /**
6708 * xmlXPathEqualNodeSetString:
6709 * @arg: the nodeset object argument
6710 * @str: the string to compare to.
6711 * @neq: flag to show whether for '=' (0) or '!=' (1)
6712 *
6713 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6714 * If one object to be compared is a node-set and the other is a string,
6715 * then the comparison will be true if and only if there is a node in
6716 * the node-set such that the result of performing the comparison on the
6717 * string-value of the node and the other string is true.
6718 *
6719 * Returns 0 or 1 depending on the results of the test.
6720 */
6721 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6722 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6723 {
6724 int i;
6725 xmlNodeSetPtr ns;
6726 xmlChar *str2;
6727 unsigned int hash;
6728
6729 if ((str == NULL) || (arg == NULL) ||
6730 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6731 return (0);
6732 ns = arg->nodesetval;
6733 /*
6734 * A NULL nodeset compared with a string is always false
6735 * (since there is no node equal, and no node not equal)
6736 */
6737 if ((ns == NULL) || (ns->nodeNr <= 0) )
6738 return (0);
6739 hash = xmlXPathStringHash(str);
6740 for (i = 0; i < ns->nodeNr; i++) {
6741 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6742 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6743 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6744 xmlFree(str2);
6745 if (neq)
6746 continue;
6747 return (1);
6748 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6749 if (neq)
6750 continue;
6751 return (1);
6752 } else if (neq) {
6753 if (str2 != NULL)
6754 xmlFree(str2);
6755 return (1);
6756 }
6757 if (str2 != NULL)
6758 xmlFree(str2);
6759 } else if (neq)
6760 return (1);
6761 }
6762 return (0);
6763 }
6764
6765 /**
6766 * xmlXPathEqualNodeSetFloat:
6767 * @arg: the nodeset object argument
6768 * @f: the float to compare to
6769 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6770 *
6771 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6772 * If one object to be compared is a node-set and the other is a number,
6773 * then the comparison will be true if and only if there is a node in
6774 * the node-set such that the result of performing the comparison on the
6775 * number to be compared and on the result of converting the string-value
6776 * of that node to a number using the number function is true.
6777 *
6778 * Returns 0 or 1 depending on the results of the test.
6779 */
6780 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6781 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6782 xmlXPathObjectPtr arg, double f, int neq) {
6783 int i, ret=0;
6784 xmlNodeSetPtr ns;
6785 xmlChar *str2;
6786 xmlXPathObjectPtr val;
6787 double v;
6788
6789 if ((arg == NULL) ||
6790 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6791 return(0);
6792
6793 ns = arg->nodesetval;
6794 if (ns != NULL) {
6795 for (i=0;i<ns->nodeNr;i++) {
6796 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6797 if (str2 != NULL) {
6798 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6799 xmlFree(str2);
6800 xmlXPathNumberFunction(ctxt, 1);
6801 val = valuePop(ctxt);
6802 v = val->floatval;
6803 xmlXPathReleaseObject(ctxt->context, val);
6804 if (!xmlXPathIsNaN(v)) {
6805 if ((!neq) && (v==f)) {
6806 ret = 1;
6807 break;
6808 } else if ((neq) && (v!=f)) {
6809 ret = 1;
6810 break;
6811 }
6812 } else { /* NaN is unequal to any value */
6813 if (neq)
6814 ret = 1;
6815 }
6816 }
6817 }
6818 }
6819
6820 return(ret);
6821 }
6822
6823
6824 /**
6825 * xmlXPathEqualNodeSets:
6826 * @arg1: first nodeset object argument
6827 * @arg2: second nodeset object argument
6828 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6829 *
6830 * Implement the equal / not equal operation on XPath nodesets:
6831 * @arg1 == @arg2 or @arg1 != @arg2
6832 * If both objects to be compared are node-sets, then the comparison
6833 * will be true if and only if there is a node in the first node-set and
6834 * a node in the second node-set such that the result of performing the
6835 * comparison on the string-values of the two nodes is true.
6836 *
6837 * (needless to say, this is a costly operation)
6838 *
6839 * Returns 0 or 1 depending on the results of the test.
6840 */
6841 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6842 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6843 int i, j;
6844 unsigned int *hashs1;
6845 unsigned int *hashs2;
6846 xmlChar **values1;
6847 xmlChar **values2;
6848 int ret = 0;
6849 xmlNodeSetPtr ns1;
6850 xmlNodeSetPtr ns2;
6851
6852 if ((arg1 == NULL) ||
6853 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6854 return(0);
6855 if ((arg2 == NULL) ||
6856 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6857 return(0);
6858
6859 ns1 = arg1->nodesetval;
6860 ns2 = arg2->nodesetval;
6861
6862 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6863 return(0);
6864 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6865 return(0);
6866
6867 /*
6868 * for equal, check if there is a node pertaining to both sets
6869 */
6870 if (neq == 0)
6871 for (i = 0;i < ns1->nodeNr;i++)
6872 for (j = 0;j < ns2->nodeNr;j++)
6873 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6874 return(1);
6875
6876 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6877 if (values1 == NULL) {
6878 /* TODO: Propagate memory error. */
6879 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6880 return(0);
6881 }
6882 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6883 if (hashs1 == NULL) {
6884 /* TODO: Propagate memory error. */
6885 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6886 xmlFree(values1);
6887 return(0);
6888 }
6889 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6890 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6891 if (values2 == NULL) {
6892 /* TODO: Propagate memory error. */
6893 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6894 xmlFree(hashs1);
6895 xmlFree(values1);
6896 return(0);
6897 }
6898 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6899 if (hashs2 == NULL) {
6900 /* TODO: Propagate memory error. */
6901 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6902 xmlFree(hashs1);
6903 xmlFree(values1);
6904 xmlFree(values2);
6905 return(0);
6906 }
6907 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6908 for (i = 0;i < ns1->nodeNr;i++) {
6909 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6910 for (j = 0;j < ns2->nodeNr;j++) {
6911 if (i == 0)
6912 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6913 if (hashs1[i] != hashs2[j]) {
6914 if (neq) {
6915 ret = 1;
6916 break;
6917 }
6918 }
6919 else {
6920 if (values1[i] == NULL)
6921 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6922 if (values2[j] == NULL)
6923 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6924 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6925 if (ret)
6926 break;
6927 }
6928 }
6929 if (ret)
6930 break;
6931 }
6932 for (i = 0;i < ns1->nodeNr;i++)
6933 if (values1[i] != NULL)
6934 xmlFree(values1[i]);
6935 for (j = 0;j < ns2->nodeNr;j++)
6936 if (values2[j] != NULL)
6937 xmlFree(values2[j]);
6938 xmlFree(values1);
6939 xmlFree(values2);
6940 xmlFree(hashs1);
6941 xmlFree(hashs2);
6942 return(ret);
6943 }
6944
6945 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6946 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6947 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6948 int ret = 0;
6949 /*
6950 *At this point we are assured neither arg1 nor arg2
6951 *is a nodeset, so we can just pick the appropriate routine.
6952 */
6953 switch (arg1->type) {
6954 case XPATH_UNDEFINED:
6955 #ifdef DEBUG_EXPR
6956 xmlGenericError(xmlGenericErrorContext,
6957 "Equal: undefined\n");
6958 #endif
6959 break;
6960 case XPATH_BOOLEAN:
6961 switch (arg2->type) {
6962 case XPATH_UNDEFINED:
6963 #ifdef DEBUG_EXPR
6964 xmlGenericError(xmlGenericErrorContext,
6965 "Equal: undefined\n");
6966 #endif
6967 break;
6968 case XPATH_BOOLEAN:
6969 #ifdef DEBUG_EXPR
6970 xmlGenericError(xmlGenericErrorContext,
6971 "Equal: %d boolean %d \n",
6972 arg1->boolval, arg2->boolval);
6973 #endif
6974 ret = (arg1->boolval == arg2->boolval);
6975 break;
6976 case XPATH_NUMBER:
6977 ret = (arg1->boolval ==
6978 xmlXPathCastNumberToBoolean(arg2->floatval));
6979 break;
6980 case XPATH_STRING:
6981 if ((arg2->stringval == NULL) ||
6982 (arg2->stringval[0] == 0)) ret = 0;
6983 else
6984 ret = 1;
6985 ret = (arg1->boolval == ret);
6986 break;
6987 case XPATH_USERS:
6988 case XPATH_POINT:
6989 case XPATH_RANGE:
6990 case XPATH_LOCATIONSET:
6991 TODO
6992 break;
6993 case XPATH_NODESET:
6994 case XPATH_XSLT_TREE:
6995 break;
6996 }
6997 break;
6998 case XPATH_NUMBER:
6999 switch (arg2->type) {
7000 case XPATH_UNDEFINED:
7001 #ifdef DEBUG_EXPR
7002 xmlGenericError(xmlGenericErrorContext,
7003 "Equal: undefined\n");
7004 #endif
7005 break;
7006 case XPATH_BOOLEAN:
7007 ret = (arg2->boolval==
7008 xmlXPathCastNumberToBoolean(arg1->floatval));
7009 break;
7010 case XPATH_STRING:
7011 valuePush(ctxt, arg2);
7012 xmlXPathNumberFunction(ctxt, 1);
7013 arg2 = valuePop(ctxt);
7014 /* Falls through. */
7015 case XPATH_NUMBER:
7016 /* Hand check NaN and Infinity equalities */
7017 if (xmlXPathIsNaN(arg1->floatval) ||
7018 xmlXPathIsNaN(arg2->floatval)) {
7019 ret = 0;
7020 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7021 if (xmlXPathIsInf(arg2->floatval) == 1)
7022 ret = 1;
7023 else
7024 ret = 0;
7025 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7026 if (xmlXPathIsInf(arg2->floatval) == -1)
7027 ret = 1;
7028 else
7029 ret = 0;
7030 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7031 if (xmlXPathIsInf(arg1->floatval) == 1)
7032 ret = 1;
7033 else
7034 ret = 0;
7035 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7036 if (xmlXPathIsInf(arg1->floatval) == -1)
7037 ret = 1;
7038 else
7039 ret = 0;
7040 } else {
7041 ret = (arg1->floatval == arg2->floatval);
7042 }
7043 break;
7044 case XPATH_USERS:
7045 case XPATH_POINT:
7046 case XPATH_RANGE:
7047 case XPATH_LOCATIONSET:
7048 TODO
7049 break;
7050 case XPATH_NODESET:
7051 case XPATH_XSLT_TREE:
7052 break;
7053 }
7054 break;
7055 case XPATH_STRING:
7056 switch (arg2->type) {
7057 case XPATH_UNDEFINED:
7058 #ifdef DEBUG_EXPR
7059 xmlGenericError(xmlGenericErrorContext,
7060 "Equal: undefined\n");
7061 #endif
7062 break;
7063 case XPATH_BOOLEAN:
7064 if ((arg1->stringval == NULL) ||
7065 (arg1->stringval[0] == 0)) ret = 0;
7066 else
7067 ret = 1;
7068 ret = (arg2->boolval == ret);
7069 break;
7070 case XPATH_STRING:
7071 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7072 break;
7073 case XPATH_NUMBER:
7074 valuePush(ctxt, arg1);
7075 xmlXPathNumberFunction(ctxt, 1);
7076 arg1 = valuePop(ctxt);
7077 /* Hand check NaN and Infinity equalities */
7078 if (xmlXPathIsNaN(arg1->floatval) ||
7079 xmlXPathIsNaN(arg2->floatval)) {
7080 ret = 0;
7081 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7082 if (xmlXPathIsInf(arg2->floatval) == 1)
7083 ret = 1;
7084 else
7085 ret = 0;
7086 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7087 if (xmlXPathIsInf(arg2->floatval) == -1)
7088 ret = 1;
7089 else
7090 ret = 0;
7091 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7092 if (xmlXPathIsInf(arg1->floatval) == 1)
7093 ret = 1;
7094 else
7095 ret = 0;
7096 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7097 if (xmlXPathIsInf(arg1->floatval) == -1)
7098 ret = 1;
7099 else
7100 ret = 0;
7101 } else {
7102 ret = (arg1->floatval == arg2->floatval);
7103 }
7104 break;
7105 case XPATH_USERS:
7106 case XPATH_POINT:
7107 case XPATH_RANGE:
7108 case XPATH_LOCATIONSET:
7109 TODO
7110 break;
7111 case XPATH_NODESET:
7112 case XPATH_XSLT_TREE:
7113 break;
7114 }
7115 break;
7116 case XPATH_USERS:
7117 case XPATH_POINT:
7118 case XPATH_RANGE:
7119 case XPATH_LOCATIONSET:
7120 TODO
7121 break;
7122 case XPATH_NODESET:
7123 case XPATH_XSLT_TREE:
7124 break;
7125 }
7126 xmlXPathReleaseObject(ctxt->context, arg1);
7127 xmlXPathReleaseObject(ctxt->context, arg2);
7128 return(ret);
7129 }
7130
7131 /**
7132 * xmlXPathEqualValues:
7133 * @ctxt: the XPath Parser context
7134 *
7135 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7136 *
7137 * Returns 0 or 1 depending on the results of the test.
7138 */
7139 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7140 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7141 xmlXPathObjectPtr arg1, arg2, argtmp;
7142 int ret = 0;
7143
7144 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7145 arg2 = valuePop(ctxt);
7146 arg1 = valuePop(ctxt);
7147 if ((arg1 == NULL) || (arg2 == NULL)) {
7148 if (arg1 != NULL)
7149 xmlXPathReleaseObject(ctxt->context, arg1);
7150 else
7151 xmlXPathReleaseObject(ctxt->context, arg2);
7152 XP_ERROR0(XPATH_INVALID_OPERAND);
7153 }
7154
7155 if (arg1 == arg2) {
7156 #ifdef DEBUG_EXPR
7157 xmlGenericError(xmlGenericErrorContext,
7158 "Equal: by pointer\n");
7159 #endif
7160 xmlXPathFreeObject(arg1);
7161 return(1);
7162 }
7163
7164 /*
7165 *If either argument is a nodeset, it's a 'special case'
7166 */
7167 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7168 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7169 /*
7170 *Hack it to assure arg1 is the nodeset
7171 */
7172 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7173 argtmp = arg2;
7174 arg2 = arg1;
7175 arg1 = argtmp;
7176 }
7177 switch (arg2->type) {
7178 case XPATH_UNDEFINED:
7179 #ifdef DEBUG_EXPR
7180 xmlGenericError(xmlGenericErrorContext,
7181 "Equal: undefined\n");
7182 #endif
7183 break;
7184 case XPATH_NODESET:
7185 case XPATH_XSLT_TREE:
7186 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7187 break;
7188 case XPATH_BOOLEAN:
7189 if ((arg1->nodesetval == NULL) ||
7190 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7191 else
7192 ret = 1;
7193 ret = (ret == arg2->boolval);
7194 break;
7195 case XPATH_NUMBER:
7196 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7197 break;
7198 case XPATH_STRING:
7199 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7200 break;
7201 case XPATH_USERS:
7202 case XPATH_POINT:
7203 case XPATH_RANGE:
7204 case XPATH_LOCATIONSET:
7205 TODO
7206 break;
7207 }
7208 xmlXPathReleaseObject(ctxt->context, arg1);
7209 xmlXPathReleaseObject(ctxt->context, arg2);
7210 return(ret);
7211 }
7212
7213 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7214 }
7215
7216 /**
7217 * xmlXPathNotEqualValues:
7218 * @ctxt: the XPath Parser context
7219 *
7220 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7221 *
7222 * Returns 0 or 1 depending on the results of the test.
7223 */
7224 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7225 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7226 xmlXPathObjectPtr arg1, arg2, argtmp;
7227 int ret = 0;
7228
7229 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7230 arg2 = valuePop(ctxt);
7231 arg1 = valuePop(ctxt);
7232 if ((arg1 == NULL) || (arg2 == NULL)) {
7233 if (arg1 != NULL)
7234 xmlXPathReleaseObject(ctxt->context, arg1);
7235 else
7236 xmlXPathReleaseObject(ctxt->context, arg2);
7237 XP_ERROR0(XPATH_INVALID_OPERAND);
7238 }
7239
7240 if (arg1 == arg2) {
7241 #ifdef DEBUG_EXPR
7242 xmlGenericError(xmlGenericErrorContext,
7243 "NotEqual: by pointer\n");
7244 #endif
7245 xmlXPathReleaseObject(ctxt->context, arg1);
7246 return(0);
7247 }
7248
7249 /*
7250 *If either argument is a nodeset, it's a 'special case'
7251 */
7252 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7253 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7254 /*
7255 *Hack it to assure arg1 is the nodeset
7256 */
7257 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7258 argtmp = arg2;
7259 arg2 = arg1;
7260 arg1 = argtmp;
7261 }
7262 switch (arg2->type) {
7263 case XPATH_UNDEFINED:
7264 #ifdef DEBUG_EXPR
7265 xmlGenericError(xmlGenericErrorContext,
7266 "NotEqual: undefined\n");
7267 #endif
7268 break;
7269 case XPATH_NODESET:
7270 case XPATH_XSLT_TREE:
7271 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7272 break;
7273 case XPATH_BOOLEAN:
7274 if ((arg1->nodesetval == NULL) ||
7275 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7276 else
7277 ret = 1;
7278 ret = (ret != arg2->boolval);
7279 break;
7280 case XPATH_NUMBER:
7281 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7282 break;
7283 case XPATH_STRING:
7284 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7285 break;
7286 case XPATH_USERS:
7287 case XPATH_POINT:
7288 case XPATH_RANGE:
7289 case XPATH_LOCATIONSET:
7290 TODO
7291 break;
7292 }
7293 xmlXPathReleaseObject(ctxt->context, arg1);
7294 xmlXPathReleaseObject(ctxt->context, arg2);
7295 return(ret);
7296 }
7297
7298 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7299 }
7300
7301 /**
7302 * xmlXPathCompareValues:
7303 * @ctxt: the XPath Parser context
7304 * @inf: less than (1) or greater than (0)
7305 * @strict: is the comparison strict
7306 *
7307 * Implement the compare operation on XPath objects:
7308 * @arg1 < @arg2 (1, 1, ...
7309 * @arg1 <= @arg2 (1, 0, ...
7310 * @arg1 > @arg2 (0, 1, ...
7311 * @arg1 >= @arg2 (0, 0, ...
7312 *
7313 * When neither object to be compared is a node-set and the operator is
7314 * <=, <, >=, >, then the objects are compared by converted both objects
7315 * to numbers and comparing the numbers according to IEEE 754. The <
7316 * comparison will be true if and only if the first number is less than the
7317 * second number. The <= comparison will be true if and only if the first
7318 * number is less than or equal to the second number. The > comparison
7319 * will be true if and only if the first number is greater than the second
7320 * number. The >= comparison will be true if and only if the first number
7321 * is greater than or equal to the second number.
7322 *
7323 * Returns 1 if the comparison succeeded, 0 if it failed
7324 */
7325 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7326 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7327 int ret = 0, arg1i = 0, arg2i = 0;
7328 xmlXPathObjectPtr arg1, arg2;
7329
7330 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7331 arg2 = valuePop(ctxt);
7332 arg1 = valuePop(ctxt);
7333 if ((arg1 == NULL) || (arg2 == NULL)) {
7334 if (arg1 != NULL)
7335 xmlXPathReleaseObject(ctxt->context, arg1);
7336 else
7337 xmlXPathReleaseObject(ctxt->context, arg2);
7338 XP_ERROR0(XPATH_INVALID_OPERAND);
7339 }
7340
7341 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7342 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7343 /*
7344 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7345 * are not freed from within this routine; they will be freed from the
7346 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7347 */
7348 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7349 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7350 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7351 } else {
7352 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7353 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7354 arg1, arg2);
7355 } else {
7356 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7357 arg2, arg1);
7358 }
7359 }
7360 return(ret);
7361 }
7362
7363 if (arg1->type != XPATH_NUMBER) {
7364 valuePush(ctxt, arg1);
7365 xmlXPathNumberFunction(ctxt, 1);
7366 arg1 = valuePop(ctxt);
7367 }
7368 if (arg1->type != XPATH_NUMBER) {
7369 xmlXPathFreeObject(arg1);
7370 xmlXPathFreeObject(arg2);
7371 XP_ERROR0(XPATH_INVALID_OPERAND);
7372 }
7373 if (arg2->type != XPATH_NUMBER) {
7374 valuePush(ctxt, arg2);
7375 xmlXPathNumberFunction(ctxt, 1);
7376 arg2 = valuePop(ctxt);
7377 }
7378 if (arg2->type != XPATH_NUMBER) {
7379 xmlXPathReleaseObject(ctxt->context, arg1);
7380 xmlXPathReleaseObject(ctxt->context, arg2);
7381 XP_ERROR0(XPATH_INVALID_OPERAND);
7382 }
7383 /*
7384 * Add tests for infinity and nan
7385 * => feedback on 3.4 for Inf and NaN
7386 */
7387 /* Hand check NaN and Infinity comparisons */
7388 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7389 ret=0;
7390 } else {
7391 arg1i=xmlXPathIsInf(arg1->floatval);
7392 arg2i=xmlXPathIsInf(arg2->floatval);
7393 if (inf && strict) {
7394 if ((arg1i == -1 && arg2i != -1) ||
7395 (arg2i == 1 && arg1i != 1)) {
7396 ret = 1;
7397 } else if (arg1i == 0 && arg2i == 0) {
7398 ret = (arg1->floatval < arg2->floatval);
7399 } else {
7400 ret = 0;
7401 }
7402 }
7403 else if (inf && !strict) {
7404 if (arg1i == -1 || arg2i == 1) {
7405 ret = 1;
7406 } else if (arg1i == 0 && arg2i == 0) {
7407 ret = (arg1->floatval <= arg2->floatval);
7408 } else {
7409 ret = 0;
7410 }
7411 }
7412 else if (!inf && strict) {
7413 if ((arg1i == 1 && arg2i != 1) ||
7414 (arg2i == -1 && arg1i != -1)) {
7415 ret = 1;
7416 } else if (arg1i == 0 && arg2i == 0) {
7417 ret = (arg1->floatval > arg2->floatval);
7418 } else {
7419 ret = 0;
7420 }
7421 }
7422 else if (!inf && !strict) {
7423 if (arg1i == 1 || arg2i == -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 }
7432 xmlXPathReleaseObject(ctxt->context, arg1);
7433 xmlXPathReleaseObject(ctxt->context, arg2);
7434 return(ret);
7435 }
7436
7437 /**
7438 * xmlXPathValueFlipSign:
7439 * @ctxt: the XPath Parser context
7440 *
7441 * Implement the unary - operation on an XPath object
7442 * The numeric operators convert their operands to numbers as if
7443 * by calling the number function.
7444 */
7445 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7446 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7447 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7448 CAST_TO_NUMBER;
7449 CHECK_TYPE(XPATH_NUMBER);
7450 ctxt->value->floatval = -ctxt->value->floatval;
7451 }
7452
7453 /**
7454 * xmlXPathAddValues:
7455 * @ctxt: the XPath Parser context
7456 *
7457 * Implement the add operation on XPath objects:
7458 * The numeric operators convert their operands to numbers as if
7459 * by calling the number function.
7460 */
7461 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7462 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7463 xmlXPathObjectPtr arg;
7464 double val;
7465
7466 arg = valuePop(ctxt);
7467 if (arg == NULL)
7468 XP_ERROR(XPATH_INVALID_OPERAND);
7469 val = xmlXPathCastToNumber(arg);
7470 xmlXPathReleaseObject(ctxt->context, arg);
7471 CAST_TO_NUMBER;
7472 CHECK_TYPE(XPATH_NUMBER);
7473 ctxt->value->floatval += val;
7474 }
7475
7476 /**
7477 * xmlXPathSubValues:
7478 * @ctxt: the XPath Parser context
7479 *
7480 * Implement the subtraction operation on XPath objects:
7481 * The numeric operators convert their operands to numbers as if
7482 * by calling the number function.
7483 */
7484 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7485 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7486 xmlXPathObjectPtr arg;
7487 double val;
7488
7489 arg = valuePop(ctxt);
7490 if (arg == NULL)
7491 XP_ERROR(XPATH_INVALID_OPERAND);
7492 val = xmlXPathCastToNumber(arg);
7493 xmlXPathReleaseObject(ctxt->context, arg);
7494 CAST_TO_NUMBER;
7495 CHECK_TYPE(XPATH_NUMBER);
7496 ctxt->value->floatval -= val;
7497 }
7498
7499 /**
7500 * xmlXPathMultValues:
7501 * @ctxt: the XPath Parser context
7502 *
7503 * Implement the multiply operation on XPath objects:
7504 * The numeric operators convert their operands to numbers as if
7505 * by calling the number function.
7506 */
7507 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7508 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7509 xmlXPathObjectPtr arg;
7510 double val;
7511
7512 arg = valuePop(ctxt);
7513 if (arg == NULL)
7514 XP_ERROR(XPATH_INVALID_OPERAND);
7515 val = xmlXPathCastToNumber(arg);
7516 xmlXPathReleaseObject(ctxt->context, arg);
7517 CAST_TO_NUMBER;
7518 CHECK_TYPE(XPATH_NUMBER);
7519 ctxt->value->floatval *= val;
7520 }
7521
7522 /**
7523 * xmlXPathDivValues:
7524 * @ctxt: the XPath Parser context
7525 *
7526 * Implement the div operation on XPath objects @arg1 / @arg2:
7527 * The numeric operators convert their operands to numbers as if
7528 * by calling the number function.
7529 */
7530 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7531 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7532 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7533 xmlXPathObjectPtr arg;
7534 double val;
7535
7536 arg = valuePop(ctxt);
7537 if (arg == NULL)
7538 XP_ERROR(XPATH_INVALID_OPERAND);
7539 val = xmlXPathCastToNumber(arg);
7540 xmlXPathReleaseObject(ctxt->context, arg);
7541 CAST_TO_NUMBER;
7542 CHECK_TYPE(XPATH_NUMBER);
7543 ctxt->value->floatval /= val;
7544 }
7545
7546 /**
7547 * xmlXPathModValues:
7548 * @ctxt: the XPath Parser context
7549 *
7550 * Implement the mod operation on XPath objects: @arg1 / @arg2
7551 * The numeric operators convert their operands to numbers as if
7552 * by calling the number function.
7553 */
7554 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7555 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7556 xmlXPathObjectPtr arg;
7557 double arg1, arg2;
7558
7559 arg = valuePop(ctxt);
7560 if (arg == NULL)
7561 XP_ERROR(XPATH_INVALID_OPERAND);
7562 arg2 = xmlXPathCastToNumber(arg);
7563 xmlXPathReleaseObject(ctxt->context, arg);
7564 CAST_TO_NUMBER;
7565 CHECK_TYPE(XPATH_NUMBER);
7566 arg1 = ctxt->value->floatval;
7567 if (arg2 == 0)
7568 ctxt->value->floatval = xmlXPathNAN;
7569 else {
7570 ctxt->value->floatval = fmod(arg1, arg2);
7571 }
7572 }
7573
7574 /************************************************************************
7575 * *
7576 * The traversal functions *
7577 * *
7578 ************************************************************************/
7579
7580 /*
7581 * A traversal function enumerates nodes along an axis.
7582 * Initially it must be called with NULL, and it indicates
7583 * termination on the axis by returning NULL.
7584 */
7585 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7586 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7587
7588 /*
7589 * xmlXPathTraversalFunctionExt:
7590 * A traversal function enumerates nodes along an axis.
7591 * Initially it must be called with NULL, and it indicates
7592 * termination on the axis by returning NULL.
7593 * The context node of the traversal is specified via @contextNode.
7594 */
7595 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7596 (xmlNodePtr cur, xmlNodePtr contextNode);
7597
7598 /*
7599 * xmlXPathNodeSetMergeFunction:
7600 * Used for merging node sets in xmlXPathCollectAndTest().
7601 */
7602 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7603 (xmlNodeSetPtr, xmlNodeSetPtr);
7604
7605
7606 /**
7607 * xmlXPathNextSelf:
7608 * @ctxt: the XPath Parser context
7609 * @cur: the current node in the traversal
7610 *
7611 * Traversal function for the "self" direction
7612 * The self axis contains just the context node itself
7613 *
7614 * Returns the next element following that axis
7615 */
7616 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7617 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7618 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7619 if (cur == NULL)
7620 return(ctxt->context->node);
7621 return(NULL);
7622 }
7623
7624 /**
7625 * xmlXPathNextChild:
7626 * @ctxt: the XPath Parser context
7627 * @cur: the current node in the traversal
7628 *
7629 * Traversal function for the "child" direction
7630 * The child axis contains the children of the context node in document order.
7631 *
7632 * Returns the next element following that axis
7633 */
7634 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7635 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7636 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7637 if (cur == NULL) {
7638 if (ctxt->context->node == NULL) return(NULL);
7639 switch (ctxt->context->node->type) {
7640 case XML_ELEMENT_NODE:
7641 case XML_TEXT_NODE:
7642 case XML_CDATA_SECTION_NODE:
7643 case XML_ENTITY_REF_NODE:
7644 case XML_ENTITY_NODE:
7645 case XML_PI_NODE:
7646 case XML_COMMENT_NODE:
7647 case XML_NOTATION_NODE:
7648 case XML_DTD_NODE:
7649 return(ctxt->context->node->children);
7650 case XML_DOCUMENT_NODE:
7651 case XML_DOCUMENT_TYPE_NODE:
7652 case XML_DOCUMENT_FRAG_NODE:
7653 case XML_HTML_DOCUMENT_NODE:
7654 #ifdef LIBXML_DOCB_ENABLED
7655 case XML_DOCB_DOCUMENT_NODE:
7656 #endif
7657 return(((xmlDocPtr) ctxt->context->node)->children);
7658 case XML_ELEMENT_DECL:
7659 case XML_ATTRIBUTE_DECL:
7660 case XML_ENTITY_DECL:
7661 case XML_ATTRIBUTE_NODE:
7662 case XML_NAMESPACE_DECL:
7663 case XML_XINCLUDE_START:
7664 case XML_XINCLUDE_END:
7665 return(NULL);
7666 }
7667 return(NULL);
7668 }
7669 if ((cur->type == XML_DOCUMENT_NODE) ||
7670 (cur->type == XML_HTML_DOCUMENT_NODE))
7671 return(NULL);
7672 return(cur->next);
7673 }
7674
7675 /**
7676 * xmlXPathNextChildElement:
7677 * @ctxt: the XPath Parser context
7678 * @cur: the current node in the traversal
7679 *
7680 * Traversal function for the "child" direction and nodes of type element.
7681 * The child axis contains the children of the context node in document order.
7682 *
7683 * Returns the next element following that axis
7684 */
7685 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7686 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688 if (cur == NULL) {
7689 cur = ctxt->context->node;
7690 if (cur == NULL) return(NULL);
7691 /*
7692 * Get the first element child.
7693 */
7694 switch (cur->type) {
7695 case XML_ELEMENT_NODE:
7696 case XML_DOCUMENT_FRAG_NODE:
7697 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7698 case XML_ENTITY_NODE:
7699 cur = cur->children;
7700 if (cur != NULL) {
7701 if (cur->type == XML_ELEMENT_NODE)
7702 return(cur);
7703 do {
7704 cur = cur->next;
7705 } while ((cur != NULL) &&
7706 (cur->type != XML_ELEMENT_NODE));
7707 return(cur);
7708 }
7709 return(NULL);
7710 case XML_DOCUMENT_NODE:
7711 case XML_HTML_DOCUMENT_NODE:
7712 #ifdef LIBXML_DOCB_ENABLED
7713 case XML_DOCB_DOCUMENT_NODE:
7714 #endif
7715 return(xmlDocGetRootElement((xmlDocPtr) cur));
7716 default:
7717 return(NULL);
7718 }
7719 return(NULL);
7720 }
7721 /*
7722 * Get the next sibling element node.
7723 */
7724 switch (cur->type) {
7725 case XML_ELEMENT_NODE:
7726 case XML_TEXT_NODE:
7727 case XML_ENTITY_REF_NODE:
7728 case XML_ENTITY_NODE:
7729 case XML_CDATA_SECTION_NODE:
7730 case XML_PI_NODE:
7731 case XML_COMMENT_NODE:
7732 case XML_XINCLUDE_END:
7733 break;
7734 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7735 default:
7736 return(NULL);
7737 }
7738 if (cur->next != NULL) {
7739 if (cur->next->type == XML_ELEMENT_NODE)
7740 return(cur->next);
7741 cur = cur->next;
7742 do {
7743 cur = cur->next;
7744 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7745 return(cur);
7746 }
7747 return(NULL);
7748 }
7749
7750 #if 0
7751 /**
7752 * xmlXPathNextDescendantOrSelfElemParent:
7753 * @ctxt: the XPath Parser context
7754 * @cur: the current node in the traversal
7755 *
7756 * Traversal function for the "descendant-or-self" axis.
7757 * Additionally it returns only nodes which can be parents of
7758 * element nodes.
7759 *
7760 *
7761 * Returns the next element following that axis
7762 */
7763 static xmlNodePtr
7764 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7765 xmlNodePtr contextNode)
7766 {
7767 if (cur == NULL) {
7768 if (contextNode == NULL)
7769 return(NULL);
7770 switch (contextNode->type) {
7771 case XML_ELEMENT_NODE:
7772 case XML_XINCLUDE_START:
7773 case XML_DOCUMENT_FRAG_NODE:
7774 case XML_DOCUMENT_NODE:
7775 #ifdef LIBXML_DOCB_ENABLED
7776 case XML_DOCB_DOCUMENT_NODE:
7777 #endif
7778 case XML_HTML_DOCUMENT_NODE:
7779 return(contextNode);
7780 default:
7781 return(NULL);
7782 }
7783 return(NULL);
7784 } else {
7785 xmlNodePtr start = cur;
7786
7787 while (cur != NULL) {
7788 switch (cur->type) {
7789 case XML_ELEMENT_NODE:
7790 /* TODO: OK to have XInclude here? */
7791 case XML_XINCLUDE_START:
7792 case XML_DOCUMENT_FRAG_NODE:
7793 if (cur != start)
7794 return(cur);
7795 if (cur->children != NULL) {
7796 cur = cur->children;
7797 continue;
7798 }
7799 break;
7800 /* Not sure if we need those here. */
7801 case XML_DOCUMENT_NODE:
7802 #ifdef LIBXML_DOCB_ENABLED
7803 case XML_DOCB_DOCUMENT_NODE:
7804 #endif
7805 case XML_HTML_DOCUMENT_NODE:
7806 if (cur != start)
7807 return(cur);
7808 return(xmlDocGetRootElement((xmlDocPtr) cur));
7809 default:
7810 break;
7811 }
7812
7813 next_sibling:
7814 if ((cur == NULL) || (cur == contextNode))
7815 return(NULL);
7816 if (cur->next != NULL) {
7817 cur = cur->next;
7818 } else {
7819 cur = cur->parent;
7820 goto next_sibling;
7821 }
7822 }
7823 }
7824 return(NULL);
7825 }
7826 #endif
7827
7828 /**
7829 * xmlXPathNextDescendant:
7830 * @ctxt: the XPath Parser context
7831 * @cur: the current node in the traversal
7832 *
7833 * Traversal function for the "descendant" direction
7834 * the descendant axis contains the descendants of the context node in document
7835 * order; a descendant is a child or a child of a child and so on.
7836 *
7837 * Returns the next element following that axis
7838 */
7839 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7840 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7841 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7842 if (cur == NULL) {
7843 if (ctxt->context->node == NULL)
7844 return(NULL);
7845 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7846 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7847 return(NULL);
7848
7849 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7850 return(ctxt->context->doc->children);
7851 return(ctxt->context->node->children);
7852 }
7853
7854 if (cur->type == XML_NAMESPACE_DECL)
7855 return(NULL);
7856 if (cur->children != NULL) {
7857 /*
7858 * Do not descend on entities declarations
7859 */
7860 if (cur->children->type != XML_ENTITY_DECL) {
7861 cur = cur->children;
7862 /*
7863 * Skip DTDs
7864 */
7865 if (cur->type != XML_DTD_NODE)
7866 return(cur);
7867 }
7868 }
7869
7870 if (cur == ctxt->context->node) return(NULL);
7871
7872 while (cur->next != NULL) {
7873 cur = cur->next;
7874 if ((cur->type != XML_ENTITY_DECL) &&
7875 (cur->type != XML_DTD_NODE))
7876 return(cur);
7877 }
7878
7879 do {
7880 cur = cur->parent;
7881 if (cur == NULL) break;
7882 if (cur == ctxt->context->node) return(NULL);
7883 if (cur->next != NULL) {
7884 cur = cur->next;
7885 return(cur);
7886 }
7887 } while (cur != NULL);
7888 return(cur);
7889 }
7890
7891 /**
7892 * xmlXPathNextDescendantOrSelf:
7893 * @ctxt: the XPath Parser context
7894 * @cur: the current node in the traversal
7895 *
7896 * Traversal function for the "descendant-or-self" direction
7897 * the descendant-or-self axis contains the context node and the descendants
7898 * of the context node in document order; thus the context node is the first
7899 * node on the axis, and the first child of the context node is the second node
7900 * on the axis
7901 *
7902 * Returns the next element following that axis
7903 */
7904 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7905 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7906 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7907 if (cur == NULL)
7908 return(ctxt->context->node);
7909
7910 if (ctxt->context->node == NULL)
7911 return(NULL);
7912 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7913 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7914 return(NULL);
7915
7916 return(xmlXPathNextDescendant(ctxt, cur));
7917 }
7918
7919 /**
7920 * xmlXPathNextParent:
7921 * @ctxt: the XPath Parser context
7922 * @cur: the current node in the traversal
7923 *
7924 * Traversal function for the "parent" direction
7925 * The parent axis contains the parent of the context node, if there is one.
7926 *
7927 * Returns the next element following that axis
7928 */
7929 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7930 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7931 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7932 /*
7933 * the parent of an attribute or namespace node is the element
7934 * to which the attribute or namespace node is attached
7935 * Namespace handling !!!
7936 */
7937 if (cur == NULL) {
7938 if (ctxt->context->node == NULL) return(NULL);
7939 switch (ctxt->context->node->type) {
7940 case XML_ELEMENT_NODE:
7941 case XML_TEXT_NODE:
7942 case XML_CDATA_SECTION_NODE:
7943 case XML_ENTITY_REF_NODE:
7944 case XML_ENTITY_NODE:
7945 case XML_PI_NODE:
7946 case XML_COMMENT_NODE:
7947 case XML_NOTATION_NODE:
7948 case XML_DTD_NODE:
7949 case XML_ELEMENT_DECL:
7950 case XML_ATTRIBUTE_DECL:
7951 case XML_XINCLUDE_START:
7952 case XML_XINCLUDE_END:
7953 case XML_ENTITY_DECL:
7954 if (ctxt->context->node->parent == NULL)
7955 return((xmlNodePtr) ctxt->context->doc);
7956 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7957 ((ctxt->context->node->parent->name[0] == ' ') ||
7958 (xmlStrEqual(ctxt->context->node->parent->name,
7959 BAD_CAST "fake node libxslt"))))
7960 return(NULL);
7961 return(ctxt->context->node->parent);
7962 case XML_ATTRIBUTE_NODE: {
7963 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7964
7965 return(att->parent);
7966 }
7967 case XML_DOCUMENT_NODE:
7968 case XML_DOCUMENT_TYPE_NODE:
7969 case XML_DOCUMENT_FRAG_NODE:
7970 case XML_HTML_DOCUMENT_NODE:
7971 #ifdef LIBXML_DOCB_ENABLED
7972 case XML_DOCB_DOCUMENT_NODE:
7973 #endif
7974 return(NULL);
7975 case XML_NAMESPACE_DECL: {
7976 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7977
7978 if ((ns->next != NULL) &&
7979 (ns->next->type != XML_NAMESPACE_DECL))
7980 return((xmlNodePtr) ns->next);
7981 return(NULL);
7982 }
7983 }
7984 }
7985 return(NULL);
7986 }
7987
7988 /**
7989 * xmlXPathNextAncestor:
7990 * @ctxt: the XPath Parser context
7991 * @cur: the current node in the traversal
7992 *
7993 * Traversal function for the "ancestor" direction
7994 * the ancestor axis contains the ancestors of the context node; the ancestors
7995 * of the context node consist of the parent of context node and the parent's
7996 * parent and so on; the nodes are ordered in reverse document order; thus the
7997 * parent is the first node on the axis, and the parent's parent is the second
7998 * node on the axis
7999 *
8000 * Returns the next element following that axis
8001 */
8002 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8003 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8004 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8005 /*
8006 * the parent of an attribute or namespace node is the element
8007 * to which the attribute or namespace node is attached
8008 * !!!!!!!!!!!!!
8009 */
8010 if (cur == NULL) {
8011 if (ctxt->context->node == NULL) return(NULL);
8012 switch (ctxt->context->node->type) {
8013 case XML_ELEMENT_NODE:
8014 case XML_TEXT_NODE:
8015 case XML_CDATA_SECTION_NODE:
8016 case XML_ENTITY_REF_NODE:
8017 case XML_ENTITY_NODE:
8018 case XML_PI_NODE:
8019 case XML_COMMENT_NODE:
8020 case XML_DTD_NODE:
8021 case XML_ELEMENT_DECL:
8022 case XML_ATTRIBUTE_DECL:
8023 case XML_ENTITY_DECL:
8024 case XML_NOTATION_NODE:
8025 case XML_XINCLUDE_START:
8026 case XML_XINCLUDE_END:
8027 if (ctxt->context->node->parent == NULL)
8028 return((xmlNodePtr) ctxt->context->doc);
8029 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8030 ((ctxt->context->node->parent->name[0] == ' ') ||
8031 (xmlStrEqual(ctxt->context->node->parent->name,
8032 BAD_CAST "fake node libxslt"))))
8033 return(NULL);
8034 return(ctxt->context->node->parent);
8035 case XML_ATTRIBUTE_NODE: {
8036 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8037
8038 return(tmp->parent);
8039 }
8040 case XML_DOCUMENT_NODE:
8041 case XML_DOCUMENT_TYPE_NODE:
8042 case XML_DOCUMENT_FRAG_NODE:
8043 case XML_HTML_DOCUMENT_NODE:
8044 #ifdef LIBXML_DOCB_ENABLED
8045 case XML_DOCB_DOCUMENT_NODE:
8046 #endif
8047 return(NULL);
8048 case XML_NAMESPACE_DECL: {
8049 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8050
8051 if ((ns->next != NULL) &&
8052 (ns->next->type != XML_NAMESPACE_DECL))
8053 return((xmlNodePtr) ns->next);
8054 /* Bad, how did that namespace end up here ? */
8055 return(NULL);
8056 }
8057 }
8058 return(NULL);
8059 }
8060 if (cur == ctxt->context->doc->children)
8061 return((xmlNodePtr) ctxt->context->doc);
8062 if (cur == (xmlNodePtr) ctxt->context->doc)
8063 return(NULL);
8064 switch (cur->type) {
8065 case XML_ELEMENT_NODE:
8066 case XML_TEXT_NODE:
8067 case XML_CDATA_SECTION_NODE:
8068 case XML_ENTITY_REF_NODE:
8069 case XML_ENTITY_NODE:
8070 case XML_PI_NODE:
8071 case XML_COMMENT_NODE:
8072 case XML_NOTATION_NODE:
8073 case XML_DTD_NODE:
8074 case XML_ELEMENT_DECL:
8075 case XML_ATTRIBUTE_DECL:
8076 case XML_ENTITY_DECL:
8077 case XML_XINCLUDE_START:
8078 case XML_XINCLUDE_END:
8079 if (cur->parent == NULL)
8080 return(NULL);
8081 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8082 ((cur->parent->name[0] == ' ') ||
8083 (xmlStrEqual(cur->parent->name,
8084 BAD_CAST "fake node libxslt"))))
8085 return(NULL);
8086 return(cur->parent);
8087 case XML_ATTRIBUTE_NODE: {
8088 xmlAttrPtr att = (xmlAttrPtr) cur;
8089
8090 return(att->parent);
8091 }
8092 case XML_NAMESPACE_DECL: {
8093 xmlNsPtr ns = (xmlNsPtr) cur;
8094
8095 if ((ns->next != NULL) &&
8096 (ns->next->type != XML_NAMESPACE_DECL))
8097 return((xmlNodePtr) ns->next);
8098 /* Bad, how did that namespace end up here ? */
8099 return(NULL);
8100 }
8101 case XML_DOCUMENT_NODE:
8102 case XML_DOCUMENT_TYPE_NODE:
8103 case XML_DOCUMENT_FRAG_NODE:
8104 case XML_HTML_DOCUMENT_NODE:
8105 #ifdef LIBXML_DOCB_ENABLED
8106 case XML_DOCB_DOCUMENT_NODE:
8107 #endif
8108 return(NULL);
8109 }
8110 return(NULL);
8111 }
8112
8113 /**
8114 * xmlXPathNextAncestorOrSelf:
8115 * @ctxt: the XPath Parser context
8116 * @cur: the current node in the traversal
8117 *
8118 * Traversal function for the "ancestor-or-self" direction
8119 * he ancestor-or-self axis contains the context node and ancestors of
8120 * the context node in reverse document order; thus the context node is
8121 * the first node on the axis, and the context node's parent the second;
8122 * parent here is defined the same as with the parent axis.
8123 *
8124 * Returns the next element following that axis
8125 */
8126 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8127 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8128 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8129 if (cur == NULL)
8130 return(ctxt->context->node);
8131 return(xmlXPathNextAncestor(ctxt, cur));
8132 }
8133
8134 /**
8135 * xmlXPathNextFollowingSibling:
8136 * @ctxt: the XPath Parser context
8137 * @cur: the current node in the traversal
8138 *
8139 * Traversal function for the "following-sibling" direction
8140 * The following-sibling axis contains the following siblings of the context
8141 * node in document order.
8142 *
8143 * Returns the next element following that axis
8144 */
8145 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8146 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8147 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8148 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8149 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8150 return(NULL);
8151 if (cur == (xmlNodePtr) ctxt->context->doc)
8152 return(NULL);
8153 if (cur == NULL)
8154 return(ctxt->context->node->next);
8155 return(cur->next);
8156 }
8157
8158 /**
8159 * xmlXPathNextPrecedingSibling:
8160 * @ctxt: the XPath Parser context
8161 * @cur: the current node in the traversal
8162 *
8163 * Traversal function for the "preceding-sibling" direction
8164 * The preceding-sibling axis contains the preceding siblings of the context
8165 * node in reverse document order; the first preceding sibling is first on the
8166 * axis; the sibling preceding that node is the second on the axis and so on.
8167 *
8168 * Returns the next element following that axis
8169 */
8170 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8171 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8173 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8174 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8175 return(NULL);
8176 if (cur == (xmlNodePtr) ctxt->context->doc)
8177 return(NULL);
8178 if (cur == NULL)
8179 return(ctxt->context->node->prev);
8180 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8181 cur = cur->prev;
8182 if (cur == NULL)
8183 return(ctxt->context->node->prev);
8184 }
8185 return(cur->prev);
8186 }
8187
8188 /**
8189 * xmlXPathNextFollowing:
8190 * @ctxt: the XPath Parser context
8191 * @cur: the current node in the traversal
8192 *
8193 * Traversal function for the "following" direction
8194 * The following axis contains all nodes in the same document as the context
8195 * node that are after the context node in document order, excluding any
8196 * descendants and excluding attribute nodes and namespace nodes; the nodes
8197 * are ordered in document order
8198 *
8199 * Returns the next element following that axis
8200 */
8201 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8202 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8203 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8204 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8205 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8206 return(cur->children);
8207
8208 if (cur == NULL) {
8209 cur = ctxt->context->node;
8210 if (cur->type == XML_ATTRIBUTE_NODE) {
8211 cur = cur->parent;
8212 } else if (cur->type == XML_NAMESPACE_DECL) {
8213 xmlNsPtr ns = (xmlNsPtr) cur;
8214
8215 if ((ns->next == NULL) ||
8216 (ns->next->type == XML_NAMESPACE_DECL))
8217 return (NULL);
8218 cur = (xmlNodePtr) ns->next;
8219 }
8220 }
8221 if (cur == NULL) return(NULL) ; /* ERROR */
8222 if (cur->next != NULL) return(cur->next) ;
8223 do {
8224 cur = cur->parent;
8225 if (cur == NULL) break;
8226 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8227 if (cur->next != NULL) return(cur->next);
8228 } while (cur != NULL);
8229 return(cur);
8230 }
8231
8232 /*
8233 * xmlXPathIsAncestor:
8234 * @ancestor: the ancestor node
8235 * @node: the current node
8236 *
8237 * Check that @ancestor is a @node's ancestor
8238 *
8239 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8240 */
8241 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8242 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8243 if ((ancestor == NULL) || (node == NULL)) return(0);
8244 if (node->type == XML_NAMESPACE_DECL)
8245 return(0);
8246 if (ancestor->type == XML_NAMESPACE_DECL)
8247 return(0);
8248 /* nodes need to be in the same document */
8249 if (ancestor->doc != node->doc) return(0);
8250 /* avoid searching if ancestor or node is the root node */
8251 if (ancestor == (xmlNodePtr) node->doc) return(1);
8252 if (node == (xmlNodePtr) ancestor->doc) return(0);
8253 while (node->parent != NULL) {
8254 if (node->parent == ancestor)
8255 return(1);
8256 node = node->parent;
8257 }
8258 return(0);
8259 }
8260
8261 /**
8262 * xmlXPathNextPreceding:
8263 * @ctxt: the XPath Parser context
8264 * @cur: the current node in the traversal
8265 *
8266 * Traversal function for the "preceding" direction
8267 * the preceding axis contains all nodes in the same document as the context
8268 * node that are before the context node in document order, excluding any
8269 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8270 * ordered in reverse document order
8271 *
8272 * Returns the next element following that axis
8273 */
8274 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8275 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8276 {
8277 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8278 if (cur == NULL) {
8279 cur = ctxt->context->node;
8280 if (cur->type == XML_ATTRIBUTE_NODE) {
8281 cur = cur->parent;
8282 } else if (cur->type == XML_NAMESPACE_DECL) {
8283 xmlNsPtr ns = (xmlNsPtr) cur;
8284
8285 if ((ns->next == NULL) ||
8286 (ns->next->type == XML_NAMESPACE_DECL))
8287 return (NULL);
8288 cur = (xmlNodePtr) ns->next;
8289 }
8290 }
8291 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8292 return (NULL);
8293 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8294 cur = cur->prev;
8295 do {
8296 if (cur->prev != NULL) {
8297 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8298 return (cur);
8299 }
8300
8301 cur = cur->parent;
8302 if (cur == NULL)
8303 return (NULL);
8304 if (cur == ctxt->context->doc->children)
8305 return (NULL);
8306 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8307 return (cur);
8308 }
8309
8310 /**
8311 * xmlXPathNextPrecedingInternal:
8312 * @ctxt: the XPath Parser context
8313 * @cur: the current node in the traversal
8314 *
8315 * Traversal function for the "preceding" direction
8316 * the preceding axis contains all nodes in the same document as the context
8317 * node that are before the context node in document order, excluding any
8318 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8319 * ordered in reverse document order
8320 * This is a faster implementation but internal only since it requires a
8321 * state kept in the parser context: ctxt->ancestor.
8322 *
8323 * Returns the next element following that axis
8324 */
8325 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8326 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8327 xmlNodePtr cur)
8328 {
8329 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8330 if (cur == NULL) {
8331 cur = ctxt->context->node;
8332 if (cur == NULL)
8333 return (NULL);
8334 if (cur->type == XML_ATTRIBUTE_NODE) {
8335 cur = cur->parent;
8336 } else if (cur->type == XML_NAMESPACE_DECL) {
8337 xmlNsPtr ns = (xmlNsPtr) cur;
8338
8339 if ((ns->next == NULL) ||
8340 (ns->next->type == XML_NAMESPACE_DECL))
8341 return (NULL);
8342 cur = (xmlNodePtr) ns->next;
8343 }
8344 ctxt->ancestor = cur->parent;
8345 }
8346 if (cur->type == XML_NAMESPACE_DECL)
8347 return(NULL);
8348 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8349 cur = cur->prev;
8350 while (cur->prev == NULL) {
8351 cur = cur->parent;
8352 if (cur == NULL)
8353 return (NULL);
8354 if (cur == ctxt->context->doc->children)
8355 return (NULL);
8356 if (cur != ctxt->ancestor)
8357 return (cur);
8358 ctxt->ancestor = cur->parent;
8359 }
8360 cur = cur->prev;
8361 while (cur->last != NULL)
8362 cur = cur->last;
8363 return (cur);
8364 }
8365
8366 /**
8367 * xmlXPathNextNamespace:
8368 * @ctxt: the XPath Parser context
8369 * @cur: the current attribute in the traversal
8370 *
8371 * Traversal function for the "namespace" direction
8372 * the namespace axis contains the namespace nodes of the context node;
8373 * the order of nodes on this axis is implementation-defined; the axis will
8374 * be empty unless the context node is an element
8375 *
8376 * We keep the XML namespace node at the end of the list.
8377 *
8378 * Returns the next element following that axis
8379 */
8380 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8381 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8382 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8383 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8384 if (cur == NULL) {
8385 if (ctxt->context->tmpNsList != NULL)
8386 xmlFree(ctxt->context->tmpNsList);
8387 ctxt->context->tmpNsList =
8388 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8389 ctxt->context->tmpNsNr = 0;
8390 if (ctxt->context->tmpNsList != NULL) {
8391 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8392 ctxt->context->tmpNsNr++;
8393 }
8394 }
8395 return((xmlNodePtr) xmlXPathXMLNamespace);
8396 }
8397 if (ctxt->context->tmpNsNr > 0) {
8398 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8399 } else {
8400 if (ctxt->context->tmpNsList != NULL)
8401 xmlFree(ctxt->context->tmpNsList);
8402 ctxt->context->tmpNsList = NULL;
8403 return(NULL);
8404 }
8405 }
8406
8407 /**
8408 * xmlXPathNextAttribute:
8409 * @ctxt: the XPath Parser context
8410 * @cur: the current attribute in the traversal
8411 *
8412 * Traversal function for the "attribute" direction
8413 * TODO: support DTD inherited default attributes
8414 *
8415 * Returns the next element following that axis
8416 */
8417 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8418 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8419 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8420 if (ctxt->context->node == NULL)
8421 return(NULL);
8422 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8423 return(NULL);
8424 if (cur == NULL) {
8425 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8426 return(NULL);
8427 return((xmlNodePtr)ctxt->context->node->properties);
8428 }
8429 return((xmlNodePtr)cur->next);
8430 }
8431
8432 /************************************************************************
8433 * *
8434 * NodeTest Functions *
8435 * *
8436 ************************************************************************/
8437
8438 #define IS_FUNCTION 200
8439
8440
8441 /************************************************************************
8442 * *
8443 * Implicit tree core function library *
8444 * *
8445 ************************************************************************/
8446
8447 /**
8448 * xmlXPathRoot:
8449 * @ctxt: the XPath Parser context
8450 *
8451 * Initialize the context to the root of the document
8452 */
8453 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8454 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8455 if ((ctxt == NULL) || (ctxt->context == NULL))
8456 return;
8457 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8458 (xmlNodePtr) ctxt->context->doc));
8459 }
8460
8461 /************************************************************************
8462 * *
8463 * The explicit core function library *
8464 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8465 * *
8466 ************************************************************************/
8467
8468
8469 /**
8470 * xmlXPathLastFunction:
8471 * @ctxt: the XPath Parser context
8472 * @nargs: the number of arguments
8473 *
8474 * Implement the last() XPath function
8475 * number last()
8476 * The last function returns the number of nodes in the context node list.
8477 */
8478 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8479 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8480 CHECK_ARITY(0);
8481 if (ctxt->context->contextSize >= 0) {
8482 valuePush(ctxt,
8483 xmlXPathCacheNewFloat(ctxt->context,
8484 (double) ctxt->context->contextSize));
8485 #ifdef DEBUG_EXPR
8486 xmlGenericError(xmlGenericErrorContext,
8487 "last() : %d\n", ctxt->context->contextSize);
8488 #endif
8489 } else {
8490 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8491 }
8492 }
8493
8494 /**
8495 * xmlXPathPositionFunction:
8496 * @ctxt: the XPath Parser context
8497 * @nargs: the number of arguments
8498 *
8499 * Implement the position() XPath function
8500 * number position()
8501 * The position function returns the position of the context node in the
8502 * context node list. The first position is 1, and so the last position
8503 * will be equal to last().
8504 */
8505 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8506 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8507 CHECK_ARITY(0);
8508 if (ctxt->context->proximityPosition >= 0) {
8509 valuePush(ctxt,
8510 xmlXPathCacheNewFloat(ctxt->context,
8511 (double) ctxt->context->proximityPosition));
8512 #ifdef DEBUG_EXPR
8513 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8514 ctxt->context->proximityPosition);
8515 #endif
8516 } else {
8517 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8518 }
8519 }
8520
8521 /**
8522 * xmlXPathCountFunction:
8523 * @ctxt: the XPath Parser context
8524 * @nargs: the number of arguments
8525 *
8526 * Implement the count() XPath function
8527 * number count(node-set)
8528 */
8529 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8530 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8531 xmlXPathObjectPtr cur;
8532
8533 CHECK_ARITY(1);
8534 if ((ctxt->value == NULL) ||
8535 ((ctxt->value->type != XPATH_NODESET) &&
8536 (ctxt->value->type != XPATH_XSLT_TREE)))
8537 XP_ERROR(XPATH_INVALID_TYPE);
8538 cur = valuePop(ctxt);
8539
8540 if ((cur == NULL) || (cur->nodesetval == NULL))
8541 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8542 else
8543 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8544 (double) cur->nodesetval->nodeNr));
8545 xmlXPathReleaseObject(ctxt->context, cur);
8546 }
8547
8548 /**
8549 * xmlXPathGetElementsByIds:
8550 * @doc: the document
8551 * @ids: a whitespace separated list of IDs
8552 *
8553 * Selects elements by their unique ID.
8554 *
8555 * Returns a node-set of selected elements.
8556 */
8557 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8558 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8559 xmlNodeSetPtr ret;
8560 const xmlChar *cur = ids;
8561 xmlChar *ID;
8562 xmlAttrPtr attr;
8563 xmlNodePtr elem = NULL;
8564
8565 if (ids == NULL) return(NULL);
8566
8567 ret = xmlXPathNodeSetCreate(NULL);
8568 if (ret == NULL)
8569 return(ret);
8570
8571 while (IS_BLANK_CH(*cur)) cur++;
8572 while (*cur != 0) {
8573 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8574 cur++;
8575
8576 ID = xmlStrndup(ids, cur - ids);
8577 if (ID != NULL) {
8578 /*
8579 * We used to check the fact that the value passed
8580 * was an NCName, but this generated much troubles for
8581 * me and Aleksey Sanin, people blatantly violated that
8582 * constraint, like Visa3D spec.
8583 * if (xmlValidateNCName(ID, 1) == 0)
8584 */
8585 attr = xmlGetID(doc, ID);
8586 if (attr != NULL) {
8587 if (attr->type == XML_ATTRIBUTE_NODE)
8588 elem = attr->parent;
8589 else if (attr->type == XML_ELEMENT_NODE)
8590 elem = (xmlNodePtr) attr;
8591 else
8592 elem = NULL;
8593 /* TODO: Check memory error. */
8594 if (elem != NULL)
8595 xmlXPathNodeSetAdd(ret, elem);
8596 }
8597 xmlFree(ID);
8598 }
8599
8600 while (IS_BLANK_CH(*cur)) cur++;
8601 ids = cur;
8602 }
8603 return(ret);
8604 }
8605
8606 /**
8607 * xmlXPathIdFunction:
8608 * @ctxt: the XPath Parser context
8609 * @nargs: the number of arguments
8610 *
8611 * Implement the id() XPath function
8612 * node-set id(object)
8613 * The id function selects elements by their unique ID
8614 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8615 * then the result is the union of the result of applying id to the
8616 * string value of each of the nodes in the argument node-set. When the
8617 * argument to id is of any other type, the argument is converted to a
8618 * string as if by a call to the string function; the string is split
8619 * into a whitespace-separated list of tokens (whitespace is any sequence
8620 * of characters matching the production S); the result is a node-set
8621 * containing the elements in the same document as the context node that
8622 * have a unique ID equal to any of the tokens in the list.
8623 */
8624 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8625 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8626 xmlChar *tokens;
8627 xmlNodeSetPtr ret;
8628 xmlXPathObjectPtr obj;
8629
8630 CHECK_ARITY(1);
8631 obj = valuePop(ctxt);
8632 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8633 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8634 xmlNodeSetPtr ns;
8635 int i;
8636
8637 /* TODO: Check memory error. */
8638 ret = xmlXPathNodeSetCreate(NULL);
8639
8640 if (obj->nodesetval != NULL) {
8641 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8642 tokens =
8643 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8644 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8645 /* TODO: Check memory error. */
8646 ret = xmlXPathNodeSetMerge(ret, ns);
8647 xmlXPathFreeNodeSet(ns);
8648 if (tokens != NULL)
8649 xmlFree(tokens);
8650 }
8651 }
8652 xmlXPathReleaseObject(ctxt->context, obj);
8653 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8654 return;
8655 }
8656 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8657 if (obj == NULL) return;
8658 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8659 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8660 xmlXPathReleaseObject(ctxt->context, obj);
8661 return;
8662 }
8663
8664 /**
8665 * xmlXPathLocalNameFunction:
8666 * @ctxt: the XPath Parser context
8667 * @nargs: the number of arguments
8668 *
8669 * Implement the local-name() XPath function
8670 * string local-name(node-set?)
8671 * The local-name function returns a string containing the local part
8672 * of the name of the node in the argument node-set that is first in
8673 * document order. If the node-set is empty or the first node has no
8674 * name, an empty string is returned. If the argument is omitted it
8675 * defaults to the context node.
8676 */
8677 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8678 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8679 xmlXPathObjectPtr cur;
8680
8681 if (ctxt == NULL) return;
8682
8683 if (nargs == 0) {
8684 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8685 ctxt->context->node));
8686 nargs = 1;
8687 }
8688
8689 CHECK_ARITY(1);
8690 if ((ctxt->value == NULL) ||
8691 ((ctxt->value->type != XPATH_NODESET) &&
8692 (ctxt->value->type != XPATH_XSLT_TREE)))
8693 XP_ERROR(XPATH_INVALID_TYPE);
8694 cur = valuePop(ctxt);
8695
8696 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8697 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8698 } else {
8699 int i = 0; /* Should be first in document order !!!!! */
8700 switch (cur->nodesetval->nodeTab[i]->type) {
8701 case XML_ELEMENT_NODE:
8702 case XML_ATTRIBUTE_NODE:
8703 case XML_PI_NODE:
8704 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8705 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8706 else
8707 valuePush(ctxt,
8708 xmlXPathCacheNewString(ctxt->context,
8709 cur->nodesetval->nodeTab[i]->name));
8710 break;
8711 case XML_NAMESPACE_DECL:
8712 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8713 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8714 break;
8715 default:
8716 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8717 }
8718 }
8719 xmlXPathReleaseObject(ctxt->context, cur);
8720 }
8721
8722 /**
8723 * xmlXPathNamespaceURIFunction:
8724 * @ctxt: the XPath Parser context
8725 * @nargs: the number of arguments
8726 *
8727 * Implement the namespace-uri() XPath function
8728 * string namespace-uri(node-set?)
8729 * The namespace-uri function returns a string containing the
8730 * namespace URI of the expanded name of the node in the argument
8731 * node-set that is first in document order. If the node-set is empty,
8732 * the first node has no name, or the expanded name has no namespace
8733 * URI, an empty string is returned. If the argument is omitted it
8734 * defaults to the context node.
8735 */
8736 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8737 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8738 xmlXPathObjectPtr cur;
8739
8740 if (ctxt == NULL) return;
8741
8742 if (nargs == 0) {
8743 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8744 ctxt->context->node));
8745 nargs = 1;
8746 }
8747 CHECK_ARITY(1);
8748 if ((ctxt->value == NULL) ||
8749 ((ctxt->value->type != XPATH_NODESET) &&
8750 (ctxt->value->type != XPATH_XSLT_TREE)))
8751 XP_ERROR(XPATH_INVALID_TYPE);
8752 cur = valuePop(ctxt);
8753
8754 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8755 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8756 } else {
8757 int i = 0; /* Should be first in document order !!!!! */
8758 switch (cur->nodesetval->nodeTab[i]->type) {
8759 case XML_ELEMENT_NODE:
8760 case XML_ATTRIBUTE_NODE:
8761 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763 else
8764 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8765 cur->nodesetval->nodeTab[i]->ns->href));
8766 break;
8767 default:
8768 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8769 }
8770 }
8771 xmlXPathReleaseObject(ctxt->context, cur);
8772 }
8773
8774 /**
8775 * xmlXPathNameFunction:
8776 * @ctxt: the XPath Parser context
8777 * @nargs: the number of arguments
8778 *
8779 * Implement the name() XPath function
8780 * string name(node-set?)
8781 * The name function returns a string containing a QName representing
8782 * the name of the node in the argument node-set that is first in document
8783 * order. The QName must represent the name with respect to the namespace
8784 * declarations in effect on the node whose name is being represented.
8785 * Typically, this will be the form in which the name occurred in the XML
8786 * source. This need not be the case if there are namespace declarations
8787 * in effect on the node that associate multiple prefixes with the same
8788 * namespace. However, an implementation may include information about
8789 * the original prefix in its representation of nodes; in this case, an
8790 * implementation can ensure that the returned string is always the same
8791 * as the QName used in the XML source. If the argument it omitted it
8792 * defaults to the context node.
8793 * Libxml keep the original prefix so the "real qualified name" used is
8794 * returned.
8795 */
8796 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8797 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8798 {
8799 xmlXPathObjectPtr cur;
8800
8801 if (nargs == 0) {
8802 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8803 ctxt->context->node));
8804 nargs = 1;
8805 }
8806
8807 CHECK_ARITY(1);
8808 if ((ctxt->value == NULL) ||
8809 ((ctxt->value->type != XPATH_NODESET) &&
8810 (ctxt->value->type != XPATH_XSLT_TREE)))
8811 XP_ERROR(XPATH_INVALID_TYPE);
8812 cur = valuePop(ctxt);
8813
8814 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8815 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8816 } else {
8817 int i = 0; /* Should be first in document order !!!!! */
8818
8819 switch (cur->nodesetval->nodeTab[i]->type) {
8820 case XML_ELEMENT_NODE:
8821 case XML_ATTRIBUTE_NODE:
8822 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8823 valuePush(ctxt,
8824 xmlXPathCacheNewCString(ctxt->context, ""));
8825 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8826 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8827 valuePush(ctxt,
8828 xmlXPathCacheNewString(ctxt->context,
8829 cur->nodesetval->nodeTab[i]->name));
8830 } else {
8831 xmlChar *fullname;
8832
8833 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8834 cur->nodesetval->nodeTab[i]->ns->prefix,
8835 NULL, 0);
8836 if (fullname == cur->nodesetval->nodeTab[i]->name)
8837 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8838 if (fullname == NULL) {
8839 XP_ERROR(XPATH_MEMORY_ERROR);
8840 }
8841 valuePush(ctxt, xmlXPathCacheWrapString(
8842 ctxt->context, fullname));
8843 }
8844 break;
8845 default:
8846 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8847 cur->nodesetval->nodeTab[i]));
8848 xmlXPathLocalNameFunction(ctxt, 1);
8849 }
8850 }
8851 xmlXPathReleaseObject(ctxt->context, cur);
8852 }
8853
8854
8855 /**
8856 * xmlXPathStringFunction:
8857 * @ctxt: the XPath Parser context
8858 * @nargs: the number of arguments
8859 *
8860 * Implement the string() XPath function
8861 * string string(object?)
8862 * The string function converts an object to a string as follows:
8863 * - A node-set is converted to a string by returning the value of
8864 * the node in the node-set that is first in document order.
8865 * If the node-set is empty, an empty string is returned.
8866 * - A number is converted to a string as follows
8867 * + NaN is converted to the string NaN
8868 * + positive zero is converted to the string 0
8869 * + negative zero is converted to the string 0
8870 * + positive infinity is converted to the string Infinity
8871 * + negative infinity is converted to the string -Infinity
8872 * + if the number is an integer, the number is represented in
8873 * decimal form as a Number with no decimal point and no leading
8874 * zeros, preceded by a minus sign (-) if the number is negative
8875 * + otherwise, the number is represented in decimal form as a
8876 * Number including a decimal point with at least one digit
8877 * before the decimal point and at least one digit after the
8878 * decimal point, preceded by a minus sign (-) if the number
8879 * is negative; there must be no leading zeros before the decimal
8880 * point apart possibly from the one required digit immediately
8881 * before the decimal point; beyond the one required digit
8882 * after the decimal point there must be as many, but only as
8883 * many, more digits as are needed to uniquely distinguish the
8884 * number from all other IEEE 754 numeric values.
8885 * - The boolean false value is converted to the string false.
8886 * The boolean true value is converted to the string true.
8887 *
8888 * If the argument is omitted, it defaults to a node-set with the
8889 * context node as its only member.
8890 */
8891 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8892 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8893 xmlXPathObjectPtr cur;
8894
8895 if (ctxt == NULL) return;
8896 if (nargs == 0) {
8897 valuePush(ctxt,
8898 xmlXPathCacheWrapString(ctxt->context,
8899 xmlXPathCastNodeToString(ctxt->context->node)));
8900 return;
8901 }
8902
8903 CHECK_ARITY(1);
8904 cur = valuePop(ctxt);
8905 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8906 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8907 }
8908
8909 /**
8910 * xmlXPathStringLengthFunction:
8911 * @ctxt: the XPath Parser context
8912 * @nargs: the number of arguments
8913 *
8914 * Implement the string-length() XPath function
8915 * number string-length(string?)
8916 * The string-length returns the number of characters in the string
8917 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8918 * the context node converted to a string, in other words the value
8919 * of the context node.
8920 */
8921 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8922 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8923 xmlXPathObjectPtr cur;
8924
8925 if (nargs == 0) {
8926 if ((ctxt == NULL) || (ctxt->context == NULL))
8927 return;
8928 if (ctxt->context->node == NULL) {
8929 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8930 } else {
8931 xmlChar *content;
8932
8933 content = xmlXPathCastNodeToString(ctxt->context->node);
8934 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8935 xmlUTF8Strlen(content)));
8936 xmlFree(content);
8937 }
8938 return;
8939 }
8940 CHECK_ARITY(1);
8941 CAST_TO_STRING;
8942 CHECK_TYPE(XPATH_STRING);
8943 cur = valuePop(ctxt);
8944 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8945 xmlUTF8Strlen(cur->stringval)));
8946 xmlXPathReleaseObject(ctxt->context, cur);
8947 }
8948
8949 /**
8950 * xmlXPathConcatFunction:
8951 * @ctxt: the XPath Parser context
8952 * @nargs: the number of arguments
8953 *
8954 * Implement the concat() XPath function
8955 * string concat(string, string, string*)
8956 * The concat function returns the concatenation of its arguments.
8957 */
8958 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)8959 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8960 xmlXPathObjectPtr cur, newobj;
8961 xmlChar *tmp;
8962
8963 if (ctxt == NULL) return;
8964 if (nargs < 2) {
8965 CHECK_ARITY(2);
8966 }
8967
8968 CAST_TO_STRING;
8969 cur = valuePop(ctxt);
8970 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8971 xmlXPathReleaseObject(ctxt->context, cur);
8972 return;
8973 }
8974 nargs--;
8975
8976 while (nargs > 0) {
8977 CAST_TO_STRING;
8978 newobj = valuePop(ctxt);
8979 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8980 xmlXPathReleaseObject(ctxt->context, newobj);
8981 xmlXPathReleaseObject(ctxt->context, cur);
8982 XP_ERROR(XPATH_INVALID_TYPE);
8983 }
8984 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8985 newobj->stringval = cur->stringval;
8986 cur->stringval = tmp;
8987 xmlXPathReleaseObject(ctxt->context, newobj);
8988 nargs--;
8989 }
8990 valuePush(ctxt, cur);
8991 }
8992
8993 /**
8994 * xmlXPathContainsFunction:
8995 * @ctxt: the XPath Parser context
8996 * @nargs: the number of arguments
8997 *
8998 * Implement the contains() XPath function
8999 * boolean contains(string, string)
9000 * The contains function returns true if the first argument string
9001 * contains the second argument string, and otherwise returns false.
9002 */
9003 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9004 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9005 xmlXPathObjectPtr hay, needle;
9006
9007 CHECK_ARITY(2);
9008 CAST_TO_STRING;
9009 CHECK_TYPE(XPATH_STRING);
9010 needle = valuePop(ctxt);
9011 CAST_TO_STRING;
9012 hay = valuePop(ctxt);
9013
9014 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9015 xmlXPathReleaseObject(ctxt->context, hay);
9016 xmlXPathReleaseObject(ctxt->context, needle);
9017 XP_ERROR(XPATH_INVALID_TYPE);
9018 }
9019 if (xmlStrstr(hay->stringval, needle->stringval))
9020 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9021 else
9022 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9023 xmlXPathReleaseObject(ctxt->context, hay);
9024 xmlXPathReleaseObject(ctxt->context, needle);
9025 }
9026
9027 /**
9028 * xmlXPathStartsWithFunction:
9029 * @ctxt: the XPath Parser context
9030 * @nargs: the number of arguments
9031 *
9032 * Implement the starts-with() XPath function
9033 * boolean starts-with(string, string)
9034 * The starts-with function returns true if the first argument string
9035 * starts with the second argument string, and otherwise returns false.
9036 */
9037 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9038 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9039 xmlXPathObjectPtr hay, needle;
9040 int n;
9041
9042 CHECK_ARITY(2);
9043 CAST_TO_STRING;
9044 CHECK_TYPE(XPATH_STRING);
9045 needle = valuePop(ctxt);
9046 CAST_TO_STRING;
9047 hay = valuePop(ctxt);
9048
9049 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9050 xmlXPathReleaseObject(ctxt->context, hay);
9051 xmlXPathReleaseObject(ctxt->context, needle);
9052 XP_ERROR(XPATH_INVALID_TYPE);
9053 }
9054 n = xmlStrlen(needle->stringval);
9055 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9056 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9057 else
9058 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9059 xmlXPathReleaseObject(ctxt->context, hay);
9060 xmlXPathReleaseObject(ctxt->context, needle);
9061 }
9062
9063 /**
9064 * xmlXPathSubstringFunction:
9065 * @ctxt: the XPath Parser context
9066 * @nargs: the number of arguments
9067 *
9068 * Implement the substring() XPath function
9069 * string substring(string, number, number?)
9070 * The substring function returns the substring of the first argument
9071 * starting at the position specified in the second argument with
9072 * length specified in the third argument. For example,
9073 * substring("12345",2,3) returns "234". If the third argument is not
9074 * specified, it returns the substring starting at the position specified
9075 * in the second argument and continuing to the end of the string. For
9076 * example, substring("12345",2) returns "2345". More precisely, each
9077 * character in the string (see [3.6 Strings]) is considered to have a
9078 * numeric position: the position of the first character is 1, the position
9079 * of the second character is 2 and so on. The returned substring contains
9080 * those characters for which the position of the character is greater than
9081 * or equal to the second argument and, if the third argument is specified,
9082 * less than the sum of the second and third arguments; the comparisons
9083 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9084 * - substring("12345", 1.5, 2.6) returns "234"
9085 * - substring("12345", 0, 3) returns "12"
9086 * - substring("12345", 0 div 0, 3) returns ""
9087 * - substring("12345", 1, 0 div 0) returns ""
9088 * - substring("12345", -42, 1 div 0) returns "12345"
9089 * - substring("12345", -1 div 0, 1 div 0) returns ""
9090 */
9091 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9092 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9093 xmlXPathObjectPtr str, start, len;
9094 double le=0, in;
9095 int i = 1, j = INT_MAX;
9096
9097 if (nargs < 2) {
9098 CHECK_ARITY(2);
9099 }
9100 if (nargs > 3) {
9101 CHECK_ARITY(3);
9102 }
9103 /*
9104 * take care of possible last (position) argument
9105 */
9106 if (nargs == 3) {
9107 CAST_TO_NUMBER;
9108 CHECK_TYPE(XPATH_NUMBER);
9109 len = valuePop(ctxt);
9110 le = len->floatval;
9111 xmlXPathReleaseObject(ctxt->context, len);
9112 }
9113
9114 CAST_TO_NUMBER;
9115 CHECK_TYPE(XPATH_NUMBER);
9116 start = valuePop(ctxt);
9117 in = start->floatval;
9118 xmlXPathReleaseObject(ctxt->context, start);
9119 CAST_TO_STRING;
9120 CHECK_TYPE(XPATH_STRING);
9121 str = valuePop(ctxt);
9122
9123 if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9124 i = INT_MAX;
9125 } else if (in >= 1.0) {
9126 i = (int)in;
9127 if (in - floor(in) >= 0.5)
9128 i += 1;
9129 }
9130
9131 if (nargs == 3) {
9132 double rin, rle, end;
9133
9134 rin = floor(in);
9135 if (in - rin >= 0.5)
9136 rin += 1.0;
9137
9138 rle = floor(le);
9139 if (le - rle >= 0.5)
9140 rle += 1.0;
9141
9142 end = rin + rle;
9143 if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9144 j = 1;
9145 } else if (end < INT_MAX) {
9146 j = (int)end;
9147 }
9148 }
9149
9150 if (i < j) {
9151 xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9152 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9153 xmlFree(ret);
9154 } else {
9155 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9156 }
9157
9158 xmlXPathReleaseObject(ctxt->context, str);
9159 }
9160
9161 /**
9162 * xmlXPathSubstringBeforeFunction:
9163 * @ctxt: the XPath Parser context
9164 * @nargs: the number of arguments
9165 *
9166 * Implement the substring-before() XPath function
9167 * string substring-before(string, string)
9168 * The substring-before function returns the substring of the first
9169 * argument string that precedes the first occurrence of the second
9170 * argument string in the first argument string, or the empty string
9171 * if the first argument string does not contain the second argument
9172 * string. For example, substring-before("1999/04/01","/") returns 1999.
9173 */
9174 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9175 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9176 xmlXPathObjectPtr str;
9177 xmlXPathObjectPtr find;
9178 xmlBufPtr target;
9179 const xmlChar *point;
9180 int offset;
9181
9182 CHECK_ARITY(2);
9183 CAST_TO_STRING;
9184 find = valuePop(ctxt);
9185 CAST_TO_STRING;
9186 str = valuePop(ctxt);
9187
9188 target = xmlBufCreate();
9189 if (target) {
9190 point = xmlStrstr(str->stringval, find->stringval);
9191 if (point) {
9192 offset = (int)(point - str->stringval);
9193 xmlBufAdd(target, str->stringval, offset);
9194 }
9195 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9196 xmlBufContent(target)));
9197 xmlBufFree(target);
9198 }
9199 xmlXPathReleaseObject(ctxt->context, str);
9200 xmlXPathReleaseObject(ctxt->context, find);
9201 }
9202
9203 /**
9204 * xmlXPathSubstringAfterFunction:
9205 * @ctxt: the XPath Parser context
9206 * @nargs: the number of arguments
9207 *
9208 * Implement the substring-after() XPath function
9209 * string substring-after(string, string)
9210 * The substring-after function returns the substring of the first
9211 * argument string that follows the first occurrence of the second
9212 * argument string in the first argument string, or the empty stringi
9213 * if the first argument string does not contain the second argument
9214 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9215 * and substring-after("1999/04/01","19") returns 99/04/01.
9216 */
9217 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9218 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9219 xmlXPathObjectPtr str;
9220 xmlXPathObjectPtr find;
9221 xmlBufPtr target;
9222 const xmlChar *point;
9223 int offset;
9224
9225 CHECK_ARITY(2);
9226 CAST_TO_STRING;
9227 find = valuePop(ctxt);
9228 CAST_TO_STRING;
9229 str = valuePop(ctxt);
9230
9231 target = xmlBufCreate();
9232 if (target) {
9233 point = xmlStrstr(str->stringval, find->stringval);
9234 if (point) {
9235 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9236 xmlBufAdd(target, &str->stringval[offset],
9237 xmlStrlen(str->stringval) - offset);
9238 }
9239 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9240 xmlBufContent(target)));
9241 xmlBufFree(target);
9242 }
9243 xmlXPathReleaseObject(ctxt->context, str);
9244 xmlXPathReleaseObject(ctxt->context, find);
9245 }
9246
9247 /**
9248 * xmlXPathNormalizeFunction:
9249 * @ctxt: the XPath Parser context
9250 * @nargs: the number of arguments
9251 *
9252 * Implement the normalize-space() XPath function
9253 * string normalize-space(string?)
9254 * The normalize-space function returns the argument string with white
9255 * space normalized by stripping leading and trailing whitespace
9256 * and replacing sequences of whitespace characters by a single
9257 * space. Whitespace characters are the same allowed by the S production
9258 * in XML. If the argument is omitted, it defaults to the context
9259 * node converted to a string, in other words the value of the context node.
9260 */
9261 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9262 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9263 xmlXPathObjectPtr obj = NULL;
9264 xmlChar *source = NULL;
9265 xmlBufPtr target;
9266 xmlChar blank;
9267
9268 if (ctxt == NULL) return;
9269 if (nargs == 0) {
9270 /* Use current context node */
9271 valuePush(ctxt,
9272 xmlXPathCacheWrapString(ctxt->context,
9273 xmlXPathCastNodeToString(ctxt->context->node)));
9274 nargs = 1;
9275 }
9276
9277 CHECK_ARITY(1);
9278 CAST_TO_STRING;
9279 CHECK_TYPE(XPATH_STRING);
9280 obj = valuePop(ctxt);
9281 source = obj->stringval;
9282
9283 target = xmlBufCreate();
9284 if (target && source) {
9285
9286 /* Skip leading whitespaces */
9287 while (IS_BLANK_CH(*source))
9288 source++;
9289
9290 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9291 blank = 0;
9292 while (*source) {
9293 if (IS_BLANK_CH(*source)) {
9294 blank = 0x20;
9295 } else {
9296 if (blank) {
9297 xmlBufAdd(target, &blank, 1);
9298 blank = 0;
9299 }
9300 xmlBufAdd(target, source, 1);
9301 }
9302 source++;
9303 }
9304 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9305 xmlBufContent(target)));
9306 xmlBufFree(target);
9307 }
9308 xmlXPathReleaseObject(ctxt->context, obj);
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 len = 0, 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 len += l;
10527 NEXTL(l);
10528 c = CUR_CHAR(l);
10529 }
10530 ret = xmlStrndup(cur, ctxt->cur - cur);
10531 ctxt->cur = cur;
10532 return(ret);
10533 }
10534
10535 /**
10536 * xmlXPathCompPathExpr:
10537 * @ctxt: the XPath Parser context
10538 *
10539 * [19] PathExpr ::= LocationPath
10540 * | FilterExpr
10541 * | FilterExpr '/' RelativeLocationPath
10542 * | FilterExpr '//' RelativeLocationPath
10543 *
10544 * Compile a path expression.
10545 * The / operator and // operators combine an arbitrary expression
10546 * and a relative location path. It is an error if the expression
10547 * does not evaluate to a node-set.
10548 * The / operator does composition in the same way as when / is
10549 * used in a location path. As in location paths, // is short for
10550 * /descendant-or-self::node()/.
10551 */
10552
10553 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10554 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10555 int lc = 1; /* Should we branch to LocationPath ? */
10556 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10557
10558 SKIP_BLANKS;
10559 if ((CUR == '$') || (CUR == '(') ||
10560 (IS_ASCII_DIGIT(CUR)) ||
10561 (CUR == '\'') || (CUR == '"') ||
10562 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10563 lc = 0;
10564 } else if (CUR == '*') {
10565 /* relative or absolute location path */
10566 lc = 1;
10567 } else if (CUR == '/') {
10568 /* relative or absolute location path */
10569 lc = 1;
10570 } else if (CUR == '@') {
10571 /* relative abbreviated attribute location path */
10572 lc = 1;
10573 } else if (CUR == '.') {
10574 /* relative abbreviated attribute location path */
10575 lc = 1;
10576 } else {
10577 /*
10578 * Problem is finding if we have a name here whether it's:
10579 * - a nodetype
10580 * - a function call in which case it's followed by '('
10581 * - an axis in which case it's followed by ':'
10582 * - a element name
10583 * We do an a priori analysis here rather than having to
10584 * maintain parsed token content through the recursive function
10585 * calls. This looks uglier but makes the code easier to
10586 * read/write/debug.
10587 */
10588 SKIP_BLANKS;
10589 name = xmlXPathScanName(ctxt);
10590 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10591 #ifdef DEBUG_STEP
10592 xmlGenericError(xmlGenericErrorContext,
10593 "PathExpr: Axis\n");
10594 #endif
10595 lc = 1;
10596 xmlFree(name);
10597 } else if (name != NULL) {
10598 int len =xmlStrlen(name);
10599
10600
10601 while (NXT(len) != 0) {
10602 if (NXT(len) == '/') {
10603 /* element name */
10604 #ifdef DEBUG_STEP
10605 xmlGenericError(xmlGenericErrorContext,
10606 "PathExpr: AbbrRelLocation\n");
10607 #endif
10608 lc = 1;
10609 break;
10610 } else if (IS_BLANK_CH(NXT(len))) {
10611 /* ignore blanks */
10612 ;
10613 } else if (NXT(len) == ':') {
10614 #ifdef DEBUG_STEP
10615 xmlGenericError(xmlGenericErrorContext,
10616 "PathExpr: AbbrRelLocation\n");
10617 #endif
10618 lc = 1;
10619 break;
10620 } else if ((NXT(len) == '(')) {
10621 /* Node Type or Function */
10622 if (xmlXPathIsNodeType(name)) {
10623 #ifdef DEBUG_STEP
10624 xmlGenericError(xmlGenericErrorContext,
10625 "PathExpr: Type search\n");
10626 #endif
10627 lc = 1;
10628 #ifdef LIBXML_XPTR_ENABLED
10629 } else if (ctxt->xptr &&
10630 xmlStrEqual(name, BAD_CAST "range-to")) {
10631 lc = 1;
10632 #endif
10633 } else {
10634 #ifdef DEBUG_STEP
10635 xmlGenericError(xmlGenericErrorContext,
10636 "PathExpr: function call\n");
10637 #endif
10638 lc = 0;
10639 }
10640 break;
10641 } else if ((NXT(len) == '[')) {
10642 /* element name */
10643 #ifdef DEBUG_STEP
10644 xmlGenericError(xmlGenericErrorContext,
10645 "PathExpr: AbbrRelLocation\n");
10646 #endif
10647 lc = 1;
10648 break;
10649 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10650 (NXT(len) == '=')) {
10651 lc = 1;
10652 break;
10653 } else {
10654 lc = 1;
10655 break;
10656 }
10657 len++;
10658 }
10659 if (NXT(len) == 0) {
10660 #ifdef DEBUG_STEP
10661 xmlGenericError(xmlGenericErrorContext,
10662 "PathExpr: AbbrRelLocation\n");
10663 #endif
10664 /* element name */
10665 lc = 1;
10666 }
10667 xmlFree(name);
10668 } else {
10669 /* make sure all cases are covered explicitly */
10670 XP_ERROR(XPATH_EXPR_ERROR);
10671 }
10672 }
10673
10674 if (lc) {
10675 if (CUR == '/') {
10676 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10677 } else {
10678 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10679 }
10680 xmlXPathCompLocationPath(ctxt);
10681 } else {
10682 xmlXPathCompFilterExpr(ctxt);
10683 CHECK_ERROR;
10684 if ((CUR == '/') && (NXT(1) == '/')) {
10685 SKIP(2);
10686 SKIP_BLANKS;
10687
10688 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10689 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10690
10691 xmlXPathCompRelativeLocationPath(ctxt);
10692 } else if (CUR == '/') {
10693 xmlXPathCompRelativeLocationPath(ctxt);
10694 }
10695 }
10696 SKIP_BLANKS;
10697 }
10698
10699 /**
10700 * xmlXPathCompUnionExpr:
10701 * @ctxt: the XPath Parser context
10702 *
10703 * [18] UnionExpr ::= PathExpr
10704 * | UnionExpr '|' PathExpr
10705 *
10706 * Compile an union expression.
10707 */
10708
10709 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10710 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10711 xmlXPathCompPathExpr(ctxt);
10712 CHECK_ERROR;
10713 SKIP_BLANKS;
10714 while (CUR == '|') {
10715 int op1 = ctxt->comp->last;
10716 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10717
10718 NEXT;
10719 SKIP_BLANKS;
10720 xmlXPathCompPathExpr(ctxt);
10721
10722 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10723
10724 SKIP_BLANKS;
10725 }
10726 }
10727
10728 /**
10729 * xmlXPathCompUnaryExpr:
10730 * @ctxt: the XPath Parser context
10731 *
10732 * [27] UnaryExpr ::= UnionExpr
10733 * | '-' UnaryExpr
10734 *
10735 * Compile an unary expression.
10736 */
10737
10738 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10739 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10740 int minus = 0;
10741 int found = 0;
10742
10743 SKIP_BLANKS;
10744 while (CUR == '-') {
10745 minus = 1 - minus;
10746 found = 1;
10747 NEXT;
10748 SKIP_BLANKS;
10749 }
10750
10751 xmlXPathCompUnionExpr(ctxt);
10752 CHECK_ERROR;
10753 if (found) {
10754 if (minus)
10755 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10756 else
10757 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10758 }
10759 }
10760
10761 /**
10762 * xmlXPathCompMultiplicativeExpr:
10763 * @ctxt: the XPath Parser context
10764 *
10765 * [26] MultiplicativeExpr ::= UnaryExpr
10766 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10767 * | MultiplicativeExpr 'div' UnaryExpr
10768 * | MultiplicativeExpr 'mod' UnaryExpr
10769 * [34] MultiplyOperator ::= '*'
10770 *
10771 * Compile an Additive expression.
10772 */
10773
10774 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10775 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10776 xmlXPathCompUnaryExpr(ctxt);
10777 CHECK_ERROR;
10778 SKIP_BLANKS;
10779 while ((CUR == '*') ||
10780 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10781 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10782 int op = -1;
10783 int op1 = ctxt->comp->last;
10784
10785 if (CUR == '*') {
10786 op = 0;
10787 NEXT;
10788 } else if (CUR == 'd') {
10789 op = 1;
10790 SKIP(3);
10791 } else if (CUR == 'm') {
10792 op = 2;
10793 SKIP(3);
10794 }
10795 SKIP_BLANKS;
10796 xmlXPathCompUnaryExpr(ctxt);
10797 CHECK_ERROR;
10798 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10799 SKIP_BLANKS;
10800 }
10801 }
10802
10803 /**
10804 * xmlXPathCompAdditiveExpr:
10805 * @ctxt: the XPath Parser context
10806 *
10807 * [25] AdditiveExpr ::= MultiplicativeExpr
10808 * | AdditiveExpr '+' MultiplicativeExpr
10809 * | AdditiveExpr '-' MultiplicativeExpr
10810 *
10811 * Compile an Additive expression.
10812 */
10813
10814 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10815 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10816
10817 xmlXPathCompMultiplicativeExpr(ctxt);
10818 CHECK_ERROR;
10819 SKIP_BLANKS;
10820 while ((CUR == '+') || (CUR == '-')) {
10821 int plus;
10822 int op1 = ctxt->comp->last;
10823
10824 if (CUR == '+') plus = 1;
10825 else plus = 0;
10826 NEXT;
10827 SKIP_BLANKS;
10828 xmlXPathCompMultiplicativeExpr(ctxt);
10829 CHECK_ERROR;
10830 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10831 SKIP_BLANKS;
10832 }
10833 }
10834
10835 /**
10836 * xmlXPathCompRelationalExpr:
10837 * @ctxt: the XPath Parser context
10838 *
10839 * [24] RelationalExpr ::= AdditiveExpr
10840 * | RelationalExpr '<' AdditiveExpr
10841 * | RelationalExpr '>' AdditiveExpr
10842 * | RelationalExpr '<=' AdditiveExpr
10843 * | RelationalExpr '>=' AdditiveExpr
10844 *
10845 * A <= B > C is allowed ? Answer from James, yes with
10846 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10847 * which is basically what got implemented.
10848 *
10849 * Compile a Relational expression, then push the result
10850 * on the stack
10851 */
10852
10853 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10854 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10855 xmlXPathCompAdditiveExpr(ctxt);
10856 CHECK_ERROR;
10857 SKIP_BLANKS;
10858 while ((CUR == '<') || (CUR == '>')) {
10859 int inf, strict;
10860 int op1 = ctxt->comp->last;
10861
10862 if (CUR == '<') inf = 1;
10863 else inf = 0;
10864 if (NXT(1) == '=') strict = 0;
10865 else strict = 1;
10866 NEXT;
10867 if (!strict) NEXT;
10868 SKIP_BLANKS;
10869 xmlXPathCompAdditiveExpr(ctxt);
10870 CHECK_ERROR;
10871 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10872 SKIP_BLANKS;
10873 }
10874 }
10875
10876 /**
10877 * xmlXPathCompEqualityExpr:
10878 * @ctxt: the XPath Parser context
10879 *
10880 * [23] EqualityExpr ::= RelationalExpr
10881 * | EqualityExpr '=' RelationalExpr
10882 * | EqualityExpr '!=' RelationalExpr
10883 *
10884 * A != B != C is allowed ? Answer from James, yes with
10885 * (RelationalExpr = RelationalExpr) = RelationalExpr
10886 * (RelationalExpr != RelationalExpr) != RelationalExpr
10887 * which is basically what got implemented.
10888 *
10889 * Compile an Equality expression.
10890 *
10891 */
10892 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10893 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10894 xmlXPathCompRelationalExpr(ctxt);
10895 CHECK_ERROR;
10896 SKIP_BLANKS;
10897 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10898 int eq;
10899 int op1 = ctxt->comp->last;
10900
10901 if (CUR == '=') eq = 1;
10902 else eq = 0;
10903 NEXT;
10904 if (!eq) NEXT;
10905 SKIP_BLANKS;
10906 xmlXPathCompRelationalExpr(ctxt);
10907 CHECK_ERROR;
10908 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10909 SKIP_BLANKS;
10910 }
10911 }
10912
10913 /**
10914 * xmlXPathCompAndExpr:
10915 * @ctxt: the XPath Parser context
10916 *
10917 * [22] AndExpr ::= EqualityExpr
10918 * | AndExpr 'and' EqualityExpr
10919 *
10920 * Compile an AND expression.
10921 *
10922 */
10923 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10924 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10925 xmlXPathCompEqualityExpr(ctxt);
10926 CHECK_ERROR;
10927 SKIP_BLANKS;
10928 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10929 int op1 = ctxt->comp->last;
10930 SKIP(3);
10931 SKIP_BLANKS;
10932 xmlXPathCompEqualityExpr(ctxt);
10933 CHECK_ERROR;
10934 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10935 SKIP_BLANKS;
10936 }
10937 }
10938
10939 /**
10940 * xmlXPathCompileExpr:
10941 * @ctxt: the XPath Parser context
10942 *
10943 * [14] Expr ::= OrExpr
10944 * [21] OrExpr ::= AndExpr
10945 * | OrExpr 'or' AndExpr
10946 *
10947 * Parse and compile an expression
10948 */
10949 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)10950 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10951 xmlXPathContextPtr xpctxt = ctxt->context;
10952
10953 if (xpctxt != NULL) {
10954 if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10955 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10956 /*
10957 * Parsing a single '(' pushes about 10 functions on the call stack
10958 * before recursing!
10959 */
10960 xpctxt->depth += 10;
10961 }
10962
10963 xmlXPathCompAndExpr(ctxt);
10964 CHECK_ERROR;
10965 SKIP_BLANKS;
10966 while ((CUR == 'o') && (NXT(1) == 'r')) {
10967 int op1 = ctxt->comp->last;
10968 SKIP(2);
10969 SKIP_BLANKS;
10970 xmlXPathCompAndExpr(ctxt);
10971 CHECK_ERROR;
10972 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10973 SKIP_BLANKS;
10974 }
10975 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10976 /* more ops could be optimized too */
10977 /*
10978 * This is the main place to eliminate sorting for
10979 * operations which don't require a sorted node-set.
10980 * E.g. count().
10981 */
10982 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10983 }
10984
10985 if (xpctxt != NULL)
10986 xpctxt->depth -= 10;
10987 }
10988
10989 /**
10990 * xmlXPathCompPredicate:
10991 * @ctxt: the XPath Parser context
10992 * @filter: act as a filter
10993 *
10994 * [8] Predicate ::= '[' PredicateExpr ']'
10995 * [9] PredicateExpr ::= Expr
10996 *
10997 * Compile a predicate expression
10998 */
10999 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)11000 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11001 int op1 = ctxt->comp->last;
11002
11003 SKIP_BLANKS;
11004 if (CUR != '[') {
11005 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11006 }
11007 NEXT;
11008 SKIP_BLANKS;
11009
11010 ctxt->comp->last = -1;
11011 /*
11012 * This call to xmlXPathCompileExpr() will deactivate sorting
11013 * of the predicate result.
11014 * TODO: Sorting is still activated for filters, since I'm not
11015 * sure if needed. Normally sorting should not be needed, since
11016 * a filter can only diminish the number of items in a sequence,
11017 * but won't change its order; so if the initial sequence is sorted,
11018 * subsequent sorting is not needed.
11019 */
11020 if (! filter)
11021 xmlXPathCompileExpr(ctxt, 0);
11022 else
11023 xmlXPathCompileExpr(ctxt, 1);
11024 CHECK_ERROR;
11025
11026 if (CUR != ']') {
11027 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11028 }
11029
11030 if (filter)
11031 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11032 else
11033 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11034
11035 NEXT;
11036 SKIP_BLANKS;
11037 }
11038
11039 /**
11040 * xmlXPathCompNodeTest:
11041 * @ctxt: the XPath Parser context
11042 * @test: pointer to a xmlXPathTestVal
11043 * @type: pointer to a xmlXPathTypeVal
11044 * @prefix: placeholder for a possible name prefix
11045 *
11046 * [7] NodeTest ::= NameTest
11047 * | NodeType '(' ')'
11048 * | 'processing-instruction' '(' Literal ')'
11049 *
11050 * [37] NameTest ::= '*'
11051 * | NCName ':' '*'
11052 * | QName
11053 * [38] NodeType ::= 'comment'
11054 * | 'text'
11055 * | 'processing-instruction'
11056 * | 'node'
11057 *
11058 * Returns the name found and updates @test, @type and @prefix appropriately
11059 */
11060 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,xmlChar ** prefix,xmlChar * name)11061 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11062 xmlXPathTypeVal *type, xmlChar **prefix,
11063 xmlChar *name) {
11064 int blanks;
11065
11066 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11067 STRANGE;
11068 return(NULL);
11069 }
11070 *type = (xmlXPathTypeVal) 0;
11071 *test = (xmlXPathTestVal) 0;
11072 *prefix = NULL;
11073 SKIP_BLANKS;
11074
11075 if ((name == NULL) && (CUR == '*')) {
11076 /*
11077 * All elements
11078 */
11079 NEXT;
11080 *test = NODE_TEST_ALL;
11081 return(NULL);
11082 }
11083
11084 if (name == NULL)
11085 name = xmlXPathParseNCName(ctxt);
11086 if (name == NULL) {
11087 XP_ERRORNULL(XPATH_EXPR_ERROR);
11088 }
11089
11090 blanks = IS_BLANK_CH(CUR);
11091 SKIP_BLANKS;
11092 if (CUR == '(') {
11093 NEXT;
11094 /*
11095 * NodeType or PI search
11096 */
11097 if (xmlStrEqual(name, BAD_CAST "comment"))
11098 *type = NODE_TYPE_COMMENT;
11099 else if (xmlStrEqual(name, BAD_CAST "node"))
11100 *type = NODE_TYPE_NODE;
11101 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11102 *type = NODE_TYPE_PI;
11103 else if (xmlStrEqual(name, BAD_CAST "text"))
11104 *type = NODE_TYPE_TEXT;
11105 else {
11106 if (name != NULL)
11107 xmlFree(name);
11108 XP_ERRORNULL(XPATH_EXPR_ERROR);
11109 }
11110
11111 *test = NODE_TEST_TYPE;
11112
11113 SKIP_BLANKS;
11114 if (*type == NODE_TYPE_PI) {
11115 /*
11116 * Specific case: search a PI by name.
11117 */
11118 if (name != NULL)
11119 xmlFree(name);
11120 name = NULL;
11121 if (CUR != ')') {
11122 name = xmlXPathParseLiteral(ctxt);
11123 CHECK_ERROR NULL;
11124 *test = NODE_TEST_PI;
11125 SKIP_BLANKS;
11126 }
11127 }
11128 if (CUR != ')') {
11129 if (name != NULL)
11130 xmlFree(name);
11131 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11132 }
11133 NEXT;
11134 return(name);
11135 }
11136 *test = NODE_TEST_NAME;
11137 if ((!blanks) && (CUR == ':')) {
11138 NEXT;
11139
11140 /*
11141 * Since currently the parser context don't have a
11142 * namespace list associated:
11143 * The namespace name for this prefix can be computed
11144 * only at evaluation time. The compilation is done
11145 * outside of any context.
11146 */
11147 #if 0
11148 *prefix = xmlXPathNsLookup(ctxt->context, name);
11149 if (name != NULL)
11150 xmlFree(name);
11151 if (*prefix == NULL) {
11152 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11153 }
11154 #else
11155 *prefix = name;
11156 #endif
11157
11158 if (CUR == '*') {
11159 /*
11160 * All elements
11161 */
11162 NEXT;
11163 *test = NODE_TEST_ALL;
11164 return(NULL);
11165 }
11166
11167 name = xmlXPathParseNCName(ctxt);
11168 if (name == NULL) {
11169 XP_ERRORNULL(XPATH_EXPR_ERROR);
11170 }
11171 }
11172 return(name);
11173 }
11174
11175 /**
11176 * xmlXPathIsAxisName:
11177 * @name: a preparsed name token
11178 *
11179 * [6] AxisName ::= 'ancestor'
11180 * | 'ancestor-or-self'
11181 * | 'attribute'
11182 * | 'child'
11183 * | 'descendant'
11184 * | 'descendant-or-self'
11185 * | 'following'
11186 * | 'following-sibling'
11187 * | 'namespace'
11188 * | 'parent'
11189 * | 'preceding'
11190 * | 'preceding-sibling'
11191 * | 'self'
11192 *
11193 * Returns the axis or 0
11194 */
11195 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11196 xmlXPathIsAxisName(const xmlChar *name) {
11197 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11198 switch (name[0]) {
11199 case 'a':
11200 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11201 ret = AXIS_ANCESTOR;
11202 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11203 ret = AXIS_ANCESTOR_OR_SELF;
11204 if (xmlStrEqual(name, BAD_CAST "attribute"))
11205 ret = AXIS_ATTRIBUTE;
11206 break;
11207 case 'c':
11208 if (xmlStrEqual(name, BAD_CAST "child"))
11209 ret = AXIS_CHILD;
11210 break;
11211 case 'd':
11212 if (xmlStrEqual(name, BAD_CAST "descendant"))
11213 ret = AXIS_DESCENDANT;
11214 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11215 ret = AXIS_DESCENDANT_OR_SELF;
11216 break;
11217 case 'f':
11218 if (xmlStrEqual(name, BAD_CAST "following"))
11219 ret = AXIS_FOLLOWING;
11220 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11221 ret = AXIS_FOLLOWING_SIBLING;
11222 break;
11223 case 'n':
11224 if (xmlStrEqual(name, BAD_CAST "namespace"))
11225 ret = AXIS_NAMESPACE;
11226 break;
11227 case 'p':
11228 if (xmlStrEqual(name, BAD_CAST "parent"))
11229 ret = AXIS_PARENT;
11230 if (xmlStrEqual(name, BAD_CAST "preceding"))
11231 ret = AXIS_PRECEDING;
11232 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11233 ret = AXIS_PRECEDING_SIBLING;
11234 break;
11235 case 's':
11236 if (xmlStrEqual(name, BAD_CAST "self"))
11237 ret = AXIS_SELF;
11238 break;
11239 }
11240 return(ret);
11241 }
11242
11243 /**
11244 * xmlXPathCompStep:
11245 * @ctxt: the XPath Parser context
11246 *
11247 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11248 * | AbbreviatedStep
11249 *
11250 * [12] AbbreviatedStep ::= '.' | '..'
11251 *
11252 * [5] AxisSpecifier ::= AxisName '::'
11253 * | AbbreviatedAxisSpecifier
11254 *
11255 * [13] AbbreviatedAxisSpecifier ::= '@'?
11256 *
11257 * Modified for XPtr range support as:
11258 *
11259 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11260 * | AbbreviatedStep
11261 * | 'range-to' '(' Expr ')' Predicate*
11262 *
11263 * Compile one step in a Location Path
11264 * A location step of . is short for self::node(). This is
11265 * particularly useful in conjunction with //. For example, the
11266 * location path .//para is short for
11267 * self::node()/descendant-or-self::node()/child::para
11268 * and so will select all para descendant elements of the context
11269 * node.
11270 * Similarly, a location step of .. is short for parent::node().
11271 * For example, ../title is short for parent::node()/child::title
11272 * and so will select the title children of the parent of the context
11273 * node.
11274 */
11275 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11276 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11277 #ifdef LIBXML_XPTR_ENABLED
11278 int rangeto = 0;
11279 int op2 = -1;
11280 #endif
11281
11282 SKIP_BLANKS;
11283 if ((CUR == '.') && (NXT(1) == '.')) {
11284 SKIP(2);
11285 SKIP_BLANKS;
11286 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11287 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11288 } else if (CUR == '.') {
11289 NEXT;
11290 SKIP_BLANKS;
11291 } else {
11292 xmlChar *name = NULL;
11293 xmlChar *prefix = NULL;
11294 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11295 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11296 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11297 int op1;
11298
11299 /*
11300 * The modification needed for XPointer change to the production
11301 */
11302 #ifdef LIBXML_XPTR_ENABLED
11303 if (ctxt->xptr) {
11304 name = xmlXPathParseNCName(ctxt);
11305 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11306 op2 = ctxt->comp->last;
11307 xmlFree(name);
11308 SKIP_BLANKS;
11309 if (CUR != '(') {
11310 XP_ERROR(XPATH_EXPR_ERROR);
11311 }
11312 NEXT;
11313 SKIP_BLANKS;
11314
11315 xmlXPathCompileExpr(ctxt, 1);
11316 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11317 CHECK_ERROR;
11318
11319 SKIP_BLANKS;
11320 if (CUR != ')') {
11321 XP_ERROR(XPATH_EXPR_ERROR);
11322 }
11323 NEXT;
11324 rangeto = 1;
11325 goto eval_predicates;
11326 }
11327 }
11328 #endif
11329 if (CUR == '*') {
11330 axis = AXIS_CHILD;
11331 } else {
11332 if (name == NULL)
11333 name = xmlXPathParseNCName(ctxt);
11334 if (name != NULL) {
11335 axis = xmlXPathIsAxisName(name);
11336 if (axis != 0) {
11337 SKIP_BLANKS;
11338 if ((CUR == ':') && (NXT(1) == ':')) {
11339 SKIP(2);
11340 xmlFree(name);
11341 name = NULL;
11342 } else {
11343 /* an element name can conflict with an axis one :-\ */
11344 axis = AXIS_CHILD;
11345 }
11346 } else {
11347 axis = AXIS_CHILD;
11348 }
11349 } else if (CUR == '@') {
11350 NEXT;
11351 axis = AXIS_ATTRIBUTE;
11352 } else {
11353 axis = AXIS_CHILD;
11354 }
11355 }
11356
11357 if (ctxt->error != XPATH_EXPRESSION_OK) {
11358 xmlFree(name);
11359 return;
11360 }
11361
11362 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11363 if (test == 0)
11364 return;
11365
11366 if ((prefix != NULL) && (ctxt->context != NULL) &&
11367 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11368 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11369 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11370 }
11371 }
11372 #ifdef DEBUG_STEP
11373 xmlGenericError(xmlGenericErrorContext,
11374 "Basis : computing new set\n");
11375 #endif
11376
11377 #ifdef DEBUG_STEP
11378 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11379 if (ctxt->value == NULL)
11380 xmlGenericError(xmlGenericErrorContext, "no value\n");
11381 else if (ctxt->value->nodesetval == NULL)
11382 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11383 else
11384 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11385 #endif
11386
11387 #ifdef LIBXML_XPTR_ENABLED
11388 eval_predicates:
11389 #endif
11390 op1 = ctxt->comp->last;
11391 ctxt->comp->last = -1;
11392
11393 SKIP_BLANKS;
11394 while (CUR == '[') {
11395 xmlXPathCompPredicate(ctxt, 0);
11396 }
11397
11398 #ifdef LIBXML_XPTR_ENABLED
11399 if (rangeto) {
11400 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11401 } else
11402 #endif
11403 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11404 test, type, (void *)prefix, (void *)name) == -1) {
11405 xmlFree(prefix);
11406 xmlFree(name);
11407 }
11408 }
11409 #ifdef DEBUG_STEP
11410 xmlGenericError(xmlGenericErrorContext, "Step : ");
11411 if (ctxt->value == NULL)
11412 xmlGenericError(xmlGenericErrorContext, "no value\n");
11413 else if (ctxt->value->nodesetval == NULL)
11414 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11415 else
11416 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11417 ctxt->value->nodesetval);
11418 #endif
11419 }
11420
11421 /**
11422 * xmlXPathCompRelativeLocationPath:
11423 * @ctxt: the XPath Parser context
11424 *
11425 * [3] RelativeLocationPath ::= Step
11426 * | RelativeLocationPath '/' Step
11427 * | AbbreviatedRelativeLocationPath
11428 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11429 *
11430 * Compile a relative location path.
11431 */
11432 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11433 xmlXPathCompRelativeLocationPath
11434 (xmlXPathParserContextPtr ctxt) {
11435 SKIP_BLANKS;
11436 if ((CUR == '/') && (NXT(1) == '/')) {
11437 SKIP(2);
11438 SKIP_BLANKS;
11439 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11440 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11441 } else if (CUR == '/') {
11442 NEXT;
11443 SKIP_BLANKS;
11444 }
11445 xmlXPathCompStep(ctxt);
11446 CHECK_ERROR;
11447 SKIP_BLANKS;
11448 while (CUR == '/') {
11449 if ((CUR == '/') && (NXT(1) == '/')) {
11450 SKIP(2);
11451 SKIP_BLANKS;
11452 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11453 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11454 xmlXPathCompStep(ctxt);
11455 } else if (CUR == '/') {
11456 NEXT;
11457 SKIP_BLANKS;
11458 xmlXPathCompStep(ctxt);
11459 }
11460 SKIP_BLANKS;
11461 }
11462 }
11463
11464 /**
11465 * xmlXPathCompLocationPath:
11466 * @ctxt: the XPath Parser context
11467 *
11468 * [1] LocationPath ::= RelativeLocationPath
11469 * | AbsoluteLocationPath
11470 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11471 * | AbbreviatedAbsoluteLocationPath
11472 * [10] AbbreviatedAbsoluteLocationPath ::=
11473 * '//' RelativeLocationPath
11474 *
11475 * Compile a location path
11476 *
11477 * // is short for /descendant-or-self::node()/. For example,
11478 * //para is short for /descendant-or-self::node()/child::para and
11479 * so will select any para element in the document (even a para element
11480 * that is a document element will be selected by //para since the
11481 * document element node is a child of the root node); div//para is
11482 * short for div/descendant-or-self::node()/child::para and so will
11483 * select all para descendants of div children.
11484 */
11485 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11486 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11487 SKIP_BLANKS;
11488 if (CUR != '/') {
11489 xmlXPathCompRelativeLocationPath(ctxt);
11490 } else {
11491 while (CUR == '/') {
11492 if ((CUR == '/') && (NXT(1) == '/')) {
11493 SKIP(2);
11494 SKIP_BLANKS;
11495 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11496 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11497 xmlXPathCompRelativeLocationPath(ctxt);
11498 } else if (CUR == '/') {
11499 NEXT;
11500 SKIP_BLANKS;
11501 if ((CUR != 0 ) &&
11502 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11503 (CUR == '@') || (CUR == '*')))
11504 xmlXPathCompRelativeLocationPath(ctxt);
11505 }
11506 CHECK_ERROR;
11507 }
11508 }
11509 }
11510
11511 /************************************************************************
11512 * *
11513 * XPath precompiled expression evaluation *
11514 * *
11515 ************************************************************************/
11516
11517 static int
11518 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11519
11520 #ifdef DEBUG_STEP
11521 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11522 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11523 int nbNodes)
11524 {
11525 xmlGenericError(xmlGenericErrorContext, "new step : ");
11526 switch (op->value) {
11527 case AXIS_ANCESTOR:
11528 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11529 break;
11530 case AXIS_ANCESTOR_OR_SELF:
11531 xmlGenericError(xmlGenericErrorContext,
11532 "axis 'ancestors-or-self' ");
11533 break;
11534 case AXIS_ATTRIBUTE:
11535 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11536 break;
11537 case AXIS_CHILD:
11538 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11539 break;
11540 case AXIS_DESCENDANT:
11541 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11542 break;
11543 case AXIS_DESCENDANT_OR_SELF:
11544 xmlGenericError(xmlGenericErrorContext,
11545 "axis 'descendant-or-self' ");
11546 break;
11547 case AXIS_FOLLOWING:
11548 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11549 break;
11550 case AXIS_FOLLOWING_SIBLING:
11551 xmlGenericError(xmlGenericErrorContext,
11552 "axis 'following-siblings' ");
11553 break;
11554 case AXIS_NAMESPACE:
11555 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11556 break;
11557 case AXIS_PARENT:
11558 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11559 break;
11560 case AXIS_PRECEDING:
11561 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11562 break;
11563 case AXIS_PRECEDING_SIBLING:
11564 xmlGenericError(xmlGenericErrorContext,
11565 "axis 'preceding-sibling' ");
11566 break;
11567 case AXIS_SELF:
11568 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11569 break;
11570 }
11571 xmlGenericError(xmlGenericErrorContext,
11572 " context contains %d nodes\n", nbNodes);
11573 switch (op->value2) {
11574 case NODE_TEST_NONE:
11575 xmlGenericError(xmlGenericErrorContext,
11576 " searching for none !!!\n");
11577 break;
11578 case NODE_TEST_TYPE:
11579 xmlGenericError(xmlGenericErrorContext,
11580 " searching for type %d\n", op->value3);
11581 break;
11582 case NODE_TEST_PI:
11583 xmlGenericError(xmlGenericErrorContext,
11584 " searching for PI !!!\n");
11585 break;
11586 case NODE_TEST_ALL:
11587 xmlGenericError(xmlGenericErrorContext,
11588 " searching for *\n");
11589 break;
11590 case NODE_TEST_NS:
11591 xmlGenericError(xmlGenericErrorContext,
11592 " searching for namespace %s\n",
11593 op->value5);
11594 break;
11595 case NODE_TEST_NAME:
11596 xmlGenericError(xmlGenericErrorContext,
11597 " searching for name %s\n", op->value5);
11598 if (op->value4)
11599 xmlGenericError(xmlGenericErrorContext,
11600 " with namespace %s\n", op->value4);
11601 break;
11602 }
11603 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11604 }
11605 #endif /* DEBUG_STEP */
11606
11607 /**
11608 * xmlXPathNodeSetFilter:
11609 * @ctxt: the XPath Parser context
11610 * @set: the node set to filter
11611 * @filterOpIndex: the index of the predicate/filter op
11612 * @minPos: minimum position in the filtered set (1-based)
11613 * @maxPos: maximum position in the filtered set (1-based)
11614 * @hasNsNodes: true if the node set may contain namespace nodes
11615 *
11616 * Filter a node set, keeping only nodes for which the predicate expression
11617 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11618 * filtered result.
11619 */
11620 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)11621 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11622 xmlNodeSetPtr set,
11623 int filterOpIndex,
11624 int minPos, int maxPos,
11625 int hasNsNodes)
11626 {
11627 xmlXPathContextPtr xpctxt;
11628 xmlNodePtr oldnode;
11629 xmlDocPtr olddoc;
11630 xmlXPathStepOpPtr filterOp;
11631 int oldcs, oldpp;
11632 int i, j, pos;
11633
11634 if ((set == NULL) || (set->nodeNr == 0))
11635 return;
11636
11637 /*
11638 * Check if the node set contains a sufficient number of nodes for
11639 * the requested range.
11640 */
11641 if (set->nodeNr < minPos) {
11642 xmlXPathNodeSetClear(set, hasNsNodes);
11643 return;
11644 }
11645
11646 xpctxt = ctxt->context;
11647 oldnode = xpctxt->node;
11648 olddoc = xpctxt->doc;
11649 oldcs = xpctxt->contextSize;
11650 oldpp = xpctxt->proximityPosition;
11651 filterOp = &ctxt->comp->steps[filterOpIndex];
11652
11653 xpctxt->contextSize = set->nodeNr;
11654
11655 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11656 xmlNodePtr node = set->nodeTab[i];
11657 int res;
11658
11659 xpctxt->node = node;
11660 xpctxt->proximityPosition = i + 1;
11661
11662 /*
11663 * Also set the xpath document in case things like
11664 * key() are evaluated in the predicate.
11665 *
11666 * TODO: Get real doc for namespace nodes.
11667 */
11668 if ((node->type != XML_NAMESPACE_DECL) &&
11669 (node->doc != NULL))
11670 xpctxt->doc = node->doc;
11671
11672 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11673
11674 if (ctxt->error != XPATH_EXPRESSION_OK)
11675 break;
11676 if (res < 0) {
11677 /* Shouldn't happen */
11678 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11679 break;
11680 }
11681
11682 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11683 if (i != j) {
11684 set->nodeTab[j] = node;
11685 set->nodeTab[i] = NULL;
11686 }
11687
11688 j += 1;
11689 } else {
11690 /* Remove the entry from the initial node set. */
11691 set->nodeTab[i] = NULL;
11692 if (node->type == XML_NAMESPACE_DECL)
11693 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11694 }
11695
11696 if (res != 0) {
11697 if (pos == maxPos) {
11698 i += 1;
11699 break;
11700 }
11701
11702 pos += 1;
11703 }
11704 }
11705
11706 /* Free remaining nodes. */
11707 if (hasNsNodes) {
11708 for (; i < set->nodeNr; i++) {
11709 xmlNodePtr node = set->nodeTab[i];
11710 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11711 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11712 }
11713 }
11714
11715 set->nodeNr = j;
11716
11717 /* If too many elements were removed, shrink table to preserve memory. */
11718 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11719 (set->nodeNr < set->nodeMax / 2)) {
11720 xmlNodePtr *tmp;
11721 int nodeMax = set->nodeNr;
11722
11723 if (nodeMax < XML_NODESET_DEFAULT)
11724 nodeMax = XML_NODESET_DEFAULT;
11725 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11726 nodeMax * sizeof(xmlNodePtr));
11727 if (tmp == NULL) {
11728 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11729 } else {
11730 set->nodeTab = tmp;
11731 set->nodeMax = nodeMax;
11732 }
11733 }
11734
11735 xpctxt->node = oldnode;
11736 xpctxt->doc = olddoc;
11737 xpctxt->contextSize = oldcs;
11738 xpctxt->proximityPosition = oldpp;
11739 }
11740
11741 #ifdef LIBXML_XPTR_ENABLED
11742 /**
11743 * xmlXPathLocationSetFilter:
11744 * @ctxt: the XPath Parser context
11745 * @locset: the location set to filter
11746 * @filterOpIndex: the index of the predicate/filter op
11747 * @minPos: minimum position in the filtered set (1-based)
11748 * @maxPos: maximum position in the filtered set (1-based)
11749 *
11750 * Filter a location set, keeping only nodes for which the predicate
11751 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11752 * in the filtered result.
11753 */
11754 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)11755 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11756 xmlLocationSetPtr locset,
11757 int filterOpIndex,
11758 int minPos, int maxPos)
11759 {
11760 xmlXPathContextPtr xpctxt;
11761 xmlNodePtr oldnode;
11762 xmlDocPtr olddoc;
11763 xmlXPathStepOpPtr filterOp;
11764 int oldcs, oldpp;
11765 int i, j, pos;
11766
11767 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11768 return;
11769
11770 xpctxt = ctxt->context;
11771 oldnode = xpctxt->node;
11772 olddoc = xpctxt->doc;
11773 oldcs = xpctxt->contextSize;
11774 oldpp = xpctxt->proximityPosition;
11775 filterOp = &ctxt->comp->steps[filterOpIndex];
11776
11777 xpctxt->contextSize = locset->locNr;
11778
11779 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11780 xmlNodePtr contextNode = locset->locTab[i]->user;
11781 int res;
11782
11783 xpctxt->node = contextNode;
11784 xpctxt->proximityPosition = i + 1;
11785
11786 /*
11787 * Also set the xpath document in case things like
11788 * key() are evaluated in the predicate.
11789 *
11790 * TODO: Get real doc for namespace nodes.
11791 */
11792 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11793 (contextNode->doc != NULL))
11794 xpctxt->doc = contextNode->doc;
11795
11796 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11797
11798 if (ctxt->error != XPATH_EXPRESSION_OK)
11799 break;
11800 if (res < 0) {
11801 /* Shouldn't happen */
11802 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11803 break;
11804 }
11805
11806 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11807 if (i != j) {
11808 locset->locTab[j] = locset->locTab[i];
11809 locset->locTab[i] = NULL;
11810 }
11811
11812 j += 1;
11813 } else {
11814 /* Remove the entry from the initial location set. */
11815 xmlXPathFreeObject(locset->locTab[i]);
11816 locset->locTab[i] = NULL;
11817 }
11818
11819 if (res != 0) {
11820 if (pos == maxPos) {
11821 i += 1;
11822 break;
11823 }
11824
11825 pos += 1;
11826 }
11827 }
11828
11829 /* Free remaining nodes. */
11830 for (; i < locset->locNr; i++)
11831 xmlXPathFreeObject(locset->locTab[i]);
11832
11833 locset->locNr = j;
11834
11835 /* If too many elements were removed, shrink table to preserve memory. */
11836 if ((locset->locMax > XML_NODESET_DEFAULT) &&
11837 (locset->locNr < locset->locMax / 2)) {
11838 xmlXPathObjectPtr *tmp;
11839 int locMax = locset->locNr;
11840
11841 if (locMax < XML_NODESET_DEFAULT)
11842 locMax = XML_NODESET_DEFAULT;
11843 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11844 locMax * sizeof(xmlXPathObjectPtr));
11845 if (tmp == NULL) {
11846 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11847 } else {
11848 locset->locTab = tmp;
11849 locset->locMax = locMax;
11850 }
11851 }
11852
11853 xpctxt->node = oldnode;
11854 xpctxt->doc = olddoc;
11855 xpctxt->contextSize = oldcs;
11856 xpctxt->proximityPosition = oldpp;
11857 }
11858 #endif /* LIBXML_XPTR_ENABLED */
11859
11860 /**
11861 * xmlXPathCompOpEvalPredicate:
11862 * @ctxt: the XPath Parser context
11863 * @op: the predicate op
11864 * @set: the node set to filter
11865 * @minPos: minimum position in the filtered set (1-based)
11866 * @maxPos: maximum position in the filtered set (1-based)
11867 * @hasNsNodes: true if the node set may contain namespace nodes
11868 *
11869 * Filter a node set, keeping only nodes for which the sequence of predicate
11870 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11871 * in the filtered result.
11872 */
11873 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)11874 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11875 xmlXPathStepOpPtr op,
11876 xmlNodeSetPtr set,
11877 int minPos, int maxPos,
11878 int hasNsNodes)
11879 {
11880 if (op->ch1 != -1) {
11881 xmlXPathCompExprPtr comp = ctxt->comp;
11882 /*
11883 * Process inner predicates first.
11884 */
11885 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11886 xmlGenericError(xmlGenericErrorContext,
11887 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11888 XP_ERROR(XPATH_INVALID_OPERAND);
11889 }
11890 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11891 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11892 ctxt->context->depth += 1;
11893 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11894 1, set->nodeNr, hasNsNodes);
11895 ctxt->context->depth -= 1;
11896 CHECK_ERROR;
11897 }
11898
11899 if (op->ch2 != -1)
11900 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11901 }
11902
11903 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11904 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11905 xmlXPathStepOpPtr op,
11906 int *maxPos)
11907 {
11908
11909 xmlXPathStepOpPtr exprOp;
11910
11911 /*
11912 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11913 */
11914
11915 /*
11916 * If not -1, then ch1 will point to:
11917 * 1) For predicates (XPATH_OP_PREDICATE):
11918 * - an inner predicate operator
11919 * 2) For filters (XPATH_OP_FILTER):
11920 * - an inner filter operator OR
11921 * - an expression selecting the node set.
11922 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11923 */
11924 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11925 return(0);
11926
11927 if (op->ch2 != -1) {
11928 exprOp = &ctxt->comp->steps[op->ch2];
11929 } else
11930 return(0);
11931
11932 if ((exprOp != NULL) &&
11933 (exprOp->op == XPATH_OP_VALUE) &&
11934 (exprOp->value4 != NULL) &&
11935 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11936 {
11937 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11938
11939 /*
11940 * We have a "[n]" predicate here.
11941 * TODO: Unfortunately this simplistic test here is not
11942 * able to detect a position() predicate in compound
11943 * expressions like "[@attr = 'a" and position() = 1],
11944 * and even not the usage of position() in
11945 * "[position() = 1]"; thus - obviously - a position-range,
11946 * like it "[position() < 5]", is also not detected.
11947 * Maybe we could rewrite the AST to ease the optimization.
11948 */
11949
11950 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11951 *maxPos = (int) floatval;
11952 if (floatval == (double) *maxPos)
11953 return(1);
11954 }
11955 }
11956 return(0);
11957 }
11958
11959 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11960 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11961 xmlXPathStepOpPtr op,
11962 xmlNodePtr * first, xmlNodePtr * last,
11963 int toBool)
11964 {
11965
11966 #define XP_TEST_HIT \
11967 if (hasAxisRange != 0) { \
11968 if (++pos == maxPos) { \
11969 if (addNode(seq, cur) < 0) \
11970 ctxt->error = XPATH_MEMORY_ERROR; \
11971 goto axis_range_end; } \
11972 } else { \
11973 if (addNode(seq, cur) < 0) \
11974 ctxt->error = XPATH_MEMORY_ERROR; \
11975 if (breakOnFirstHit) goto first_hit; }
11976
11977 #define XP_TEST_HIT_NS \
11978 if (hasAxisRange != 0) { \
11979 if (++pos == maxPos) { \
11980 hasNsNodes = 1; \
11981 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11982 ctxt->error = XPATH_MEMORY_ERROR; \
11983 goto axis_range_end; } \
11984 } else { \
11985 hasNsNodes = 1; \
11986 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11987 ctxt->error = XPATH_MEMORY_ERROR; \
11988 if (breakOnFirstHit) goto first_hit; }
11989
11990 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11991 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11992 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11993 const xmlChar *prefix = op->value4;
11994 const xmlChar *name = op->value5;
11995 const xmlChar *URI = NULL;
11996
11997 #ifdef DEBUG_STEP
11998 int nbMatches = 0, prevMatches = 0;
11999 #endif
12000 int total = 0, hasNsNodes = 0;
12001 /* The popped object holding the context nodes */
12002 xmlXPathObjectPtr obj;
12003 /* The set of context nodes for the node tests */
12004 xmlNodeSetPtr contextSeq;
12005 int contextIdx;
12006 xmlNodePtr contextNode;
12007 /* The final resulting node set wrt to all context nodes */
12008 xmlNodeSetPtr outSeq;
12009 /*
12010 * The temporary resulting node set wrt 1 context node.
12011 * Used to feed predicate evaluation.
12012 */
12013 xmlNodeSetPtr seq;
12014 xmlNodePtr cur;
12015 /* First predicate operator */
12016 xmlXPathStepOpPtr predOp;
12017 int maxPos; /* The requested position() (when a "[n]" predicate) */
12018 int hasPredicateRange, hasAxisRange, pos;
12019 int breakOnFirstHit;
12020
12021 xmlXPathTraversalFunction next = NULL;
12022 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12023 xmlXPathNodeSetMergeFunction mergeAndClear;
12024 xmlNodePtr oldContextNode;
12025 xmlXPathContextPtr xpctxt = ctxt->context;
12026
12027
12028 CHECK_TYPE0(XPATH_NODESET);
12029 obj = valuePop(ctxt);
12030 /*
12031 * Setup namespaces.
12032 */
12033 if (prefix != NULL) {
12034 URI = xmlXPathNsLookup(xpctxt, prefix);
12035 if (URI == NULL) {
12036 xmlXPathReleaseObject(xpctxt, obj);
12037 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12038 }
12039 }
12040 /*
12041 * Setup axis.
12042 *
12043 * MAYBE FUTURE TODO: merging optimizations:
12044 * - If the nodes to be traversed wrt to the initial nodes and
12045 * the current axis cannot overlap, then we could avoid searching
12046 * for duplicates during the merge.
12047 * But the question is how/when to evaluate if they cannot overlap.
12048 * Example: if we know that for two initial nodes, the one is
12049 * not in the ancestor-or-self axis of the other, then we could safely
12050 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12051 * the descendant-or-self axis.
12052 */
12053 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12054 switch (axis) {
12055 case AXIS_ANCESTOR:
12056 first = NULL;
12057 next = xmlXPathNextAncestor;
12058 break;
12059 case AXIS_ANCESTOR_OR_SELF:
12060 first = NULL;
12061 next = xmlXPathNextAncestorOrSelf;
12062 break;
12063 case AXIS_ATTRIBUTE:
12064 first = NULL;
12065 last = NULL;
12066 next = xmlXPathNextAttribute;
12067 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12068 break;
12069 case AXIS_CHILD:
12070 last = NULL;
12071 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12072 (type == NODE_TYPE_NODE))
12073 {
12074 /*
12075 * Optimization if an element node type is 'element'.
12076 */
12077 next = xmlXPathNextChildElement;
12078 } else
12079 next = xmlXPathNextChild;
12080 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12081 break;
12082 case AXIS_DESCENDANT:
12083 last = NULL;
12084 next = xmlXPathNextDescendant;
12085 break;
12086 case AXIS_DESCENDANT_OR_SELF:
12087 last = NULL;
12088 next = xmlXPathNextDescendantOrSelf;
12089 break;
12090 case AXIS_FOLLOWING:
12091 last = NULL;
12092 next = xmlXPathNextFollowing;
12093 break;
12094 case AXIS_FOLLOWING_SIBLING:
12095 last = NULL;
12096 next = xmlXPathNextFollowingSibling;
12097 break;
12098 case AXIS_NAMESPACE:
12099 first = NULL;
12100 last = NULL;
12101 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12102 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12103 break;
12104 case AXIS_PARENT:
12105 first = NULL;
12106 next = xmlXPathNextParent;
12107 break;
12108 case AXIS_PRECEDING:
12109 first = NULL;
12110 next = xmlXPathNextPrecedingInternal;
12111 break;
12112 case AXIS_PRECEDING_SIBLING:
12113 first = NULL;
12114 next = xmlXPathNextPrecedingSibling;
12115 break;
12116 case AXIS_SELF:
12117 first = NULL;
12118 last = NULL;
12119 next = xmlXPathNextSelf;
12120 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12121 break;
12122 }
12123
12124 #ifdef DEBUG_STEP
12125 xmlXPathDebugDumpStepAxis(op,
12126 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12127 #endif
12128
12129 if (next == NULL) {
12130 xmlXPathReleaseObject(xpctxt, obj);
12131 return(0);
12132 }
12133 contextSeq = obj->nodesetval;
12134 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12135 xmlXPathReleaseObject(xpctxt, obj);
12136 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12137 return(0);
12138 }
12139 /*
12140 * Predicate optimization ---------------------------------------------
12141 * If this step has a last predicate, which contains a position(),
12142 * then we'll optimize (although not exactly "position()", but only
12143 * the short-hand form, i.e., "[n]".
12144 *
12145 * Example - expression "/foo[parent::bar][1]":
12146 *
12147 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12148 * ROOT -- op->ch1
12149 * PREDICATE -- op->ch2 (predOp)
12150 * PREDICATE -- predOp->ch1 = [parent::bar]
12151 * SORT
12152 * COLLECT 'parent' 'name' 'node' bar
12153 * NODE
12154 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12155 *
12156 */
12157 maxPos = 0;
12158 predOp = NULL;
12159 hasPredicateRange = 0;
12160 hasAxisRange = 0;
12161 if (op->ch2 != -1) {
12162 /*
12163 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12164 */
12165 predOp = &ctxt->comp->steps[op->ch2];
12166 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12167 if (predOp->ch1 != -1) {
12168 /*
12169 * Use the next inner predicate operator.
12170 */
12171 predOp = &ctxt->comp->steps[predOp->ch1];
12172 hasPredicateRange = 1;
12173 } else {
12174 /*
12175 * There's no other predicate than the [n] predicate.
12176 */
12177 predOp = NULL;
12178 hasAxisRange = 1;
12179 }
12180 }
12181 }
12182 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12183 /*
12184 * Axis traversal -----------------------------------------------------
12185 */
12186 /*
12187 * 2.3 Node Tests
12188 * - For the attribute axis, the principal node type is attribute.
12189 * - For the namespace axis, the principal node type is namespace.
12190 * - For other axes, the principal node type is element.
12191 *
12192 * A node test * is true for any node of the
12193 * principal node type. For example, child::* will
12194 * select all element children of the context node
12195 */
12196 oldContextNode = xpctxt->node;
12197 addNode = xmlXPathNodeSetAddUnique;
12198 outSeq = NULL;
12199 seq = NULL;
12200 contextNode = NULL;
12201 contextIdx = 0;
12202
12203
12204 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12205 (ctxt->error == XPATH_EXPRESSION_OK)) {
12206 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12207
12208 if (seq == NULL) {
12209 seq = xmlXPathNodeSetCreate(NULL);
12210 if (seq == NULL) {
12211 /* TODO: Propagate memory error. */
12212 total = 0;
12213 goto error;
12214 }
12215 }
12216 /*
12217 * Traverse the axis and test the nodes.
12218 */
12219 pos = 0;
12220 cur = NULL;
12221 hasNsNodes = 0;
12222 do {
12223 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12224 goto error;
12225
12226 cur = next(ctxt, cur);
12227 if (cur == NULL)
12228 break;
12229
12230 /*
12231 * QUESTION TODO: What does the "first" and "last" stuff do?
12232 */
12233 if ((first != NULL) && (*first != NULL)) {
12234 if (*first == cur)
12235 break;
12236 if (((total % 256) == 0) &&
12237 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12238 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12239 #else
12240 (xmlXPathCmpNodes(*first, cur) >= 0))
12241 #endif
12242 {
12243 break;
12244 }
12245 }
12246 if ((last != NULL) && (*last != NULL)) {
12247 if (*last == cur)
12248 break;
12249 if (((total % 256) == 0) &&
12250 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12251 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12252 #else
12253 (xmlXPathCmpNodes(cur, *last) >= 0))
12254 #endif
12255 {
12256 break;
12257 }
12258 }
12259
12260 total++;
12261
12262 #ifdef DEBUG_STEP
12263 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12264 #endif
12265
12266 switch (test) {
12267 case NODE_TEST_NONE:
12268 total = 0;
12269 STRANGE
12270 goto error;
12271 case NODE_TEST_TYPE:
12272 if (type == NODE_TYPE_NODE) {
12273 switch (cur->type) {
12274 case XML_DOCUMENT_NODE:
12275 case XML_HTML_DOCUMENT_NODE:
12276 #ifdef LIBXML_DOCB_ENABLED
12277 case XML_DOCB_DOCUMENT_NODE:
12278 #endif
12279 case XML_ELEMENT_NODE:
12280 case XML_ATTRIBUTE_NODE:
12281 case XML_PI_NODE:
12282 case XML_COMMENT_NODE:
12283 case XML_CDATA_SECTION_NODE:
12284 case XML_TEXT_NODE:
12285 XP_TEST_HIT
12286 break;
12287 case XML_NAMESPACE_DECL: {
12288 if (axis == AXIS_NAMESPACE) {
12289 XP_TEST_HIT_NS
12290 } else {
12291 hasNsNodes = 1;
12292 XP_TEST_HIT
12293 }
12294 break;
12295 }
12296 default:
12297 break;
12298 }
12299 } else if (cur->type == (xmlElementType) type) {
12300 if (cur->type == XML_NAMESPACE_DECL)
12301 XP_TEST_HIT_NS
12302 else
12303 XP_TEST_HIT
12304 } else if ((type == NODE_TYPE_TEXT) &&
12305 (cur->type == XML_CDATA_SECTION_NODE))
12306 {
12307 XP_TEST_HIT
12308 }
12309 break;
12310 case NODE_TEST_PI:
12311 if ((cur->type == XML_PI_NODE) &&
12312 ((name == NULL) || xmlStrEqual(name, cur->name)))
12313 {
12314 XP_TEST_HIT
12315 }
12316 break;
12317 case NODE_TEST_ALL:
12318 if (axis == AXIS_ATTRIBUTE) {
12319 if (cur->type == XML_ATTRIBUTE_NODE)
12320 {
12321 if (prefix == NULL)
12322 {
12323 XP_TEST_HIT
12324 } else if ((cur->ns != NULL) &&
12325 (xmlStrEqual(URI, cur->ns->href)))
12326 {
12327 XP_TEST_HIT
12328 }
12329 }
12330 } else if (axis == AXIS_NAMESPACE) {
12331 if (cur->type == XML_NAMESPACE_DECL)
12332 {
12333 XP_TEST_HIT_NS
12334 }
12335 } else {
12336 if (cur->type == XML_ELEMENT_NODE) {
12337 if (prefix == NULL)
12338 {
12339 XP_TEST_HIT
12340
12341 } else if ((cur->ns != NULL) &&
12342 (xmlStrEqual(URI, cur->ns->href)))
12343 {
12344 XP_TEST_HIT
12345 }
12346 }
12347 }
12348 break;
12349 case NODE_TEST_NS:{
12350 TODO;
12351 break;
12352 }
12353 case NODE_TEST_NAME:
12354 if (axis == AXIS_ATTRIBUTE) {
12355 if (cur->type != XML_ATTRIBUTE_NODE)
12356 break;
12357 } else if (axis == AXIS_NAMESPACE) {
12358 if (cur->type != XML_NAMESPACE_DECL)
12359 break;
12360 } else {
12361 if (cur->type != XML_ELEMENT_NODE)
12362 break;
12363 }
12364 switch (cur->type) {
12365 case XML_ELEMENT_NODE:
12366 if (xmlStrEqual(name, cur->name)) {
12367 if (prefix == NULL) {
12368 if (cur->ns == NULL)
12369 {
12370 XP_TEST_HIT
12371 }
12372 } else {
12373 if ((cur->ns != NULL) &&
12374 (xmlStrEqual(URI, cur->ns->href)))
12375 {
12376 XP_TEST_HIT
12377 }
12378 }
12379 }
12380 break;
12381 case XML_ATTRIBUTE_NODE:{
12382 xmlAttrPtr attr = (xmlAttrPtr) cur;
12383
12384 if (xmlStrEqual(name, attr->name)) {
12385 if (prefix == NULL) {
12386 if ((attr->ns == NULL) ||
12387 (attr->ns->prefix == NULL))
12388 {
12389 XP_TEST_HIT
12390 }
12391 } else {
12392 if ((attr->ns != NULL) &&
12393 (xmlStrEqual(URI,
12394 attr->ns->href)))
12395 {
12396 XP_TEST_HIT
12397 }
12398 }
12399 }
12400 break;
12401 }
12402 case XML_NAMESPACE_DECL:
12403 if (cur->type == XML_NAMESPACE_DECL) {
12404 xmlNsPtr ns = (xmlNsPtr) cur;
12405
12406 if ((ns->prefix != NULL) && (name != NULL)
12407 && (xmlStrEqual(ns->prefix, name)))
12408 {
12409 XP_TEST_HIT_NS
12410 }
12411 }
12412 break;
12413 default:
12414 break;
12415 }
12416 break;
12417 } /* switch(test) */
12418 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12419
12420 goto apply_predicates;
12421
12422 axis_range_end: /* ----------------------------------------------------- */
12423 /*
12424 * We have a "/foo[n]", and position() = n was reached.
12425 * Note that we can have as well "/foo/::parent::foo[1]", so
12426 * a duplicate-aware merge is still needed.
12427 * Merge with the result.
12428 */
12429 if (outSeq == NULL) {
12430 outSeq = seq;
12431 seq = NULL;
12432 } else
12433 /* TODO: Check memory error. */
12434 outSeq = mergeAndClear(outSeq, seq);
12435 /*
12436 * Break if only a true/false result was requested.
12437 */
12438 if (toBool)
12439 break;
12440 continue;
12441
12442 first_hit: /* ---------------------------------------------------------- */
12443 /*
12444 * Break if only a true/false result was requested and
12445 * no predicates existed and a node test succeeded.
12446 */
12447 if (outSeq == NULL) {
12448 outSeq = seq;
12449 seq = NULL;
12450 } else
12451 /* TODO: Check memory error. */
12452 outSeq = mergeAndClear(outSeq, seq);
12453 break;
12454
12455 #ifdef DEBUG_STEP
12456 if (seq != NULL)
12457 nbMatches += seq->nodeNr;
12458 #endif
12459
12460 apply_predicates: /* --------------------------------------------------- */
12461 if (ctxt->error != XPATH_EXPRESSION_OK)
12462 goto error;
12463
12464 /*
12465 * Apply predicates.
12466 */
12467 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12468 /*
12469 * E.g. when we have a "/foo[some expression][n]".
12470 */
12471 /*
12472 * QUESTION TODO: The old predicate evaluation took into
12473 * account location-sets.
12474 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12475 * Do we expect such a set here?
12476 * All what I learned now from the evaluation semantics
12477 * does not indicate that a location-set will be processed
12478 * here, so this looks OK.
12479 */
12480 /*
12481 * Iterate over all predicates, starting with the outermost
12482 * predicate.
12483 * TODO: Problem: we cannot execute the inner predicates first
12484 * since we cannot go back *up* the operator tree!
12485 * Options we have:
12486 * 1) Use of recursive functions (like is it currently done
12487 * via xmlXPathCompOpEval())
12488 * 2) Add a predicate evaluation information stack to the
12489 * context struct
12490 * 3) Change the way the operators are linked; we need a
12491 * "parent" field on xmlXPathStepOp
12492 *
12493 * For the moment, I'll try to solve this with a recursive
12494 * function: xmlXPathCompOpEvalPredicate().
12495 */
12496 if (hasPredicateRange != 0)
12497 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12498 hasNsNodes);
12499 else
12500 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12501 hasNsNodes);
12502
12503 if (ctxt->error != XPATH_EXPRESSION_OK) {
12504 total = 0;
12505 goto error;
12506 }
12507 }
12508
12509 if (seq->nodeNr > 0) {
12510 /*
12511 * Add to result set.
12512 */
12513 if (outSeq == NULL) {
12514 outSeq = seq;
12515 seq = NULL;
12516 } else {
12517 /* TODO: Check memory error. */
12518 outSeq = mergeAndClear(outSeq, seq);
12519 }
12520
12521 if (toBool)
12522 break;
12523 }
12524 }
12525
12526 error:
12527 if ((obj->boolval) && (obj->user != NULL)) {
12528 /*
12529 * QUESTION TODO: What does this do and why?
12530 * TODO: Do we have to do this also for the "error"
12531 * cleanup further down?
12532 */
12533 ctxt->value->boolval = 1;
12534 ctxt->value->user = obj->user;
12535 obj->user = NULL;
12536 obj->boolval = 0;
12537 }
12538 xmlXPathReleaseObject(xpctxt, obj);
12539
12540 /*
12541 * Ensure we return at least an empty set.
12542 */
12543 if (outSeq == NULL) {
12544 if ((seq != NULL) && (seq->nodeNr == 0))
12545 outSeq = seq;
12546 else
12547 /* TODO: Check memory error. */
12548 outSeq = xmlXPathNodeSetCreate(NULL);
12549 }
12550 if ((seq != NULL) && (seq != outSeq)) {
12551 xmlXPathFreeNodeSet(seq);
12552 }
12553 /*
12554 * Hand over the result. Better to push the set also in
12555 * case of errors.
12556 */
12557 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12558 /*
12559 * Reset the context node.
12560 */
12561 xpctxt->node = oldContextNode;
12562 /*
12563 * When traversing the namespace axis in "toBool" mode, it's
12564 * possible that tmpNsList wasn't freed.
12565 */
12566 if (xpctxt->tmpNsList != NULL) {
12567 xmlFree(xpctxt->tmpNsList);
12568 xpctxt->tmpNsList = NULL;
12569 }
12570
12571 #ifdef DEBUG_STEP
12572 xmlGenericError(xmlGenericErrorContext,
12573 "\nExamined %d nodes, found %d nodes at that step\n",
12574 total, nbMatches);
12575 #endif
12576
12577 return(total);
12578 }
12579
12580 static int
12581 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12582 xmlXPathStepOpPtr op, xmlNodePtr * first);
12583
12584 /**
12585 * xmlXPathCompOpEvalFirst:
12586 * @ctxt: the XPath parser context with the compiled expression
12587 * @op: an XPath compiled operation
12588 * @first: the first elem found so far
12589 *
12590 * Evaluate the Precompiled XPath operation searching only the first
12591 * element in document order
12592 *
12593 * Returns the number of examined objects.
12594 */
12595 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12596 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12597 xmlXPathStepOpPtr op, xmlNodePtr * first)
12598 {
12599 int total = 0, cur;
12600 xmlXPathCompExprPtr comp;
12601 xmlXPathObjectPtr arg1, arg2;
12602
12603 CHECK_ERROR0;
12604 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12605 return(0);
12606 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12607 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12608 ctxt->context->depth += 1;
12609 comp = ctxt->comp;
12610 switch (op->op) {
12611 case XPATH_OP_END:
12612 break;
12613 case XPATH_OP_UNION:
12614 total =
12615 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12616 first);
12617 CHECK_ERROR0;
12618 if ((ctxt->value != NULL)
12619 && (ctxt->value->type == XPATH_NODESET)
12620 && (ctxt->value->nodesetval != NULL)
12621 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12622 /*
12623 * limit tree traversing to first node in the result
12624 */
12625 /*
12626 * OPTIMIZE TODO: This implicitly sorts
12627 * the result, even if not needed. E.g. if the argument
12628 * of the count() function, no sorting is needed.
12629 * OPTIMIZE TODO: How do we know if the node-list wasn't
12630 * already sorted?
12631 */
12632 if (ctxt->value->nodesetval->nodeNr > 1)
12633 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12634 *first = ctxt->value->nodesetval->nodeTab[0];
12635 }
12636 cur =
12637 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12638 first);
12639 CHECK_ERROR0;
12640
12641 arg2 = valuePop(ctxt);
12642 arg1 = valuePop(ctxt);
12643 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12644 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12645 xmlXPathReleaseObject(ctxt->context, arg1);
12646 xmlXPathReleaseObject(ctxt->context, arg2);
12647 XP_ERROR0(XPATH_INVALID_TYPE);
12648 }
12649 if ((ctxt->context->opLimit != 0) &&
12650 (((arg1->nodesetval != NULL) &&
12651 (xmlXPathCheckOpLimit(ctxt,
12652 arg1->nodesetval->nodeNr) < 0)) ||
12653 ((arg2->nodesetval != NULL) &&
12654 (xmlXPathCheckOpLimit(ctxt,
12655 arg2->nodesetval->nodeNr) < 0)))) {
12656 xmlXPathReleaseObject(ctxt->context, arg1);
12657 xmlXPathReleaseObject(ctxt->context, arg2);
12658 break;
12659 }
12660
12661 /* TODO: Check memory error. */
12662 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12663 arg2->nodesetval);
12664 valuePush(ctxt, arg1);
12665 xmlXPathReleaseObject(ctxt->context, arg2);
12666 /* optimizer */
12667 if (total > cur)
12668 xmlXPathCompSwap(op);
12669 total += cur;
12670 break;
12671 case XPATH_OP_ROOT:
12672 xmlXPathRoot(ctxt);
12673 break;
12674 case XPATH_OP_NODE:
12675 if (op->ch1 != -1)
12676 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12677 CHECK_ERROR0;
12678 if (op->ch2 != -1)
12679 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12680 CHECK_ERROR0;
12681 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12682 ctxt->context->node));
12683 break;
12684 case XPATH_OP_COLLECT:{
12685 if (op->ch1 == -1)
12686 break;
12687
12688 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12689 CHECK_ERROR0;
12690
12691 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12692 break;
12693 }
12694 case XPATH_OP_VALUE:
12695 valuePush(ctxt,
12696 xmlXPathCacheObjectCopy(ctxt->context,
12697 (xmlXPathObjectPtr) op->value4));
12698 break;
12699 case XPATH_OP_SORT:
12700 if (op->ch1 != -1)
12701 total +=
12702 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12703 first);
12704 CHECK_ERROR0;
12705 if ((ctxt->value != NULL)
12706 && (ctxt->value->type == XPATH_NODESET)
12707 && (ctxt->value->nodesetval != NULL)
12708 && (ctxt->value->nodesetval->nodeNr > 1))
12709 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12710 break;
12711 #ifdef XP_OPTIMIZED_FILTER_FIRST
12712 case XPATH_OP_FILTER:
12713 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12714 break;
12715 #endif
12716 default:
12717 total += xmlXPathCompOpEval(ctxt, op);
12718 break;
12719 }
12720
12721 ctxt->context->depth -= 1;
12722 return(total);
12723 }
12724
12725 /**
12726 * xmlXPathCompOpEvalLast:
12727 * @ctxt: the XPath parser context with the compiled expression
12728 * @op: an XPath compiled operation
12729 * @last: the last elem found so far
12730 *
12731 * Evaluate the Precompiled XPath operation searching only the last
12732 * element in document order
12733 *
12734 * Returns the number of nodes traversed
12735 */
12736 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12737 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12738 xmlNodePtr * last)
12739 {
12740 int total = 0, cur;
12741 xmlXPathCompExprPtr comp;
12742 xmlXPathObjectPtr arg1, arg2;
12743
12744 CHECK_ERROR0;
12745 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12746 return(0);
12747 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12748 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12749 ctxt->context->depth += 1;
12750 comp = ctxt->comp;
12751 switch (op->op) {
12752 case XPATH_OP_END:
12753 break;
12754 case XPATH_OP_UNION:
12755 total =
12756 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12757 CHECK_ERROR0;
12758 if ((ctxt->value != NULL)
12759 && (ctxt->value->type == XPATH_NODESET)
12760 && (ctxt->value->nodesetval != NULL)
12761 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12762 /*
12763 * limit tree traversing to first node in the result
12764 */
12765 if (ctxt->value->nodesetval->nodeNr > 1)
12766 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12767 *last =
12768 ctxt->value->nodesetval->nodeTab[ctxt->value->
12769 nodesetval->nodeNr -
12770 1];
12771 }
12772 cur =
12773 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12774 CHECK_ERROR0;
12775 if ((ctxt->value != NULL)
12776 && (ctxt->value->type == XPATH_NODESET)
12777 && (ctxt->value->nodesetval != NULL)
12778 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12779 }
12780
12781 arg2 = valuePop(ctxt);
12782 arg1 = valuePop(ctxt);
12783 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12784 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12785 xmlXPathReleaseObject(ctxt->context, arg1);
12786 xmlXPathReleaseObject(ctxt->context, arg2);
12787 XP_ERROR0(XPATH_INVALID_TYPE);
12788 }
12789 if ((ctxt->context->opLimit != 0) &&
12790 (((arg1->nodesetval != NULL) &&
12791 (xmlXPathCheckOpLimit(ctxt,
12792 arg1->nodesetval->nodeNr) < 0)) ||
12793 ((arg2->nodesetval != NULL) &&
12794 (xmlXPathCheckOpLimit(ctxt,
12795 arg2->nodesetval->nodeNr) < 0)))) {
12796 xmlXPathReleaseObject(ctxt->context, arg1);
12797 xmlXPathReleaseObject(ctxt->context, arg2);
12798 break;
12799 }
12800
12801 /* TODO: Check memory error. */
12802 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12803 arg2->nodesetval);
12804 valuePush(ctxt, arg1);
12805 xmlXPathReleaseObject(ctxt->context, arg2);
12806 /* optimizer */
12807 if (total > cur)
12808 xmlXPathCompSwap(op);
12809 total += cur;
12810 break;
12811 case XPATH_OP_ROOT:
12812 xmlXPathRoot(ctxt);
12813 break;
12814 case XPATH_OP_NODE:
12815 if (op->ch1 != -1)
12816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12817 CHECK_ERROR0;
12818 if (op->ch2 != -1)
12819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12820 CHECK_ERROR0;
12821 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12822 ctxt->context->node));
12823 break;
12824 case XPATH_OP_COLLECT:{
12825 if (op->ch1 == -1)
12826 break;
12827
12828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12829 CHECK_ERROR0;
12830
12831 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12832 break;
12833 }
12834 case XPATH_OP_VALUE:
12835 valuePush(ctxt,
12836 xmlXPathCacheObjectCopy(ctxt->context,
12837 (xmlXPathObjectPtr) op->value4));
12838 break;
12839 case XPATH_OP_SORT:
12840 if (op->ch1 != -1)
12841 total +=
12842 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12843 last);
12844 CHECK_ERROR0;
12845 if ((ctxt->value != NULL)
12846 && (ctxt->value->type == XPATH_NODESET)
12847 && (ctxt->value->nodesetval != NULL)
12848 && (ctxt->value->nodesetval->nodeNr > 1))
12849 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12850 break;
12851 default:
12852 total += xmlXPathCompOpEval(ctxt, op);
12853 break;
12854 }
12855
12856 ctxt->context->depth -= 1;
12857 return (total);
12858 }
12859
12860 #ifdef XP_OPTIMIZED_FILTER_FIRST
12861 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12862 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12863 xmlXPathStepOpPtr op, xmlNodePtr * first)
12864 {
12865 int total = 0;
12866 xmlXPathCompExprPtr comp;
12867 xmlNodeSetPtr set;
12868
12869 CHECK_ERROR0;
12870 comp = ctxt->comp;
12871 /*
12872 * Optimization for ()[last()] selection i.e. the last elem
12873 */
12874 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12875 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12876 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12877 int f = comp->steps[op->ch2].ch1;
12878
12879 if ((f != -1) &&
12880 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12881 (comp->steps[f].value5 == NULL) &&
12882 (comp->steps[f].value == 0) &&
12883 (comp->steps[f].value4 != NULL) &&
12884 (xmlStrEqual
12885 (comp->steps[f].value4, BAD_CAST "last"))) {
12886 xmlNodePtr last = NULL;
12887
12888 total +=
12889 xmlXPathCompOpEvalLast(ctxt,
12890 &comp->steps[op->ch1],
12891 &last);
12892 CHECK_ERROR0;
12893 /*
12894 * The nodeset should be in document order,
12895 * Keep only the last value
12896 */
12897 if ((ctxt->value != NULL) &&
12898 (ctxt->value->type == XPATH_NODESET) &&
12899 (ctxt->value->nodesetval != NULL) &&
12900 (ctxt->value->nodesetval->nodeTab != NULL) &&
12901 (ctxt->value->nodesetval->nodeNr > 1)) {
12902 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12903 *first = *(ctxt->value->nodesetval->nodeTab);
12904 }
12905 return (total);
12906 }
12907 }
12908
12909 if (op->ch1 != -1)
12910 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12911 CHECK_ERROR0;
12912 if (op->ch2 == -1)
12913 return (total);
12914 if (ctxt->value == NULL)
12915 return (total);
12916
12917 #ifdef LIBXML_XPTR_ENABLED
12918 /*
12919 * Hum are we filtering the result of an XPointer expression
12920 */
12921 if (ctxt->value->type == XPATH_LOCATIONSET) {
12922 xmlLocationSetPtr locset = ctxt->value->user;
12923
12924 if (locset != NULL) {
12925 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12926 if (locset->locNr > 0)
12927 *first = (xmlNodePtr) locset->locTab[0]->user;
12928 }
12929
12930 return (total);
12931 }
12932 #endif /* LIBXML_XPTR_ENABLED */
12933
12934 CHECK_TYPE0(XPATH_NODESET);
12935 set = ctxt->value->nodesetval;
12936 if (set != NULL) {
12937 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12938 if (set->nodeNr > 0)
12939 *first = set->nodeTab[0];
12940 }
12941
12942 return (total);
12943 }
12944 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12945
12946 /**
12947 * xmlXPathCompOpEval:
12948 * @ctxt: the XPath parser context with the compiled expression
12949 * @op: an XPath compiled operation
12950 *
12951 * Evaluate the Precompiled XPath operation
12952 * Returns the number of nodes traversed
12953 */
12954 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)12955 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12956 {
12957 int total = 0;
12958 int equal, ret;
12959 xmlXPathCompExprPtr comp;
12960 xmlXPathObjectPtr arg1, arg2;
12961
12962 CHECK_ERROR0;
12963 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12964 return(0);
12965 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12966 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12967 ctxt->context->depth += 1;
12968 comp = ctxt->comp;
12969 switch (op->op) {
12970 case XPATH_OP_END:
12971 break;
12972 case XPATH_OP_AND:
12973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12974 CHECK_ERROR0;
12975 xmlXPathBooleanFunction(ctxt, 1);
12976 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12977 break;
12978 arg2 = valuePop(ctxt);
12979 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12980 if (ctxt->error) {
12981 xmlXPathFreeObject(arg2);
12982 break;
12983 }
12984 xmlXPathBooleanFunction(ctxt, 1);
12985 if (ctxt->value != NULL)
12986 ctxt->value->boolval &= arg2->boolval;
12987 xmlXPathReleaseObject(ctxt->context, arg2);
12988 break;
12989 case XPATH_OP_OR:
12990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12991 CHECK_ERROR0;
12992 xmlXPathBooleanFunction(ctxt, 1);
12993 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12994 break;
12995 arg2 = valuePop(ctxt);
12996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12997 if (ctxt->error) {
12998 xmlXPathFreeObject(arg2);
12999 break;
13000 }
13001 xmlXPathBooleanFunction(ctxt, 1);
13002 if (ctxt->value != NULL)
13003 ctxt->value->boolval |= arg2->boolval;
13004 xmlXPathReleaseObject(ctxt->context, arg2);
13005 break;
13006 case XPATH_OP_EQUAL:
13007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13008 CHECK_ERROR0;
13009 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13010 CHECK_ERROR0;
13011 if (op->value)
13012 equal = xmlXPathEqualValues(ctxt);
13013 else
13014 equal = xmlXPathNotEqualValues(ctxt);
13015 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13016 break;
13017 case XPATH_OP_CMP:
13018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13019 CHECK_ERROR0;
13020 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13021 CHECK_ERROR0;
13022 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13023 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13024 break;
13025 case XPATH_OP_PLUS:
13026 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13027 CHECK_ERROR0;
13028 if (op->ch2 != -1) {
13029 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13030 }
13031 CHECK_ERROR0;
13032 if (op->value == 0)
13033 xmlXPathSubValues(ctxt);
13034 else if (op->value == 1)
13035 xmlXPathAddValues(ctxt);
13036 else if (op->value == 2)
13037 xmlXPathValueFlipSign(ctxt);
13038 else if (op->value == 3) {
13039 CAST_TO_NUMBER;
13040 CHECK_TYPE0(XPATH_NUMBER);
13041 }
13042 break;
13043 case XPATH_OP_MULT:
13044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13045 CHECK_ERROR0;
13046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13047 CHECK_ERROR0;
13048 if (op->value == 0)
13049 xmlXPathMultValues(ctxt);
13050 else if (op->value == 1)
13051 xmlXPathDivValues(ctxt);
13052 else if (op->value == 2)
13053 xmlXPathModValues(ctxt);
13054 break;
13055 case XPATH_OP_UNION:
13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13057 CHECK_ERROR0;
13058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13059 CHECK_ERROR0;
13060
13061 arg2 = valuePop(ctxt);
13062 arg1 = valuePop(ctxt);
13063 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13064 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13065 xmlXPathReleaseObject(ctxt->context, arg1);
13066 xmlXPathReleaseObject(ctxt->context, arg2);
13067 XP_ERROR0(XPATH_INVALID_TYPE);
13068 }
13069 if ((ctxt->context->opLimit != 0) &&
13070 (((arg1->nodesetval != NULL) &&
13071 (xmlXPathCheckOpLimit(ctxt,
13072 arg1->nodesetval->nodeNr) < 0)) ||
13073 ((arg2->nodesetval != NULL) &&
13074 (xmlXPathCheckOpLimit(ctxt,
13075 arg2->nodesetval->nodeNr) < 0)))) {
13076 xmlXPathReleaseObject(ctxt->context, arg1);
13077 xmlXPathReleaseObject(ctxt->context, arg2);
13078 break;
13079 }
13080
13081 if ((arg1->nodesetval == NULL) ||
13082 ((arg2->nodesetval != NULL) &&
13083 (arg2->nodesetval->nodeNr != 0)))
13084 {
13085 /* TODO: Check memory error. */
13086 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13087 arg2->nodesetval);
13088 }
13089
13090 valuePush(ctxt, arg1);
13091 xmlXPathReleaseObject(ctxt->context, arg2);
13092 break;
13093 case XPATH_OP_ROOT:
13094 xmlXPathRoot(ctxt);
13095 break;
13096 case XPATH_OP_NODE:
13097 if (op->ch1 != -1)
13098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13099 CHECK_ERROR0;
13100 if (op->ch2 != -1)
13101 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13102 CHECK_ERROR0;
13103 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13104 ctxt->context->node));
13105 break;
13106 case XPATH_OP_COLLECT:{
13107 if (op->ch1 == -1)
13108 break;
13109
13110 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13111 CHECK_ERROR0;
13112
13113 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13114 break;
13115 }
13116 case XPATH_OP_VALUE:
13117 valuePush(ctxt,
13118 xmlXPathCacheObjectCopy(ctxt->context,
13119 (xmlXPathObjectPtr) op->value4));
13120 break;
13121 case XPATH_OP_VARIABLE:{
13122 xmlXPathObjectPtr val;
13123
13124 if (op->ch1 != -1)
13125 total +=
13126 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13127 if (op->value5 == NULL) {
13128 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13129 if (val == NULL)
13130 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13131 valuePush(ctxt, val);
13132 } else {
13133 const xmlChar *URI;
13134
13135 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13136 if (URI == NULL) {
13137 xmlGenericError(xmlGenericErrorContext,
13138 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13139 (char *) op->value4, (char *)op->value5);
13140 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13141 break;
13142 }
13143 val = xmlXPathVariableLookupNS(ctxt->context,
13144 op->value4, URI);
13145 if (val == NULL)
13146 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13147 valuePush(ctxt, val);
13148 }
13149 break;
13150 }
13151 case XPATH_OP_FUNCTION:{
13152 xmlXPathFunction func;
13153 const xmlChar *oldFunc, *oldFuncURI;
13154 int i;
13155 int frame;
13156
13157 frame = xmlXPathSetFrame(ctxt);
13158 if (op->ch1 != -1) {
13159 total +=
13160 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13161 if (ctxt->error != XPATH_EXPRESSION_OK) {
13162 xmlXPathPopFrame(ctxt, frame);
13163 break;
13164 }
13165 }
13166 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13167 xmlGenericError(xmlGenericErrorContext,
13168 "xmlXPathCompOpEval: parameter error\n");
13169 ctxt->error = XPATH_INVALID_OPERAND;
13170 xmlXPathPopFrame(ctxt, frame);
13171 break;
13172 }
13173 for (i = 0; i < op->value; i++) {
13174 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13175 xmlGenericError(xmlGenericErrorContext,
13176 "xmlXPathCompOpEval: parameter error\n");
13177 ctxt->error = XPATH_INVALID_OPERAND;
13178 xmlXPathPopFrame(ctxt, frame);
13179 break;
13180 }
13181 }
13182 if (op->cache != NULL)
13183 func = op->cache;
13184 else {
13185 const xmlChar *URI = NULL;
13186
13187 if (op->value5 == NULL)
13188 func =
13189 xmlXPathFunctionLookup(ctxt->context,
13190 op->value4);
13191 else {
13192 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13193 if (URI == NULL) {
13194 xmlGenericError(xmlGenericErrorContext,
13195 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13196 (char *)op->value4, (char *)op->value5);
13197 xmlXPathPopFrame(ctxt, frame);
13198 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13199 break;
13200 }
13201 func = xmlXPathFunctionLookupNS(ctxt->context,
13202 op->value4, URI);
13203 }
13204 if (func == NULL) {
13205 xmlGenericError(xmlGenericErrorContext,
13206 "xmlXPathCompOpEval: function %s not found\n",
13207 (char *)op->value4);
13208 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13209 }
13210 op->cache = func;
13211 op->cacheURI = (void *) URI;
13212 }
13213 oldFunc = ctxt->context->function;
13214 oldFuncURI = ctxt->context->functionURI;
13215 ctxt->context->function = op->value4;
13216 ctxt->context->functionURI = op->cacheURI;
13217 func(ctxt, op->value);
13218 ctxt->context->function = oldFunc;
13219 ctxt->context->functionURI = oldFuncURI;
13220 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13221 (ctxt->valueNr != ctxt->valueFrame + 1))
13222 XP_ERROR0(XPATH_STACK_ERROR);
13223 xmlXPathPopFrame(ctxt, frame);
13224 break;
13225 }
13226 case XPATH_OP_ARG:
13227 if (op->ch1 != -1) {
13228 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13229 CHECK_ERROR0;
13230 }
13231 if (op->ch2 != -1) {
13232 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13233 CHECK_ERROR0;
13234 }
13235 break;
13236 case XPATH_OP_PREDICATE:
13237 case XPATH_OP_FILTER:{
13238 xmlNodeSetPtr set;
13239
13240 /*
13241 * Optimization for ()[1] selection i.e. the first elem
13242 */
13243 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13244 #ifdef XP_OPTIMIZED_FILTER_FIRST
13245 /*
13246 * FILTER TODO: Can we assume that the inner processing
13247 * will result in an ordered list if we have an
13248 * XPATH_OP_FILTER?
13249 * What about an additional field or flag on
13250 * xmlXPathObject like @sorted ? This way we wouldn't need
13251 * to assume anything, so it would be more robust and
13252 * easier to optimize.
13253 */
13254 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13255 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13256 #else
13257 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13258 #endif
13259 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13260 xmlXPathObjectPtr val;
13261
13262 val = comp->steps[op->ch2].value4;
13263 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13264 (val->floatval == 1.0)) {
13265 xmlNodePtr first = NULL;
13266
13267 total +=
13268 xmlXPathCompOpEvalFirst(ctxt,
13269 &comp->steps[op->ch1],
13270 &first);
13271 CHECK_ERROR0;
13272 /*
13273 * The nodeset should be in document order,
13274 * Keep only the first value
13275 */
13276 if ((ctxt->value != NULL) &&
13277 (ctxt->value->type == XPATH_NODESET) &&
13278 (ctxt->value->nodesetval != NULL) &&
13279 (ctxt->value->nodesetval->nodeNr > 1))
13280 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13281 1, 1);
13282 break;
13283 }
13284 }
13285 /*
13286 * Optimization for ()[last()] selection i.e. the last elem
13287 */
13288 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13289 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13290 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13291 int f = comp->steps[op->ch2].ch1;
13292
13293 if ((f != -1) &&
13294 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13295 (comp->steps[f].value5 == NULL) &&
13296 (comp->steps[f].value == 0) &&
13297 (comp->steps[f].value4 != NULL) &&
13298 (xmlStrEqual
13299 (comp->steps[f].value4, BAD_CAST "last"))) {
13300 xmlNodePtr last = NULL;
13301
13302 total +=
13303 xmlXPathCompOpEvalLast(ctxt,
13304 &comp->steps[op->ch1],
13305 &last);
13306 CHECK_ERROR0;
13307 /*
13308 * The nodeset should be in document order,
13309 * Keep only the last value
13310 */
13311 if ((ctxt->value != NULL) &&
13312 (ctxt->value->type == XPATH_NODESET) &&
13313 (ctxt->value->nodesetval != NULL) &&
13314 (ctxt->value->nodesetval->nodeTab != NULL) &&
13315 (ctxt->value->nodesetval->nodeNr > 1))
13316 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13317 break;
13318 }
13319 }
13320 /*
13321 * Process inner predicates first.
13322 * Example "index[parent::book][1]":
13323 * ...
13324 * PREDICATE <-- we are here "[1]"
13325 * PREDICATE <-- process "[parent::book]" first
13326 * SORT
13327 * COLLECT 'parent' 'name' 'node' book
13328 * NODE
13329 * ELEM Object is a number : 1
13330 */
13331 if (op->ch1 != -1)
13332 total +=
13333 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13334 CHECK_ERROR0;
13335 if (op->ch2 == -1)
13336 break;
13337 if (ctxt->value == NULL)
13338 break;
13339
13340 #ifdef LIBXML_XPTR_ENABLED
13341 /*
13342 * Hum are we filtering the result of an XPointer expression
13343 */
13344 if (ctxt->value->type == XPATH_LOCATIONSET) {
13345 xmlLocationSetPtr locset = ctxt->value->user;
13346 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13347 1, locset->locNr);
13348 break;
13349 }
13350 #endif /* LIBXML_XPTR_ENABLED */
13351
13352 CHECK_TYPE0(XPATH_NODESET);
13353 set = ctxt->value->nodesetval;
13354 if (set != NULL)
13355 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13356 1, set->nodeNr, 1);
13357 break;
13358 }
13359 case XPATH_OP_SORT:
13360 if (op->ch1 != -1)
13361 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13362 CHECK_ERROR0;
13363 if ((ctxt->value != NULL) &&
13364 (ctxt->value->type == XPATH_NODESET) &&
13365 (ctxt->value->nodesetval != NULL) &&
13366 (ctxt->value->nodesetval->nodeNr > 1))
13367 {
13368 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13369 }
13370 break;
13371 #ifdef LIBXML_XPTR_ENABLED
13372 case XPATH_OP_RANGETO:{
13373 xmlXPathObjectPtr range;
13374 xmlXPathObjectPtr res, obj;
13375 xmlXPathObjectPtr tmp;
13376 xmlLocationSetPtr newlocset = NULL;
13377 xmlLocationSetPtr oldlocset;
13378 xmlNodeSetPtr oldset;
13379 xmlNodePtr oldnode = ctxt->context->node;
13380 int oldcs = ctxt->context->contextSize;
13381 int oldpp = ctxt->context->proximityPosition;
13382 int i, j;
13383
13384 if (op->ch1 != -1) {
13385 total +=
13386 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13387 CHECK_ERROR0;
13388 }
13389 if (ctxt->value == NULL) {
13390 XP_ERROR0(XPATH_INVALID_OPERAND);
13391 }
13392 if (op->ch2 == -1)
13393 break;
13394
13395 if (ctxt->value->type == XPATH_LOCATIONSET) {
13396 /*
13397 * Extract the old locset, and then evaluate the result of the
13398 * expression for all the element in the locset. use it to grow
13399 * up a new locset.
13400 */
13401 CHECK_TYPE0(XPATH_LOCATIONSET);
13402
13403 if ((ctxt->value->user == NULL) ||
13404 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13405 break;
13406
13407 obj = valuePop(ctxt);
13408 oldlocset = obj->user;
13409
13410 newlocset = xmlXPtrLocationSetCreate(NULL);
13411
13412 for (i = 0; i < oldlocset->locNr; i++) {
13413 /*
13414 * Run the evaluation with a node list made of a
13415 * single item in the nodelocset.
13416 */
13417 ctxt->context->node = oldlocset->locTab[i]->user;
13418 ctxt->context->contextSize = oldlocset->locNr;
13419 ctxt->context->proximityPosition = i + 1;
13420 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13421 ctxt->context->node);
13422 valuePush(ctxt, tmp);
13423
13424 if (op->ch2 != -1)
13425 total +=
13426 xmlXPathCompOpEval(ctxt,
13427 &comp->steps[op->ch2]);
13428 if (ctxt->error != XPATH_EXPRESSION_OK) {
13429 xmlXPtrFreeLocationSet(newlocset);
13430 goto rangeto_error;
13431 }
13432
13433 res = valuePop(ctxt);
13434 if (res->type == XPATH_LOCATIONSET) {
13435 xmlLocationSetPtr rloc =
13436 (xmlLocationSetPtr)res->user;
13437 for (j=0; j<rloc->locNr; j++) {
13438 range = xmlXPtrNewRange(
13439 oldlocset->locTab[i]->user,
13440 oldlocset->locTab[i]->index,
13441 rloc->locTab[j]->user2,
13442 rloc->locTab[j]->index2);
13443 if (range != NULL) {
13444 xmlXPtrLocationSetAdd(newlocset, range);
13445 }
13446 }
13447 } else {
13448 range = xmlXPtrNewRangeNodeObject(
13449 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13450 if (range != NULL) {
13451 xmlXPtrLocationSetAdd(newlocset,range);
13452 }
13453 }
13454
13455 /*
13456 * Cleanup
13457 */
13458 if (res != NULL) {
13459 xmlXPathReleaseObject(ctxt->context, res);
13460 }
13461 if (ctxt->value == tmp) {
13462 res = valuePop(ctxt);
13463 xmlXPathReleaseObject(ctxt->context, res);
13464 }
13465 }
13466 } else { /* Not a location set */
13467 CHECK_TYPE0(XPATH_NODESET);
13468 obj = valuePop(ctxt);
13469 oldset = obj->nodesetval;
13470
13471 newlocset = xmlXPtrLocationSetCreate(NULL);
13472
13473 if (oldset != NULL) {
13474 for (i = 0; i < oldset->nodeNr; i++) {
13475 /*
13476 * Run the evaluation with a node list made of a single item
13477 * in the nodeset.
13478 */
13479 ctxt->context->node = oldset->nodeTab[i];
13480 /*
13481 * OPTIMIZE TODO: Avoid recreation for every iteration.
13482 */
13483 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13484 ctxt->context->node);
13485 valuePush(ctxt, tmp);
13486
13487 if (op->ch2 != -1)
13488 total +=
13489 xmlXPathCompOpEval(ctxt,
13490 &comp->steps[op->ch2]);
13491 if (ctxt->error != XPATH_EXPRESSION_OK) {
13492 xmlXPtrFreeLocationSet(newlocset);
13493 goto rangeto_error;
13494 }
13495
13496 res = valuePop(ctxt);
13497 range =
13498 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13499 res);
13500 if (range != NULL) {
13501 xmlXPtrLocationSetAdd(newlocset, range);
13502 }
13503
13504 /*
13505 * Cleanup
13506 */
13507 if (res != NULL) {
13508 xmlXPathReleaseObject(ctxt->context, res);
13509 }
13510 if (ctxt->value == tmp) {
13511 res = valuePop(ctxt);
13512 xmlXPathReleaseObject(ctxt->context, res);
13513 }
13514 }
13515 }
13516 }
13517
13518 /*
13519 * The result is used as the new evaluation set.
13520 */
13521 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13522 rangeto_error:
13523 xmlXPathReleaseObject(ctxt->context, obj);
13524 ctxt->context->node = oldnode;
13525 ctxt->context->contextSize = oldcs;
13526 ctxt->context->proximityPosition = oldpp;
13527 break;
13528 }
13529 #endif /* LIBXML_XPTR_ENABLED */
13530 default:
13531 xmlGenericError(xmlGenericErrorContext,
13532 "XPath: unknown precompiled operation %d\n", op->op);
13533 ctxt->error = XPATH_INVALID_OPERAND;
13534 break;
13535 }
13536
13537 ctxt->context->depth -= 1;
13538 return (total);
13539 }
13540
13541 /**
13542 * xmlXPathCompOpEvalToBoolean:
13543 * @ctxt: the XPath parser context
13544 *
13545 * Evaluates if the expression evaluates to true.
13546 *
13547 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13548 */
13549 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13550 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13551 xmlXPathStepOpPtr op,
13552 int isPredicate)
13553 {
13554 xmlXPathObjectPtr resObj = NULL;
13555
13556 start:
13557 if (OP_LIMIT_EXCEEDED(ctxt, 1))
13558 return(0);
13559 /* comp = ctxt->comp; */
13560 switch (op->op) {
13561 case XPATH_OP_END:
13562 return (0);
13563 case XPATH_OP_VALUE:
13564 resObj = (xmlXPathObjectPtr) op->value4;
13565 if (isPredicate)
13566 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13567 return(xmlXPathCastToBoolean(resObj));
13568 case XPATH_OP_SORT:
13569 /*
13570 * We don't need sorting for boolean results. Skip this one.
13571 */
13572 if (op->ch1 != -1) {
13573 op = &ctxt->comp->steps[op->ch1];
13574 goto start;
13575 }
13576 return(0);
13577 case XPATH_OP_COLLECT:
13578 if (op->ch1 == -1)
13579 return(0);
13580
13581 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13582 if (ctxt->error != XPATH_EXPRESSION_OK)
13583 return(-1);
13584
13585 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13586 if (ctxt->error != XPATH_EXPRESSION_OK)
13587 return(-1);
13588
13589 resObj = valuePop(ctxt);
13590 if (resObj == NULL)
13591 return(-1);
13592 break;
13593 default:
13594 /*
13595 * Fallback to call xmlXPathCompOpEval().
13596 */
13597 xmlXPathCompOpEval(ctxt, op);
13598 if (ctxt->error != XPATH_EXPRESSION_OK)
13599 return(-1);
13600
13601 resObj = valuePop(ctxt);
13602 if (resObj == NULL)
13603 return(-1);
13604 break;
13605 }
13606
13607 if (resObj) {
13608 int res;
13609
13610 if (resObj->type == XPATH_BOOLEAN) {
13611 res = resObj->boolval;
13612 } else if (isPredicate) {
13613 /*
13614 * For predicates a result of type "number" is handled
13615 * differently:
13616 * SPEC XPath 1.0:
13617 * "If the result is a number, the result will be converted
13618 * to true if the number is equal to the context position
13619 * and will be converted to false otherwise;"
13620 */
13621 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13622 } else {
13623 res = xmlXPathCastToBoolean(resObj);
13624 }
13625 xmlXPathReleaseObject(ctxt->context, resObj);
13626 return(res);
13627 }
13628
13629 return(0);
13630 }
13631
13632 #ifdef XPATH_STREAMING
13633 /**
13634 * xmlXPathRunStreamEval:
13635 * @ctxt: the XPath parser context with the compiled expression
13636 *
13637 * Evaluate the Precompiled Streamable XPath expression in the given context.
13638 */
13639 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)13640 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13641 xmlXPathObjectPtr *resultSeq, int toBool)
13642 {
13643 int max_depth, min_depth;
13644 int from_root;
13645 int ret, depth;
13646 int eval_all_nodes;
13647 xmlNodePtr cur = NULL, limit = NULL;
13648 xmlStreamCtxtPtr patstream = NULL;
13649
13650 int nb_nodes = 0;
13651
13652 if ((ctxt == NULL) || (comp == NULL))
13653 return(-1);
13654 max_depth = xmlPatternMaxDepth(comp);
13655 if (max_depth == -1)
13656 return(-1);
13657 if (max_depth == -2)
13658 max_depth = 10000;
13659 min_depth = xmlPatternMinDepth(comp);
13660 if (min_depth == -1)
13661 return(-1);
13662 from_root = xmlPatternFromRoot(comp);
13663 if (from_root < 0)
13664 return(-1);
13665 #if 0
13666 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13667 #endif
13668
13669 if (! toBool) {
13670 if (resultSeq == NULL)
13671 return(-1);
13672 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13673 if (*resultSeq == NULL)
13674 return(-1);
13675 }
13676
13677 /*
13678 * handle the special cases of "/" amd "." being matched
13679 */
13680 if (min_depth == 0) {
13681 if (from_root) {
13682 /* Select "/" */
13683 if (toBool)
13684 return(1);
13685 /* TODO: Check memory error. */
13686 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13687 (xmlNodePtr) ctxt->doc);
13688 } else {
13689 /* Select "self::node()" */
13690 if (toBool)
13691 return(1);
13692 /* TODO: Check memory error. */
13693 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13694 }
13695 }
13696 if (max_depth == 0) {
13697 return(0);
13698 }
13699
13700 if (from_root) {
13701 cur = (xmlNodePtr)ctxt->doc;
13702 } else if (ctxt->node != NULL) {
13703 switch (ctxt->node->type) {
13704 case XML_ELEMENT_NODE:
13705 case XML_DOCUMENT_NODE:
13706 case XML_DOCUMENT_FRAG_NODE:
13707 case XML_HTML_DOCUMENT_NODE:
13708 #ifdef LIBXML_DOCB_ENABLED
13709 case XML_DOCB_DOCUMENT_NODE:
13710 #endif
13711 cur = ctxt->node;
13712 break;
13713 case XML_ATTRIBUTE_NODE:
13714 case XML_TEXT_NODE:
13715 case XML_CDATA_SECTION_NODE:
13716 case XML_ENTITY_REF_NODE:
13717 case XML_ENTITY_NODE:
13718 case XML_PI_NODE:
13719 case XML_COMMENT_NODE:
13720 case XML_NOTATION_NODE:
13721 case XML_DTD_NODE:
13722 case XML_DOCUMENT_TYPE_NODE:
13723 case XML_ELEMENT_DECL:
13724 case XML_ATTRIBUTE_DECL:
13725 case XML_ENTITY_DECL:
13726 case XML_NAMESPACE_DECL:
13727 case XML_XINCLUDE_START:
13728 case XML_XINCLUDE_END:
13729 break;
13730 }
13731 limit = cur;
13732 }
13733 if (cur == NULL) {
13734 return(0);
13735 }
13736
13737 patstream = xmlPatternGetStreamCtxt(comp);
13738 if (patstream == NULL) {
13739 /*
13740 * QUESTION TODO: Is this an error?
13741 */
13742 return(0);
13743 }
13744
13745 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13746
13747 if (from_root) {
13748 ret = xmlStreamPush(patstream, NULL, NULL);
13749 if (ret < 0) {
13750 } else if (ret == 1) {
13751 if (toBool)
13752 goto return_1;
13753 /* TODO: Check memory error. */
13754 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13755 }
13756 }
13757 depth = 0;
13758 goto scan_children;
13759 next_node:
13760 do {
13761 if (ctxt->opLimit != 0) {
13762 if (ctxt->opCount >= ctxt->opLimit) {
13763 xmlGenericError(xmlGenericErrorContext,
13764 "XPath operation limit exceeded\n");
13765 xmlFreeStreamCtxt(patstream);
13766 return(-1);
13767 }
13768 ctxt->opCount++;
13769 }
13770
13771 nb_nodes++;
13772
13773 switch (cur->type) {
13774 case XML_ELEMENT_NODE:
13775 case XML_TEXT_NODE:
13776 case XML_CDATA_SECTION_NODE:
13777 case XML_COMMENT_NODE:
13778 case XML_PI_NODE:
13779 if (cur->type == XML_ELEMENT_NODE) {
13780 ret = xmlStreamPush(patstream, cur->name,
13781 (cur->ns ? cur->ns->href : NULL));
13782 } else if (eval_all_nodes)
13783 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13784 else
13785 break;
13786
13787 if (ret < 0) {
13788 /* NOP. */
13789 } else if (ret == 1) {
13790 if (toBool)
13791 goto return_1;
13792 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13793 < 0) {
13794 ctxt->lastError.domain = XML_FROM_XPATH;
13795 ctxt->lastError.code = XML_ERR_NO_MEMORY;
13796 }
13797 }
13798 if ((cur->children == NULL) || (depth >= max_depth)) {
13799 ret = xmlStreamPop(patstream);
13800 while (cur->next != NULL) {
13801 cur = cur->next;
13802 if ((cur->type != XML_ENTITY_DECL) &&
13803 (cur->type != XML_DTD_NODE))
13804 goto next_node;
13805 }
13806 }
13807 default:
13808 break;
13809 }
13810
13811 scan_children:
13812 if (cur->type == XML_NAMESPACE_DECL) break;
13813 if ((cur->children != NULL) && (depth < max_depth)) {
13814 /*
13815 * Do not descend on entities declarations
13816 */
13817 if (cur->children->type != XML_ENTITY_DECL) {
13818 cur = cur->children;
13819 depth++;
13820 /*
13821 * Skip DTDs
13822 */
13823 if (cur->type != XML_DTD_NODE)
13824 continue;
13825 }
13826 }
13827
13828 if (cur == limit)
13829 break;
13830
13831 while (cur->next != NULL) {
13832 cur = cur->next;
13833 if ((cur->type != XML_ENTITY_DECL) &&
13834 (cur->type != XML_DTD_NODE))
13835 goto next_node;
13836 }
13837
13838 do {
13839 cur = cur->parent;
13840 depth--;
13841 if ((cur == NULL) || (cur == limit) ||
13842 (cur->type == XML_DOCUMENT_NODE))
13843 goto done;
13844 if (cur->type == XML_ELEMENT_NODE) {
13845 ret = xmlStreamPop(patstream);
13846 } else if ((eval_all_nodes) &&
13847 ((cur->type == XML_TEXT_NODE) ||
13848 (cur->type == XML_CDATA_SECTION_NODE) ||
13849 (cur->type == XML_COMMENT_NODE) ||
13850 (cur->type == XML_PI_NODE)))
13851 {
13852 ret = xmlStreamPop(patstream);
13853 }
13854 if (cur->next != NULL) {
13855 cur = cur->next;
13856 break;
13857 }
13858 } while (cur != NULL);
13859
13860 } while ((cur != NULL) && (depth >= 0));
13861
13862 done:
13863
13864 #if 0
13865 printf("stream eval: checked %d nodes selected %d\n",
13866 nb_nodes, retObj->nodesetval->nodeNr);
13867 #endif
13868
13869 if (patstream)
13870 xmlFreeStreamCtxt(patstream);
13871 return(0);
13872
13873 return_1:
13874 if (patstream)
13875 xmlFreeStreamCtxt(patstream);
13876 return(1);
13877 }
13878 #endif /* XPATH_STREAMING */
13879
13880 /**
13881 * xmlXPathRunEval:
13882 * @ctxt: the XPath parser context with the compiled expression
13883 * @toBool: evaluate to a boolean result
13884 *
13885 * Evaluate the Precompiled XPath expression in the given context.
13886 */
13887 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)13888 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13889 {
13890 xmlXPathCompExprPtr comp;
13891
13892 if ((ctxt == NULL) || (ctxt->comp == NULL))
13893 return(-1);
13894
13895 ctxt->context->depth = 0;
13896
13897 if (ctxt->valueTab == NULL) {
13898 /* Allocate the value stack */
13899 ctxt->valueTab = (xmlXPathObjectPtr *)
13900 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13901 if (ctxt->valueTab == NULL) {
13902 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13903 xmlFree(ctxt);
13904 }
13905 ctxt->valueNr = 0;
13906 ctxt->valueMax = 10;
13907 ctxt->value = NULL;
13908 ctxt->valueFrame = 0;
13909 }
13910 #ifdef XPATH_STREAMING
13911 if (ctxt->comp->stream) {
13912 int res;
13913
13914 if (toBool) {
13915 /*
13916 * Evaluation to boolean result.
13917 */
13918 res = xmlXPathRunStreamEval(ctxt->context,
13919 ctxt->comp->stream, NULL, 1);
13920 if (res != -1)
13921 return(res);
13922 } else {
13923 xmlXPathObjectPtr resObj = NULL;
13924
13925 /*
13926 * Evaluation to a sequence.
13927 */
13928 res = xmlXPathRunStreamEval(ctxt->context,
13929 ctxt->comp->stream, &resObj, 0);
13930
13931 if ((res != -1) && (resObj != NULL)) {
13932 valuePush(ctxt, resObj);
13933 return(0);
13934 }
13935 if (resObj != NULL)
13936 xmlXPathReleaseObject(ctxt->context, resObj);
13937 }
13938 /*
13939 * QUESTION TODO: This falls back to normal XPath evaluation
13940 * if res == -1. Is this intended?
13941 */
13942 }
13943 #endif
13944 comp = ctxt->comp;
13945 if (comp->last < 0) {
13946 xmlGenericError(xmlGenericErrorContext,
13947 "xmlXPathRunEval: last is less than zero\n");
13948 return(-1);
13949 }
13950 if (toBool)
13951 return(xmlXPathCompOpEvalToBoolean(ctxt,
13952 &comp->steps[comp->last], 0));
13953 else
13954 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13955
13956 return(0);
13957 }
13958
13959 /************************************************************************
13960 * *
13961 * Public interfaces *
13962 * *
13963 ************************************************************************/
13964
13965 /**
13966 * xmlXPathEvalPredicate:
13967 * @ctxt: the XPath context
13968 * @res: the Predicate Expression evaluation result
13969 *
13970 * Evaluate a predicate result for the current node.
13971 * A PredicateExpr is evaluated by evaluating the Expr and converting
13972 * the result to a boolean. If the result is a number, the result will
13973 * be converted to true if the number is equal to the position of the
13974 * context node in the context node list (as returned by the position
13975 * function) and will be converted to false otherwise; if the result
13976 * is not a number, then the result will be converted as if by a call
13977 * to the boolean function.
13978 *
13979 * Returns 1 if predicate is true, 0 otherwise
13980 */
13981 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)13982 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13983 if ((ctxt == NULL) || (res == NULL)) return(0);
13984 switch (res->type) {
13985 case XPATH_BOOLEAN:
13986 return(res->boolval);
13987 case XPATH_NUMBER:
13988 return(res->floatval == ctxt->proximityPosition);
13989 case XPATH_NODESET:
13990 case XPATH_XSLT_TREE:
13991 if (res->nodesetval == NULL)
13992 return(0);
13993 return(res->nodesetval->nodeNr != 0);
13994 case XPATH_STRING:
13995 return((res->stringval != NULL) &&
13996 (xmlStrlen(res->stringval) != 0));
13997 default:
13998 STRANGE
13999 }
14000 return(0);
14001 }
14002
14003 /**
14004 * xmlXPathEvaluatePredicateResult:
14005 * @ctxt: the XPath Parser context
14006 * @res: the Predicate Expression evaluation result
14007 *
14008 * Evaluate a predicate result for the current node.
14009 * A PredicateExpr is evaluated by evaluating the Expr and converting
14010 * the result to a boolean. If the result is a number, the result will
14011 * be converted to true if the number is equal to the position of the
14012 * context node in the context node list (as returned by the position
14013 * function) and will be converted to false otherwise; if the result
14014 * is not a number, then the result will be converted as if by a call
14015 * to the boolean function.
14016 *
14017 * Returns 1 if predicate is true, 0 otherwise
14018 */
14019 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14020 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14021 xmlXPathObjectPtr res) {
14022 if ((ctxt == NULL) || (res == NULL)) return(0);
14023 switch (res->type) {
14024 case XPATH_BOOLEAN:
14025 return(res->boolval);
14026 case XPATH_NUMBER:
14027 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14028 return((res->floatval == ctxt->context->proximityPosition) &&
14029 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14030 #else
14031 return(res->floatval == ctxt->context->proximityPosition);
14032 #endif
14033 case XPATH_NODESET:
14034 case XPATH_XSLT_TREE:
14035 if (res->nodesetval == NULL)
14036 return(0);
14037 return(res->nodesetval->nodeNr != 0);
14038 case XPATH_STRING:
14039 return((res->stringval != NULL) && (res->stringval[0] != 0));
14040 #ifdef LIBXML_XPTR_ENABLED
14041 case XPATH_LOCATIONSET:{
14042 xmlLocationSetPtr ptr = res->user;
14043 if (ptr == NULL)
14044 return(0);
14045 return (ptr->locNr != 0);
14046 }
14047 #endif
14048 default:
14049 STRANGE
14050 }
14051 return(0);
14052 }
14053
14054 #ifdef XPATH_STREAMING
14055 /**
14056 * xmlXPathTryStreamCompile:
14057 * @ctxt: an XPath context
14058 * @str: the XPath expression
14059 *
14060 * Try to compile the XPath expression as a streamable subset.
14061 *
14062 * Returns the compiled expression or NULL if failed to compile.
14063 */
14064 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14065 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14066 /*
14067 * Optimization: use streaming patterns when the XPath expression can
14068 * be compiled to a stream lookup
14069 */
14070 xmlPatternPtr stream;
14071 xmlXPathCompExprPtr comp;
14072 xmlDictPtr dict = NULL;
14073 const xmlChar **namespaces = NULL;
14074 xmlNsPtr ns;
14075 int i, j;
14076
14077 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14078 (!xmlStrchr(str, '@'))) {
14079 const xmlChar *tmp;
14080
14081 /*
14082 * We don't try to handle expressions using the verbose axis
14083 * specifiers ("::"), just the simplified form at this point.
14084 * Additionally, if there is no list of namespaces available and
14085 * there's a ":" in the expression, indicating a prefixed QName,
14086 * then we won't try to compile either. xmlPatterncompile() needs
14087 * to have a list of namespaces at compilation time in order to
14088 * compile prefixed name tests.
14089 */
14090 tmp = xmlStrchr(str, ':');
14091 if ((tmp != NULL) &&
14092 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14093 return(NULL);
14094
14095 if (ctxt != NULL) {
14096 dict = ctxt->dict;
14097 if (ctxt->nsNr > 0) {
14098 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14099 if (namespaces == NULL) {
14100 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14101 return(NULL);
14102 }
14103 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14104 ns = ctxt->namespaces[j];
14105 namespaces[i++] = ns->href;
14106 namespaces[i++] = ns->prefix;
14107 }
14108 namespaces[i++] = NULL;
14109 namespaces[i] = NULL;
14110 }
14111 }
14112
14113 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14114 if (namespaces != NULL) {
14115 xmlFree((xmlChar **)namespaces);
14116 }
14117 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14118 comp = xmlXPathNewCompExpr();
14119 if (comp == NULL) {
14120 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14121 return(NULL);
14122 }
14123 comp->stream = stream;
14124 comp->dict = dict;
14125 if (comp->dict)
14126 xmlDictReference(comp->dict);
14127 return(comp);
14128 }
14129 xmlFreePattern(stream);
14130 }
14131 return(NULL);
14132 }
14133 #endif /* XPATH_STREAMING */
14134
14135 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)14136 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14137 xmlXPathStepOpPtr op)
14138 {
14139 xmlXPathCompExprPtr comp = pctxt->comp;
14140 xmlXPathContextPtr ctxt;
14141
14142 /*
14143 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14144 * internal representation.
14145 */
14146
14147 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14148 (op->ch1 != -1) &&
14149 (op->ch2 == -1 /* no predicate */))
14150 {
14151 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14152
14153 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14154 ((xmlXPathAxisVal) prevop->value ==
14155 AXIS_DESCENDANT_OR_SELF) &&
14156 (prevop->ch2 == -1) &&
14157 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14158 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14159 {
14160 /*
14161 * This is a "descendant-or-self::node()" without predicates.
14162 * Try to eliminate it.
14163 */
14164
14165 switch ((xmlXPathAxisVal) op->value) {
14166 case AXIS_CHILD:
14167 case AXIS_DESCENDANT:
14168 /*
14169 * Convert "descendant-or-self::node()/child::" or
14170 * "descendant-or-self::node()/descendant::" to
14171 * "descendant::"
14172 */
14173 op->ch1 = prevop->ch1;
14174 op->value = AXIS_DESCENDANT;
14175 break;
14176 case AXIS_SELF:
14177 case AXIS_DESCENDANT_OR_SELF:
14178 /*
14179 * Convert "descendant-or-self::node()/self::" or
14180 * "descendant-or-self::node()/descendant-or-self::" to
14181 * to "descendant-or-self::"
14182 */
14183 op->ch1 = prevop->ch1;
14184 op->value = AXIS_DESCENDANT_OR_SELF;
14185 break;
14186 default:
14187 break;
14188 }
14189 }
14190 }
14191
14192 /* OP_VALUE has invalid ch1. */
14193 if (op->op == XPATH_OP_VALUE)
14194 return;
14195
14196 /* Recurse */
14197 ctxt = pctxt->context;
14198 if (ctxt != NULL) {
14199 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14200 return;
14201 ctxt->depth += 1;
14202 }
14203 if (op->ch1 != -1)
14204 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14205 if (op->ch2 != -1)
14206 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14207 if (ctxt != NULL)
14208 ctxt->depth -= 1;
14209 }
14210
14211 /**
14212 * xmlXPathCtxtCompile:
14213 * @ctxt: an XPath context
14214 * @str: the XPath expression
14215 *
14216 * Compile an XPath expression
14217 *
14218 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14219 * the caller has to free the object.
14220 */
14221 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14222 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14223 xmlXPathParserContextPtr pctxt;
14224 xmlXPathCompExprPtr comp;
14225
14226 #ifdef XPATH_STREAMING
14227 comp = xmlXPathTryStreamCompile(ctxt, str);
14228 if (comp != NULL)
14229 return(comp);
14230 #endif
14231
14232 xmlInitParser();
14233
14234 pctxt = xmlXPathNewParserContext(str, ctxt);
14235 if (pctxt == NULL)
14236 return NULL;
14237 if (ctxt != NULL)
14238 ctxt->depth = 0;
14239 xmlXPathCompileExpr(pctxt, 1);
14240
14241 if( pctxt->error != XPATH_EXPRESSION_OK )
14242 {
14243 xmlXPathFreeParserContext(pctxt);
14244 return(NULL);
14245 }
14246
14247 if (*pctxt->cur != 0) {
14248 /*
14249 * aleksey: in some cases this line prints *second* error message
14250 * (see bug #78858) and probably this should be fixed.
14251 * However, we are not sure that all error messages are printed
14252 * out in other places. It's not critical so we leave it as-is for now
14253 */
14254 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14255 comp = NULL;
14256 } else {
14257 comp = pctxt->comp;
14258 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14259 if (ctxt != NULL)
14260 ctxt->depth = 0;
14261 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14262 }
14263 pctxt->comp = NULL;
14264 }
14265 xmlXPathFreeParserContext(pctxt);
14266
14267 if (comp != NULL) {
14268 comp->expr = xmlStrdup(str);
14269 #ifdef DEBUG_EVAL_COUNTS
14270 comp->string = xmlStrdup(str);
14271 comp->nb = 0;
14272 #endif
14273 }
14274 return(comp);
14275 }
14276
14277 /**
14278 * xmlXPathCompile:
14279 * @str: the XPath expression
14280 *
14281 * Compile an XPath expression
14282 *
14283 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14284 * the caller has to free the object.
14285 */
14286 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14287 xmlXPathCompile(const xmlChar *str) {
14288 return(xmlXPathCtxtCompile(NULL, str));
14289 }
14290
14291 /**
14292 * xmlXPathCompiledEvalInternal:
14293 * @comp: the compiled XPath expression
14294 * @ctxt: the XPath context
14295 * @resObj: the resulting XPath object or NULL
14296 * @toBool: 1 if only a boolean result is requested
14297 *
14298 * Evaluate the Precompiled XPath expression in the given context.
14299 * The caller has to free @resObj.
14300 *
14301 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14302 * the caller has to free the object.
14303 */
14304 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14305 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14306 xmlXPathContextPtr ctxt,
14307 xmlXPathObjectPtr *resObjPtr,
14308 int toBool)
14309 {
14310 xmlXPathParserContextPtr pctxt;
14311 xmlXPathObjectPtr resObj;
14312 #ifndef LIBXML_THREAD_ENABLED
14313 static int reentance = 0;
14314 #endif
14315 int res;
14316
14317 CHECK_CTXT_NEG(ctxt)
14318
14319 if (comp == NULL)
14320 return(-1);
14321 xmlInitParser();
14322
14323 #ifndef LIBXML_THREAD_ENABLED
14324 reentance++;
14325 if (reentance > 1)
14326 xmlXPathDisableOptimizer = 1;
14327 #endif
14328
14329 #ifdef DEBUG_EVAL_COUNTS
14330 comp->nb++;
14331 if ((comp->string != NULL) && (comp->nb > 100)) {
14332 fprintf(stderr, "100 x %s\n", comp->string);
14333 comp->nb = 0;
14334 }
14335 #endif
14336 pctxt = xmlXPathCompParserContext(comp, ctxt);
14337 res = xmlXPathRunEval(pctxt, toBool);
14338
14339 if (pctxt->error != XPATH_EXPRESSION_OK) {
14340 resObj = NULL;
14341 } else {
14342 resObj = valuePop(pctxt);
14343 if (resObj == NULL) {
14344 if (!toBool)
14345 xmlGenericError(xmlGenericErrorContext,
14346 "xmlXPathCompiledEval: No result on the stack.\n");
14347 } else if (pctxt->valueNr > 0) {
14348 xmlGenericError(xmlGenericErrorContext,
14349 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14350 pctxt->valueNr);
14351 }
14352 }
14353
14354 if (resObjPtr)
14355 *resObjPtr = resObj;
14356 else
14357 xmlXPathReleaseObject(ctxt, resObj);
14358
14359 pctxt->comp = NULL;
14360 xmlXPathFreeParserContext(pctxt);
14361 #ifndef LIBXML_THREAD_ENABLED
14362 reentance--;
14363 #endif
14364
14365 return(res);
14366 }
14367
14368 /**
14369 * xmlXPathCompiledEval:
14370 * @comp: the compiled XPath expression
14371 * @ctx: the XPath context
14372 *
14373 * Evaluate the Precompiled XPath expression in the given context.
14374 *
14375 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14376 * the caller has to free the object.
14377 */
14378 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14379 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14380 {
14381 xmlXPathObjectPtr res = NULL;
14382
14383 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14384 return(res);
14385 }
14386
14387 /**
14388 * xmlXPathCompiledEvalToBoolean:
14389 * @comp: the compiled XPath expression
14390 * @ctxt: the XPath context
14391 *
14392 * Applies the XPath boolean() function on the result of the given
14393 * compiled expression.
14394 *
14395 * Returns 1 if the expression evaluated to true, 0 if to false and
14396 * -1 in API and internal errors.
14397 */
14398 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14399 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14400 xmlXPathContextPtr ctxt)
14401 {
14402 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14403 }
14404
14405 /**
14406 * xmlXPathEvalExpr:
14407 * @ctxt: the XPath Parser context
14408 *
14409 * Parse and evaluate an XPath expression in the given context,
14410 * then push the result on the context stack
14411 */
14412 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14413 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14414 #ifdef XPATH_STREAMING
14415 xmlXPathCompExprPtr comp;
14416 #endif
14417
14418 if (ctxt == NULL) return;
14419
14420 #ifdef XPATH_STREAMING
14421 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14422 if (comp != NULL) {
14423 if (ctxt->comp != NULL)
14424 xmlXPathFreeCompExpr(ctxt->comp);
14425 ctxt->comp = comp;
14426 } else
14427 #endif
14428 {
14429 if (ctxt->context != NULL)
14430 ctxt->context->depth = 0;
14431 xmlXPathCompileExpr(ctxt, 1);
14432 CHECK_ERROR;
14433
14434 /* Check for trailing characters. */
14435 if (*ctxt->cur != 0)
14436 XP_ERROR(XPATH_EXPR_ERROR);
14437
14438 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14439 if (ctxt->context != NULL)
14440 ctxt->context->depth = 0;
14441 xmlXPathOptimizeExpression(ctxt,
14442 &ctxt->comp->steps[ctxt->comp->last]);
14443 }
14444 }
14445
14446 xmlXPathRunEval(ctxt, 0);
14447 }
14448
14449 /**
14450 * xmlXPathEval:
14451 * @str: the XPath expression
14452 * @ctx: the XPath context
14453 *
14454 * Evaluate the XPath Location Path in the given context.
14455 *
14456 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14457 * the caller has to free the object.
14458 */
14459 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14460 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14461 xmlXPathParserContextPtr ctxt;
14462 xmlXPathObjectPtr res;
14463
14464 CHECK_CTXT(ctx)
14465
14466 xmlInitParser();
14467
14468 ctxt = xmlXPathNewParserContext(str, ctx);
14469 if (ctxt == NULL)
14470 return NULL;
14471 xmlXPathEvalExpr(ctxt);
14472
14473 if (ctxt->error != XPATH_EXPRESSION_OK) {
14474 res = NULL;
14475 } else {
14476 res = valuePop(ctxt);
14477 if (res == NULL) {
14478 xmlGenericError(xmlGenericErrorContext,
14479 "xmlXPathCompiledEval: No result on the stack.\n");
14480 } else if (ctxt->valueNr > 0) {
14481 xmlGenericError(xmlGenericErrorContext,
14482 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14483 ctxt->valueNr);
14484 }
14485 }
14486
14487 xmlXPathFreeParserContext(ctxt);
14488 return(res);
14489 }
14490
14491 /**
14492 * xmlXPathSetContextNode:
14493 * @node: the node to to use as the context node
14494 * @ctx: the XPath context
14495 *
14496 * Sets 'node' as the context node. The node must be in the same
14497 * document as that associated with the context.
14498 *
14499 * Returns -1 in case of error or 0 if successful
14500 */
14501 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14502 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14503 if ((node == NULL) || (ctx == NULL))
14504 return(-1);
14505
14506 if (node->doc == ctx->doc) {
14507 ctx->node = node;
14508 return(0);
14509 }
14510 return(-1);
14511 }
14512
14513 /**
14514 * xmlXPathNodeEval:
14515 * @node: the node to to use as the context node
14516 * @str: the XPath expression
14517 * @ctx: the XPath context
14518 *
14519 * Evaluate the XPath Location Path in the given context. The node 'node'
14520 * is set as the context node. The context node is not restored.
14521 *
14522 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14523 * the caller has to free the object.
14524 */
14525 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14526 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14527 if (str == NULL)
14528 return(NULL);
14529 if (xmlXPathSetContextNode(node, ctx) < 0)
14530 return(NULL);
14531 return(xmlXPathEval(str, ctx));
14532 }
14533
14534 /**
14535 * xmlXPathEvalExpression:
14536 * @str: the XPath expression
14537 * @ctxt: the XPath context
14538 *
14539 * Alias for xmlXPathEval().
14540 *
14541 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14542 * the caller has to free the object.
14543 */
14544 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14545 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14546 return(xmlXPathEval(str, ctxt));
14547 }
14548
14549 /************************************************************************
14550 * *
14551 * Extra functions not pertaining to the XPath spec *
14552 * *
14553 ************************************************************************/
14554 /**
14555 * xmlXPathEscapeUriFunction:
14556 * @ctxt: the XPath Parser context
14557 * @nargs: the number of arguments
14558 *
14559 * Implement the escape-uri() XPath function
14560 * string escape-uri(string $str, bool $escape-reserved)
14561 *
14562 * This function applies the URI escaping rules defined in section 2 of [RFC
14563 * 2396] to the string supplied as $uri-part, which typically represents all
14564 * or part of a URI. The effect of the function is to replace any special
14565 * character in the string by an escape sequence of the form %xx%yy...,
14566 * where xxyy... is the hexadecimal representation of the octets used to
14567 * represent the character in UTF-8.
14568 *
14569 * The set of characters that are escaped depends on the setting of the
14570 * boolean argument $escape-reserved.
14571 *
14572 * If $escape-reserved is true, all characters are escaped other than lower
14573 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14574 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14575 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14576 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14577 * A-F).
14578 *
14579 * If $escape-reserved is false, the behavior differs in that characters
14580 * referred to in [RFC 2396] as reserved characters are not escaped. These
14581 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14582 *
14583 * [RFC 2396] does not define whether escaped URIs should use lower case or
14584 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14585 * compared using string comparison functions, this function must always use
14586 * the upper-case letters A-F.
14587 *
14588 * Generally, $escape-reserved should be set to true when escaping a string
14589 * that is to form a single part of a URI, and to false when escaping an
14590 * entire URI or URI reference.
14591 *
14592 * In the case of non-ascii characters, the string is encoded according to
14593 * utf-8 and then converted according to RFC 2396.
14594 *
14595 * Examples
14596 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14597 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14598 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14599 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14600 *
14601 */
14602 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)14603 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14604 xmlXPathObjectPtr str;
14605 int escape_reserved;
14606 xmlBufPtr target;
14607 xmlChar *cptr;
14608 xmlChar escape[4];
14609
14610 CHECK_ARITY(2);
14611
14612 escape_reserved = xmlXPathPopBoolean(ctxt);
14613
14614 CAST_TO_STRING;
14615 str = valuePop(ctxt);
14616
14617 target = xmlBufCreate();
14618
14619 escape[0] = '%';
14620 escape[3] = 0;
14621
14622 if (target) {
14623 for (cptr = str->stringval; *cptr; cptr++) {
14624 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14625 (*cptr >= 'a' && *cptr <= 'z') ||
14626 (*cptr >= '0' && *cptr <= '9') ||
14627 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14628 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14629 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14630 (*cptr == '%' &&
14631 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14632 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14633 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14634 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14635 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14636 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14637 (!escape_reserved &&
14638 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14639 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14640 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14641 *cptr == ','))) {
14642 xmlBufAdd(target, cptr, 1);
14643 } else {
14644 if ((*cptr >> 4) < 10)
14645 escape[1] = '0' + (*cptr >> 4);
14646 else
14647 escape[1] = 'A' - 10 + (*cptr >> 4);
14648 if ((*cptr & 0xF) < 10)
14649 escape[2] = '0' + (*cptr & 0xF);
14650 else
14651 escape[2] = 'A' - 10 + (*cptr & 0xF);
14652
14653 xmlBufAdd(target, &escape[0], 3);
14654 }
14655 }
14656 }
14657 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14658 xmlBufContent(target)));
14659 xmlBufFree(target);
14660 xmlXPathReleaseObject(ctxt->context, str);
14661 }
14662
14663 /**
14664 * xmlXPathRegisterAllFunctions:
14665 * @ctxt: the XPath context
14666 *
14667 * Registers all default XPath functions in this context
14668 */
14669 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)14670 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14671 {
14672 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14673 xmlXPathBooleanFunction);
14674 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14675 xmlXPathCeilingFunction);
14676 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14677 xmlXPathCountFunction);
14678 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14679 xmlXPathConcatFunction);
14680 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14681 xmlXPathContainsFunction);
14682 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14683 xmlXPathIdFunction);
14684 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14685 xmlXPathFalseFunction);
14686 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14687 xmlXPathFloorFunction);
14688 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14689 xmlXPathLastFunction);
14690 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14691 xmlXPathLangFunction);
14692 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14693 xmlXPathLocalNameFunction);
14694 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14695 xmlXPathNotFunction);
14696 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14697 xmlXPathNameFunction);
14698 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14699 xmlXPathNamespaceURIFunction);
14700 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14701 xmlXPathNormalizeFunction);
14702 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14703 xmlXPathNumberFunction);
14704 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14705 xmlXPathPositionFunction);
14706 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14707 xmlXPathRoundFunction);
14708 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14709 xmlXPathStringFunction);
14710 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14711 xmlXPathStringLengthFunction);
14712 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14713 xmlXPathStartsWithFunction);
14714 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14715 xmlXPathSubstringFunction);
14716 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14717 xmlXPathSubstringBeforeFunction);
14718 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14719 xmlXPathSubstringAfterFunction);
14720 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14721 xmlXPathSumFunction);
14722 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14723 xmlXPathTrueFunction);
14724 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14725 xmlXPathTranslateFunction);
14726
14727 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14728 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14729 xmlXPathEscapeUriFunction);
14730 }
14731
14732 #endif /* LIBXML_XPATH_ENABLED */
14733 #define bottom_xpath
14734 #include "elfgcchack.h"
14735