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 if (name == NULL) {
11124 XP_ERRORNULL(XPATH_EXPR_ERROR);
11125 }
11126 *test = NODE_TEST_PI;
11127 SKIP_BLANKS;
11128 }
11129 }
11130 if (CUR != ')') {
11131 if (name != NULL)
11132 xmlFree(name);
11133 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11134 }
11135 NEXT;
11136 return(name);
11137 }
11138 *test = NODE_TEST_NAME;
11139 if ((!blanks) && (CUR == ':')) {
11140 NEXT;
11141
11142 /*
11143 * Since currently the parser context don't have a
11144 * namespace list associated:
11145 * The namespace name for this prefix can be computed
11146 * only at evaluation time. The compilation is done
11147 * outside of any context.
11148 */
11149 #if 0
11150 *prefix = xmlXPathNsLookup(ctxt->context, name);
11151 if (name != NULL)
11152 xmlFree(name);
11153 if (*prefix == NULL) {
11154 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11155 }
11156 #else
11157 *prefix = name;
11158 #endif
11159
11160 if (CUR == '*') {
11161 /*
11162 * All elements
11163 */
11164 NEXT;
11165 *test = NODE_TEST_ALL;
11166 return(NULL);
11167 }
11168
11169 name = xmlXPathParseNCName(ctxt);
11170 if (name == NULL) {
11171 XP_ERRORNULL(XPATH_EXPR_ERROR);
11172 }
11173 }
11174 return(name);
11175 }
11176
11177 /**
11178 * xmlXPathIsAxisName:
11179 * @name: a preparsed name token
11180 *
11181 * [6] AxisName ::= 'ancestor'
11182 * | 'ancestor-or-self'
11183 * | 'attribute'
11184 * | 'child'
11185 * | 'descendant'
11186 * | 'descendant-or-self'
11187 * | 'following'
11188 * | 'following-sibling'
11189 * | 'namespace'
11190 * | 'parent'
11191 * | 'preceding'
11192 * | 'preceding-sibling'
11193 * | 'self'
11194 *
11195 * Returns the axis or 0
11196 */
11197 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11198 xmlXPathIsAxisName(const xmlChar *name) {
11199 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11200 switch (name[0]) {
11201 case 'a':
11202 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11203 ret = AXIS_ANCESTOR;
11204 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11205 ret = AXIS_ANCESTOR_OR_SELF;
11206 if (xmlStrEqual(name, BAD_CAST "attribute"))
11207 ret = AXIS_ATTRIBUTE;
11208 break;
11209 case 'c':
11210 if (xmlStrEqual(name, BAD_CAST "child"))
11211 ret = AXIS_CHILD;
11212 break;
11213 case 'd':
11214 if (xmlStrEqual(name, BAD_CAST "descendant"))
11215 ret = AXIS_DESCENDANT;
11216 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11217 ret = AXIS_DESCENDANT_OR_SELF;
11218 break;
11219 case 'f':
11220 if (xmlStrEqual(name, BAD_CAST "following"))
11221 ret = AXIS_FOLLOWING;
11222 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11223 ret = AXIS_FOLLOWING_SIBLING;
11224 break;
11225 case 'n':
11226 if (xmlStrEqual(name, BAD_CAST "namespace"))
11227 ret = AXIS_NAMESPACE;
11228 break;
11229 case 'p':
11230 if (xmlStrEqual(name, BAD_CAST "parent"))
11231 ret = AXIS_PARENT;
11232 if (xmlStrEqual(name, BAD_CAST "preceding"))
11233 ret = AXIS_PRECEDING;
11234 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11235 ret = AXIS_PRECEDING_SIBLING;
11236 break;
11237 case 's':
11238 if (xmlStrEqual(name, BAD_CAST "self"))
11239 ret = AXIS_SELF;
11240 break;
11241 }
11242 return(ret);
11243 }
11244
11245 /**
11246 * xmlXPathCompStep:
11247 * @ctxt: the XPath Parser context
11248 *
11249 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11250 * | AbbreviatedStep
11251 *
11252 * [12] AbbreviatedStep ::= '.' | '..'
11253 *
11254 * [5] AxisSpecifier ::= AxisName '::'
11255 * | AbbreviatedAxisSpecifier
11256 *
11257 * [13] AbbreviatedAxisSpecifier ::= '@'?
11258 *
11259 * Modified for XPtr range support as:
11260 *
11261 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11262 * | AbbreviatedStep
11263 * | 'range-to' '(' Expr ')' Predicate*
11264 *
11265 * Compile one step in a Location Path
11266 * A location step of . is short for self::node(). This is
11267 * particularly useful in conjunction with //. For example, the
11268 * location path .//para is short for
11269 * self::node()/descendant-or-self::node()/child::para
11270 * and so will select all para descendant elements of the context
11271 * node.
11272 * Similarly, a location step of .. is short for parent::node().
11273 * For example, ../title is short for parent::node()/child::title
11274 * and so will select the title children of the parent of the context
11275 * node.
11276 */
11277 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11278 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11279 #ifdef LIBXML_XPTR_ENABLED
11280 int rangeto = 0;
11281 int op2 = -1;
11282 #endif
11283
11284 SKIP_BLANKS;
11285 if ((CUR == '.') && (NXT(1) == '.')) {
11286 SKIP(2);
11287 SKIP_BLANKS;
11288 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11289 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11290 } else if (CUR == '.') {
11291 NEXT;
11292 SKIP_BLANKS;
11293 } else {
11294 xmlChar *name = NULL;
11295 xmlChar *prefix = NULL;
11296 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11297 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11298 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11299 int op1;
11300
11301 /*
11302 * The modification needed for XPointer change to the production
11303 */
11304 #ifdef LIBXML_XPTR_ENABLED
11305 if (ctxt->xptr) {
11306 name = xmlXPathParseNCName(ctxt);
11307 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11308 op2 = ctxt->comp->last;
11309 xmlFree(name);
11310 SKIP_BLANKS;
11311 if (CUR != '(') {
11312 XP_ERROR(XPATH_EXPR_ERROR);
11313 }
11314 NEXT;
11315 SKIP_BLANKS;
11316
11317 xmlXPathCompileExpr(ctxt, 1);
11318 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11319 CHECK_ERROR;
11320
11321 SKIP_BLANKS;
11322 if (CUR != ')') {
11323 XP_ERROR(XPATH_EXPR_ERROR);
11324 }
11325 NEXT;
11326 rangeto = 1;
11327 goto eval_predicates;
11328 }
11329 }
11330 #endif
11331 if (CUR == '*') {
11332 axis = AXIS_CHILD;
11333 } else {
11334 if (name == NULL)
11335 name = xmlXPathParseNCName(ctxt);
11336 if (name != NULL) {
11337 axis = xmlXPathIsAxisName(name);
11338 if (axis != 0) {
11339 SKIP_BLANKS;
11340 if ((CUR == ':') && (NXT(1) == ':')) {
11341 SKIP(2);
11342 xmlFree(name);
11343 name = NULL;
11344 } else {
11345 /* an element name can conflict with an axis one :-\ */
11346 axis = AXIS_CHILD;
11347 }
11348 } else {
11349 axis = AXIS_CHILD;
11350 }
11351 } else if (CUR == '@') {
11352 NEXT;
11353 axis = AXIS_ATTRIBUTE;
11354 } else {
11355 axis = AXIS_CHILD;
11356 }
11357 }
11358
11359 if (ctxt->error != XPATH_EXPRESSION_OK) {
11360 xmlFree(name);
11361 return;
11362 }
11363
11364 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11365 if (test == 0)
11366 return;
11367
11368 if ((prefix != NULL) && (ctxt->context != NULL) &&
11369 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11370 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11371 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11372 }
11373 }
11374 #ifdef DEBUG_STEP
11375 xmlGenericError(xmlGenericErrorContext,
11376 "Basis : computing new set\n");
11377 #endif
11378
11379 #ifdef DEBUG_STEP
11380 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11381 if (ctxt->value == NULL)
11382 xmlGenericError(xmlGenericErrorContext, "no value\n");
11383 else if (ctxt->value->nodesetval == NULL)
11384 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11385 else
11386 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11387 #endif
11388
11389 #ifdef LIBXML_XPTR_ENABLED
11390 eval_predicates:
11391 #endif
11392 op1 = ctxt->comp->last;
11393 ctxt->comp->last = -1;
11394
11395 SKIP_BLANKS;
11396 while (CUR == '[') {
11397 xmlXPathCompPredicate(ctxt, 0);
11398 }
11399
11400 #ifdef LIBXML_XPTR_ENABLED
11401 if (rangeto) {
11402 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11403 } else
11404 #endif
11405 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11406 test, type, (void *)prefix, (void *)name) == -1) {
11407 xmlFree(prefix);
11408 xmlFree(name);
11409 }
11410 }
11411 #ifdef DEBUG_STEP
11412 xmlGenericError(xmlGenericErrorContext, "Step : ");
11413 if (ctxt->value == NULL)
11414 xmlGenericError(xmlGenericErrorContext, "no value\n");
11415 else if (ctxt->value->nodesetval == NULL)
11416 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11417 else
11418 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11419 ctxt->value->nodesetval);
11420 #endif
11421 }
11422
11423 /**
11424 * xmlXPathCompRelativeLocationPath:
11425 * @ctxt: the XPath Parser context
11426 *
11427 * [3] RelativeLocationPath ::= Step
11428 * | RelativeLocationPath '/' Step
11429 * | AbbreviatedRelativeLocationPath
11430 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11431 *
11432 * Compile a relative location path.
11433 */
11434 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11435 xmlXPathCompRelativeLocationPath
11436 (xmlXPathParserContextPtr ctxt) {
11437 SKIP_BLANKS;
11438 if ((CUR == '/') && (NXT(1) == '/')) {
11439 SKIP(2);
11440 SKIP_BLANKS;
11441 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11442 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11443 } else if (CUR == '/') {
11444 NEXT;
11445 SKIP_BLANKS;
11446 }
11447 xmlXPathCompStep(ctxt);
11448 CHECK_ERROR;
11449 SKIP_BLANKS;
11450 while (CUR == '/') {
11451 if ((CUR == '/') && (NXT(1) == '/')) {
11452 SKIP(2);
11453 SKIP_BLANKS;
11454 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11455 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11456 xmlXPathCompStep(ctxt);
11457 } else if (CUR == '/') {
11458 NEXT;
11459 SKIP_BLANKS;
11460 xmlXPathCompStep(ctxt);
11461 }
11462 SKIP_BLANKS;
11463 }
11464 }
11465
11466 /**
11467 * xmlXPathCompLocationPath:
11468 * @ctxt: the XPath Parser context
11469 *
11470 * [1] LocationPath ::= RelativeLocationPath
11471 * | AbsoluteLocationPath
11472 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11473 * | AbbreviatedAbsoluteLocationPath
11474 * [10] AbbreviatedAbsoluteLocationPath ::=
11475 * '//' RelativeLocationPath
11476 *
11477 * Compile a location path
11478 *
11479 * // is short for /descendant-or-self::node()/. For example,
11480 * //para is short for /descendant-or-self::node()/child::para and
11481 * so will select any para element in the document (even a para element
11482 * that is a document element will be selected by //para since the
11483 * document element node is a child of the root node); div//para is
11484 * short for div/descendant-or-self::node()/child::para and so will
11485 * select all para descendants of div children.
11486 */
11487 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11488 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11489 SKIP_BLANKS;
11490 if (CUR != '/') {
11491 xmlXPathCompRelativeLocationPath(ctxt);
11492 } else {
11493 while (CUR == '/') {
11494 if ((CUR == '/') && (NXT(1) == '/')) {
11495 SKIP(2);
11496 SKIP_BLANKS;
11497 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11498 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11499 xmlXPathCompRelativeLocationPath(ctxt);
11500 } else if (CUR == '/') {
11501 NEXT;
11502 SKIP_BLANKS;
11503 if ((CUR != 0 ) &&
11504 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11505 (CUR == '@') || (CUR == '*')))
11506 xmlXPathCompRelativeLocationPath(ctxt);
11507 }
11508 CHECK_ERROR;
11509 }
11510 }
11511 }
11512
11513 /************************************************************************
11514 * *
11515 * XPath precompiled expression evaluation *
11516 * *
11517 ************************************************************************/
11518
11519 static int
11520 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11521
11522 #ifdef DEBUG_STEP
11523 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11524 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11525 int nbNodes)
11526 {
11527 xmlGenericError(xmlGenericErrorContext, "new step : ");
11528 switch (op->value) {
11529 case AXIS_ANCESTOR:
11530 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11531 break;
11532 case AXIS_ANCESTOR_OR_SELF:
11533 xmlGenericError(xmlGenericErrorContext,
11534 "axis 'ancestors-or-self' ");
11535 break;
11536 case AXIS_ATTRIBUTE:
11537 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11538 break;
11539 case AXIS_CHILD:
11540 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11541 break;
11542 case AXIS_DESCENDANT:
11543 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11544 break;
11545 case AXIS_DESCENDANT_OR_SELF:
11546 xmlGenericError(xmlGenericErrorContext,
11547 "axis 'descendant-or-self' ");
11548 break;
11549 case AXIS_FOLLOWING:
11550 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11551 break;
11552 case AXIS_FOLLOWING_SIBLING:
11553 xmlGenericError(xmlGenericErrorContext,
11554 "axis 'following-siblings' ");
11555 break;
11556 case AXIS_NAMESPACE:
11557 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11558 break;
11559 case AXIS_PARENT:
11560 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11561 break;
11562 case AXIS_PRECEDING:
11563 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11564 break;
11565 case AXIS_PRECEDING_SIBLING:
11566 xmlGenericError(xmlGenericErrorContext,
11567 "axis 'preceding-sibling' ");
11568 break;
11569 case AXIS_SELF:
11570 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11571 break;
11572 }
11573 xmlGenericError(xmlGenericErrorContext,
11574 " context contains %d nodes\n", nbNodes);
11575 switch (op->value2) {
11576 case NODE_TEST_NONE:
11577 xmlGenericError(xmlGenericErrorContext,
11578 " searching for none !!!\n");
11579 break;
11580 case NODE_TEST_TYPE:
11581 xmlGenericError(xmlGenericErrorContext,
11582 " searching for type %d\n", op->value3);
11583 break;
11584 case NODE_TEST_PI:
11585 xmlGenericError(xmlGenericErrorContext,
11586 " searching for PI !!!\n");
11587 break;
11588 case NODE_TEST_ALL:
11589 xmlGenericError(xmlGenericErrorContext,
11590 " searching for *\n");
11591 break;
11592 case NODE_TEST_NS:
11593 xmlGenericError(xmlGenericErrorContext,
11594 " searching for namespace %s\n",
11595 op->value5);
11596 break;
11597 case NODE_TEST_NAME:
11598 xmlGenericError(xmlGenericErrorContext,
11599 " searching for name %s\n", op->value5);
11600 if (op->value4)
11601 xmlGenericError(xmlGenericErrorContext,
11602 " with namespace %s\n", op->value4);
11603 break;
11604 }
11605 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11606 }
11607 #endif /* DEBUG_STEP */
11608
11609 /**
11610 * xmlXPathNodeSetFilter:
11611 * @ctxt: the XPath Parser context
11612 * @set: the node set to filter
11613 * @filterOpIndex: the index of the predicate/filter op
11614 * @minPos: minimum position in the filtered set (1-based)
11615 * @maxPos: maximum position in the filtered set (1-based)
11616 * @hasNsNodes: true if the node set may contain namespace nodes
11617 *
11618 * Filter a node set, keeping only nodes for which the predicate expression
11619 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11620 * filtered result.
11621 */
11622 static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,xmlNodeSetPtr set,int filterOpIndex,int minPos,int maxPos,int hasNsNodes)11623 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11624 xmlNodeSetPtr set,
11625 int filterOpIndex,
11626 int minPos, int maxPos,
11627 int hasNsNodes)
11628 {
11629 xmlXPathContextPtr xpctxt;
11630 xmlNodePtr oldnode;
11631 xmlDocPtr olddoc;
11632 xmlXPathStepOpPtr filterOp;
11633 int oldcs, oldpp;
11634 int i, j, pos;
11635
11636 if ((set == NULL) || (set->nodeNr == 0))
11637 return;
11638
11639 /*
11640 * Check if the node set contains a sufficient number of nodes for
11641 * the requested range.
11642 */
11643 if (set->nodeNr < minPos) {
11644 xmlXPathNodeSetClear(set, hasNsNodes);
11645 return;
11646 }
11647
11648 xpctxt = ctxt->context;
11649 oldnode = xpctxt->node;
11650 olddoc = xpctxt->doc;
11651 oldcs = xpctxt->contextSize;
11652 oldpp = xpctxt->proximityPosition;
11653 filterOp = &ctxt->comp->steps[filterOpIndex];
11654
11655 xpctxt->contextSize = set->nodeNr;
11656
11657 for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11658 xmlNodePtr node = set->nodeTab[i];
11659 int res;
11660
11661 xpctxt->node = node;
11662 xpctxt->proximityPosition = i + 1;
11663
11664 /*
11665 * Also set the xpath document in case things like
11666 * key() are evaluated in the predicate.
11667 *
11668 * TODO: Get real doc for namespace nodes.
11669 */
11670 if ((node->type != XML_NAMESPACE_DECL) &&
11671 (node->doc != NULL))
11672 xpctxt->doc = node->doc;
11673
11674 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11675
11676 if (ctxt->error != XPATH_EXPRESSION_OK)
11677 break;
11678 if (res < 0) {
11679 /* Shouldn't happen */
11680 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11681 break;
11682 }
11683
11684 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11685 if (i != j) {
11686 set->nodeTab[j] = node;
11687 set->nodeTab[i] = NULL;
11688 }
11689
11690 j += 1;
11691 } else {
11692 /* Remove the entry from the initial node set. */
11693 set->nodeTab[i] = NULL;
11694 if (node->type == XML_NAMESPACE_DECL)
11695 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11696 }
11697
11698 if (res != 0) {
11699 if (pos == maxPos) {
11700 i += 1;
11701 break;
11702 }
11703
11704 pos += 1;
11705 }
11706 }
11707
11708 /* Free remaining nodes. */
11709 if (hasNsNodes) {
11710 for (; i < set->nodeNr; i++) {
11711 xmlNodePtr node = set->nodeTab[i];
11712 if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11713 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11714 }
11715 }
11716
11717 set->nodeNr = j;
11718
11719 /* If too many elements were removed, shrink table to preserve memory. */
11720 if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11721 (set->nodeNr < set->nodeMax / 2)) {
11722 xmlNodePtr *tmp;
11723 int nodeMax = set->nodeNr;
11724
11725 if (nodeMax < XML_NODESET_DEFAULT)
11726 nodeMax = XML_NODESET_DEFAULT;
11727 tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11728 nodeMax * sizeof(xmlNodePtr));
11729 if (tmp == NULL) {
11730 xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11731 } else {
11732 set->nodeTab = tmp;
11733 set->nodeMax = nodeMax;
11734 }
11735 }
11736
11737 xpctxt->node = oldnode;
11738 xpctxt->doc = olddoc;
11739 xpctxt->contextSize = oldcs;
11740 xpctxt->proximityPosition = oldpp;
11741 }
11742
11743 #ifdef LIBXML_XPTR_ENABLED
11744 /**
11745 * xmlXPathLocationSetFilter:
11746 * @ctxt: the XPath Parser context
11747 * @locset: the location set to filter
11748 * @filterOpIndex: the index of the predicate/filter op
11749 * @minPos: minimum position in the filtered set (1-based)
11750 * @maxPos: maximum position in the filtered set (1-based)
11751 *
11752 * Filter a location set, keeping only nodes for which the predicate
11753 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11754 * in the filtered result.
11755 */
11756 static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,xmlLocationSetPtr locset,int filterOpIndex,int minPos,int maxPos)11757 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11758 xmlLocationSetPtr locset,
11759 int filterOpIndex,
11760 int minPos, int maxPos)
11761 {
11762 xmlXPathContextPtr xpctxt;
11763 xmlNodePtr oldnode;
11764 xmlDocPtr olddoc;
11765 xmlXPathStepOpPtr filterOp;
11766 int oldcs, oldpp;
11767 int i, j, pos;
11768
11769 if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11770 return;
11771
11772 xpctxt = ctxt->context;
11773 oldnode = xpctxt->node;
11774 olddoc = xpctxt->doc;
11775 oldcs = xpctxt->contextSize;
11776 oldpp = xpctxt->proximityPosition;
11777 filterOp = &ctxt->comp->steps[filterOpIndex];
11778
11779 xpctxt->contextSize = locset->locNr;
11780
11781 for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11782 xmlNodePtr contextNode = locset->locTab[i]->user;
11783 int res;
11784
11785 xpctxt->node = contextNode;
11786 xpctxt->proximityPosition = i + 1;
11787
11788 /*
11789 * Also set the xpath document in case things like
11790 * key() are evaluated in the predicate.
11791 *
11792 * TODO: Get real doc for namespace nodes.
11793 */
11794 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11795 (contextNode->doc != NULL))
11796 xpctxt->doc = contextNode->doc;
11797
11798 res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11799
11800 if (ctxt->error != XPATH_EXPRESSION_OK)
11801 break;
11802 if (res < 0) {
11803 /* Shouldn't happen */
11804 xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11805 break;
11806 }
11807
11808 if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11809 if (i != j) {
11810 locset->locTab[j] = locset->locTab[i];
11811 locset->locTab[i] = NULL;
11812 }
11813
11814 j += 1;
11815 } else {
11816 /* Remove the entry from the initial location set. */
11817 xmlXPathFreeObject(locset->locTab[i]);
11818 locset->locTab[i] = NULL;
11819 }
11820
11821 if (res != 0) {
11822 if (pos == maxPos) {
11823 i += 1;
11824 break;
11825 }
11826
11827 pos += 1;
11828 }
11829 }
11830
11831 /* Free remaining nodes. */
11832 for (; i < locset->locNr; i++)
11833 xmlXPathFreeObject(locset->locTab[i]);
11834
11835 locset->locNr = j;
11836
11837 /* If too many elements were removed, shrink table to preserve memory. */
11838 if ((locset->locMax > XML_NODESET_DEFAULT) &&
11839 (locset->locNr < locset->locMax / 2)) {
11840 xmlXPathObjectPtr *tmp;
11841 int locMax = locset->locNr;
11842
11843 if (locMax < XML_NODESET_DEFAULT)
11844 locMax = XML_NODESET_DEFAULT;
11845 tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11846 locMax * sizeof(xmlXPathObjectPtr));
11847 if (tmp == NULL) {
11848 xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11849 } else {
11850 locset->locTab = tmp;
11851 locset->locMax = locMax;
11852 }
11853 }
11854
11855 xpctxt->node = oldnode;
11856 xpctxt->doc = olddoc;
11857 xpctxt->contextSize = oldcs;
11858 xpctxt->proximityPosition = oldpp;
11859 }
11860 #endif /* LIBXML_XPTR_ENABLED */
11861
11862 /**
11863 * xmlXPathCompOpEvalPredicate:
11864 * @ctxt: the XPath Parser context
11865 * @op: the predicate op
11866 * @set: the node set to filter
11867 * @minPos: minimum position in the filtered set (1-based)
11868 * @maxPos: maximum position in the filtered set (1-based)
11869 * @hasNsNodes: true if the node set may contain namespace nodes
11870 *
11871 * Filter a node set, keeping only nodes for which the sequence of predicate
11872 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11873 * in the filtered result.
11874 */
11875 static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int minPos,int maxPos,int hasNsNodes)11876 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11877 xmlXPathStepOpPtr op,
11878 xmlNodeSetPtr set,
11879 int minPos, int maxPos,
11880 int hasNsNodes)
11881 {
11882 if (op->ch1 != -1) {
11883 xmlXPathCompExprPtr comp = ctxt->comp;
11884 /*
11885 * Process inner predicates first.
11886 */
11887 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11888 xmlGenericError(xmlGenericErrorContext,
11889 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11890 XP_ERROR(XPATH_INVALID_OPERAND);
11891 }
11892 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11893 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11894 ctxt->context->depth += 1;
11895 xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11896 1, set->nodeNr, hasNsNodes);
11897 ctxt->context->depth -= 1;
11898 CHECK_ERROR;
11899 }
11900
11901 if (op->ch2 != -1)
11902 xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11903 }
11904
11905 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)11906 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11907 xmlXPathStepOpPtr op,
11908 int *maxPos)
11909 {
11910
11911 xmlXPathStepOpPtr exprOp;
11912
11913 /*
11914 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11915 */
11916
11917 /*
11918 * If not -1, then ch1 will point to:
11919 * 1) For predicates (XPATH_OP_PREDICATE):
11920 * - an inner predicate operator
11921 * 2) For filters (XPATH_OP_FILTER):
11922 * - an inner filter operator OR
11923 * - an expression selecting the node set.
11924 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11925 */
11926 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11927 return(0);
11928
11929 if (op->ch2 != -1) {
11930 exprOp = &ctxt->comp->steps[op->ch2];
11931 } else
11932 return(0);
11933
11934 if ((exprOp != NULL) &&
11935 (exprOp->op == XPATH_OP_VALUE) &&
11936 (exprOp->value4 != NULL) &&
11937 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11938 {
11939 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11940
11941 /*
11942 * We have a "[n]" predicate here.
11943 * TODO: Unfortunately this simplistic test here is not
11944 * able to detect a position() predicate in compound
11945 * expressions like "[@attr = 'a" and position() = 1],
11946 * and even not the usage of position() in
11947 * "[position() = 1]"; thus - obviously - a position-range,
11948 * like it "[position() < 5]", is also not detected.
11949 * Maybe we could rewrite the AST to ease the optimization.
11950 */
11951
11952 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11953 *maxPos = (int) floatval;
11954 if (floatval == (double) *maxPos)
11955 return(1);
11956 }
11957 }
11958 return(0);
11959 }
11960
11961 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)11962 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11963 xmlXPathStepOpPtr op,
11964 xmlNodePtr * first, xmlNodePtr * last,
11965 int toBool)
11966 {
11967
11968 #define XP_TEST_HIT \
11969 if (hasAxisRange != 0) { \
11970 if (++pos == maxPos) { \
11971 if (addNode(seq, cur) < 0) \
11972 ctxt->error = XPATH_MEMORY_ERROR; \
11973 goto axis_range_end; } \
11974 } else { \
11975 if (addNode(seq, cur) < 0) \
11976 ctxt->error = XPATH_MEMORY_ERROR; \
11977 if (breakOnFirstHit) goto first_hit; }
11978
11979 #define XP_TEST_HIT_NS \
11980 if (hasAxisRange != 0) { \
11981 if (++pos == maxPos) { \
11982 hasNsNodes = 1; \
11983 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11984 ctxt->error = XPATH_MEMORY_ERROR; \
11985 goto axis_range_end; } \
11986 } else { \
11987 hasNsNodes = 1; \
11988 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11989 ctxt->error = XPATH_MEMORY_ERROR; \
11990 if (breakOnFirstHit) goto first_hit; }
11991
11992 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11993 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11994 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11995 const xmlChar *prefix = op->value4;
11996 const xmlChar *name = op->value5;
11997 const xmlChar *URI = NULL;
11998
11999 #ifdef DEBUG_STEP
12000 int nbMatches = 0, prevMatches = 0;
12001 #endif
12002 int total = 0, hasNsNodes = 0;
12003 /* The popped object holding the context nodes */
12004 xmlXPathObjectPtr obj;
12005 /* The set of context nodes for the node tests */
12006 xmlNodeSetPtr contextSeq;
12007 int contextIdx;
12008 xmlNodePtr contextNode;
12009 /* The final resulting node set wrt to all context nodes */
12010 xmlNodeSetPtr outSeq;
12011 /*
12012 * The temporary resulting node set wrt 1 context node.
12013 * Used to feed predicate evaluation.
12014 */
12015 xmlNodeSetPtr seq;
12016 xmlNodePtr cur;
12017 /* First predicate operator */
12018 xmlXPathStepOpPtr predOp;
12019 int maxPos; /* The requested position() (when a "[n]" predicate) */
12020 int hasPredicateRange, hasAxisRange, pos;
12021 int breakOnFirstHit;
12022
12023 xmlXPathTraversalFunction next = NULL;
12024 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12025 xmlXPathNodeSetMergeFunction mergeAndClear;
12026 xmlNodePtr oldContextNode;
12027 xmlXPathContextPtr xpctxt = ctxt->context;
12028
12029
12030 CHECK_TYPE0(XPATH_NODESET);
12031 obj = valuePop(ctxt);
12032 /*
12033 * Setup namespaces.
12034 */
12035 if (prefix != NULL) {
12036 URI = xmlXPathNsLookup(xpctxt, prefix);
12037 if (URI == NULL) {
12038 xmlXPathReleaseObject(xpctxt, obj);
12039 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12040 }
12041 }
12042 /*
12043 * Setup axis.
12044 *
12045 * MAYBE FUTURE TODO: merging optimizations:
12046 * - If the nodes to be traversed wrt to the initial nodes and
12047 * the current axis cannot overlap, then we could avoid searching
12048 * for duplicates during the merge.
12049 * But the question is how/when to evaluate if they cannot overlap.
12050 * Example: if we know that for two initial nodes, the one is
12051 * not in the ancestor-or-self axis of the other, then we could safely
12052 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12053 * the descendant-or-self axis.
12054 */
12055 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12056 switch (axis) {
12057 case AXIS_ANCESTOR:
12058 first = NULL;
12059 next = xmlXPathNextAncestor;
12060 break;
12061 case AXIS_ANCESTOR_OR_SELF:
12062 first = NULL;
12063 next = xmlXPathNextAncestorOrSelf;
12064 break;
12065 case AXIS_ATTRIBUTE:
12066 first = NULL;
12067 last = NULL;
12068 next = xmlXPathNextAttribute;
12069 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12070 break;
12071 case AXIS_CHILD:
12072 last = NULL;
12073 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12074 (type == NODE_TYPE_NODE))
12075 {
12076 /*
12077 * Optimization if an element node type is 'element'.
12078 */
12079 next = xmlXPathNextChildElement;
12080 } else
12081 next = xmlXPathNextChild;
12082 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12083 break;
12084 case AXIS_DESCENDANT:
12085 last = NULL;
12086 next = xmlXPathNextDescendant;
12087 break;
12088 case AXIS_DESCENDANT_OR_SELF:
12089 last = NULL;
12090 next = xmlXPathNextDescendantOrSelf;
12091 break;
12092 case AXIS_FOLLOWING:
12093 last = NULL;
12094 next = xmlXPathNextFollowing;
12095 break;
12096 case AXIS_FOLLOWING_SIBLING:
12097 last = NULL;
12098 next = xmlXPathNextFollowingSibling;
12099 break;
12100 case AXIS_NAMESPACE:
12101 first = NULL;
12102 last = NULL;
12103 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12104 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12105 break;
12106 case AXIS_PARENT:
12107 first = NULL;
12108 next = xmlXPathNextParent;
12109 break;
12110 case AXIS_PRECEDING:
12111 first = NULL;
12112 next = xmlXPathNextPrecedingInternal;
12113 break;
12114 case AXIS_PRECEDING_SIBLING:
12115 first = NULL;
12116 next = xmlXPathNextPrecedingSibling;
12117 break;
12118 case AXIS_SELF:
12119 first = NULL;
12120 last = NULL;
12121 next = xmlXPathNextSelf;
12122 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12123 break;
12124 }
12125
12126 #ifdef DEBUG_STEP
12127 xmlXPathDebugDumpStepAxis(op,
12128 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12129 #endif
12130
12131 if (next == NULL) {
12132 xmlXPathReleaseObject(xpctxt, obj);
12133 return(0);
12134 }
12135 contextSeq = obj->nodesetval;
12136 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12137 xmlXPathReleaseObject(xpctxt, obj);
12138 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12139 return(0);
12140 }
12141 /*
12142 * Predicate optimization ---------------------------------------------
12143 * If this step has a last predicate, which contains a position(),
12144 * then we'll optimize (although not exactly "position()", but only
12145 * the short-hand form, i.e., "[n]".
12146 *
12147 * Example - expression "/foo[parent::bar][1]":
12148 *
12149 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12150 * ROOT -- op->ch1
12151 * PREDICATE -- op->ch2 (predOp)
12152 * PREDICATE -- predOp->ch1 = [parent::bar]
12153 * SORT
12154 * COLLECT 'parent' 'name' 'node' bar
12155 * NODE
12156 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12157 *
12158 */
12159 maxPos = 0;
12160 predOp = NULL;
12161 hasPredicateRange = 0;
12162 hasAxisRange = 0;
12163 if (op->ch2 != -1) {
12164 /*
12165 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12166 */
12167 predOp = &ctxt->comp->steps[op->ch2];
12168 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12169 if (predOp->ch1 != -1) {
12170 /*
12171 * Use the next inner predicate operator.
12172 */
12173 predOp = &ctxt->comp->steps[predOp->ch1];
12174 hasPredicateRange = 1;
12175 } else {
12176 /*
12177 * There's no other predicate than the [n] predicate.
12178 */
12179 predOp = NULL;
12180 hasAxisRange = 1;
12181 }
12182 }
12183 }
12184 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12185 /*
12186 * Axis traversal -----------------------------------------------------
12187 */
12188 /*
12189 * 2.3 Node Tests
12190 * - For the attribute axis, the principal node type is attribute.
12191 * - For the namespace axis, the principal node type is namespace.
12192 * - For other axes, the principal node type is element.
12193 *
12194 * A node test * is true for any node of the
12195 * principal node type. For example, child::* will
12196 * select all element children of the context node
12197 */
12198 oldContextNode = xpctxt->node;
12199 addNode = xmlXPathNodeSetAddUnique;
12200 outSeq = NULL;
12201 seq = NULL;
12202 contextNode = NULL;
12203 contextIdx = 0;
12204
12205
12206 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12207 (ctxt->error == XPATH_EXPRESSION_OK)) {
12208 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12209
12210 if (seq == NULL) {
12211 seq = xmlXPathNodeSetCreate(NULL);
12212 if (seq == NULL) {
12213 /* TODO: Propagate memory error. */
12214 total = 0;
12215 goto error;
12216 }
12217 }
12218 /*
12219 * Traverse the axis and test the nodes.
12220 */
12221 pos = 0;
12222 cur = NULL;
12223 hasNsNodes = 0;
12224 do {
12225 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12226 goto error;
12227
12228 cur = next(ctxt, cur);
12229 if (cur == NULL)
12230 break;
12231
12232 /*
12233 * QUESTION TODO: What does the "first" and "last" stuff do?
12234 */
12235 if ((first != NULL) && (*first != NULL)) {
12236 if (*first == cur)
12237 break;
12238 if (((total % 256) == 0) &&
12239 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12240 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12241 #else
12242 (xmlXPathCmpNodes(*first, cur) >= 0))
12243 #endif
12244 {
12245 break;
12246 }
12247 }
12248 if ((last != NULL) && (*last != NULL)) {
12249 if (*last == cur)
12250 break;
12251 if (((total % 256) == 0) &&
12252 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12253 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12254 #else
12255 (xmlXPathCmpNodes(cur, *last) >= 0))
12256 #endif
12257 {
12258 break;
12259 }
12260 }
12261
12262 total++;
12263
12264 #ifdef DEBUG_STEP
12265 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12266 #endif
12267
12268 switch (test) {
12269 case NODE_TEST_NONE:
12270 total = 0;
12271 STRANGE
12272 goto error;
12273 case NODE_TEST_TYPE:
12274 if (type == NODE_TYPE_NODE) {
12275 switch (cur->type) {
12276 case XML_DOCUMENT_NODE:
12277 case XML_HTML_DOCUMENT_NODE:
12278 #ifdef LIBXML_DOCB_ENABLED
12279 case XML_DOCB_DOCUMENT_NODE:
12280 #endif
12281 case XML_ELEMENT_NODE:
12282 case XML_ATTRIBUTE_NODE:
12283 case XML_PI_NODE:
12284 case XML_COMMENT_NODE:
12285 case XML_CDATA_SECTION_NODE:
12286 case XML_TEXT_NODE:
12287 XP_TEST_HIT
12288 break;
12289 case XML_NAMESPACE_DECL: {
12290 if (axis == AXIS_NAMESPACE) {
12291 XP_TEST_HIT_NS
12292 } else {
12293 hasNsNodes = 1;
12294 XP_TEST_HIT
12295 }
12296 break;
12297 }
12298 default:
12299 break;
12300 }
12301 } else if (cur->type == (xmlElementType) type) {
12302 if (cur->type == XML_NAMESPACE_DECL)
12303 XP_TEST_HIT_NS
12304 else
12305 XP_TEST_HIT
12306 } else if ((type == NODE_TYPE_TEXT) &&
12307 (cur->type == XML_CDATA_SECTION_NODE))
12308 {
12309 XP_TEST_HIT
12310 }
12311 break;
12312 case NODE_TEST_PI:
12313 if ((cur->type == XML_PI_NODE) &&
12314 ((name == NULL) || xmlStrEqual(name, cur->name)))
12315 {
12316 XP_TEST_HIT
12317 }
12318 break;
12319 case NODE_TEST_ALL:
12320 if (axis == AXIS_ATTRIBUTE) {
12321 if (cur->type == XML_ATTRIBUTE_NODE)
12322 {
12323 if (prefix == NULL)
12324 {
12325 XP_TEST_HIT
12326 } else if ((cur->ns != NULL) &&
12327 (xmlStrEqual(URI, cur->ns->href)))
12328 {
12329 XP_TEST_HIT
12330 }
12331 }
12332 } else if (axis == AXIS_NAMESPACE) {
12333 if (cur->type == XML_NAMESPACE_DECL)
12334 {
12335 XP_TEST_HIT_NS
12336 }
12337 } else {
12338 if (cur->type == XML_ELEMENT_NODE) {
12339 if (prefix == NULL)
12340 {
12341 XP_TEST_HIT
12342
12343 } else if ((cur->ns != NULL) &&
12344 (xmlStrEqual(URI, cur->ns->href)))
12345 {
12346 XP_TEST_HIT
12347 }
12348 }
12349 }
12350 break;
12351 case NODE_TEST_NS:{
12352 TODO;
12353 break;
12354 }
12355 case NODE_TEST_NAME:
12356 if (axis == AXIS_ATTRIBUTE) {
12357 if (cur->type != XML_ATTRIBUTE_NODE)
12358 break;
12359 } else if (axis == AXIS_NAMESPACE) {
12360 if (cur->type != XML_NAMESPACE_DECL)
12361 break;
12362 } else {
12363 if (cur->type != XML_ELEMENT_NODE)
12364 break;
12365 }
12366 switch (cur->type) {
12367 case XML_ELEMENT_NODE:
12368 if (xmlStrEqual(name, cur->name)) {
12369 if (prefix == NULL) {
12370 if (cur->ns == NULL)
12371 {
12372 XP_TEST_HIT
12373 }
12374 } else {
12375 if ((cur->ns != NULL) &&
12376 (xmlStrEqual(URI, cur->ns->href)))
12377 {
12378 XP_TEST_HIT
12379 }
12380 }
12381 }
12382 break;
12383 case XML_ATTRIBUTE_NODE:{
12384 xmlAttrPtr attr = (xmlAttrPtr) cur;
12385
12386 if (xmlStrEqual(name, attr->name)) {
12387 if (prefix == NULL) {
12388 if ((attr->ns == NULL) ||
12389 (attr->ns->prefix == NULL))
12390 {
12391 XP_TEST_HIT
12392 }
12393 } else {
12394 if ((attr->ns != NULL) &&
12395 (xmlStrEqual(URI,
12396 attr->ns->href)))
12397 {
12398 XP_TEST_HIT
12399 }
12400 }
12401 }
12402 break;
12403 }
12404 case XML_NAMESPACE_DECL:
12405 if (cur->type == XML_NAMESPACE_DECL) {
12406 xmlNsPtr ns = (xmlNsPtr) cur;
12407
12408 if ((ns->prefix != NULL) && (name != NULL)
12409 && (xmlStrEqual(ns->prefix, name)))
12410 {
12411 XP_TEST_HIT_NS
12412 }
12413 }
12414 break;
12415 default:
12416 break;
12417 }
12418 break;
12419 } /* switch(test) */
12420 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12421
12422 goto apply_predicates;
12423
12424 axis_range_end: /* ----------------------------------------------------- */
12425 /*
12426 * We have a "/foo[n]", and position() = n was reached.
12427 * Note that we can have as well "/foo/::parent::foo[1]", so
12428 * a duplicate-aware merge is still needed.
12429 * Merge with the result.
12430 */
12431 if (outSeq == NULL) {
12432 outSeq = seq;
12433 seq = NULL;
12434 } else
12435 /* TODO: Check memory error. */
12436 outSeq = mergeAndClear(outSeq, seq);
12437 /*
12438 * Break if only a true/false result was requested.
12439 */
12440 if (toBool)
12441 break;
12442 continue;
12443
12444 first_hit: /* ---------------------------------------------------------- */
12445 /*
12446 * Break if only a true/false result was requested and
12447 * no predicates existed and a node test succeeded.
12448 */
12449 if (outSeq == NULL) {
12450 outSeq = seq;
12451 seq = NULL;
12452 } else
12453 /* TODO: Check memory error. */
12454 outSeq = mergeAndClear(outSeq, seq);
12455 break;
12456
12457 #ifdef DEBUG_STEP
12458 if (seq != NULL)
12459 nbMatches += seq->nodeNr;
12460 #endif
12461
12462 apply_predicates: /* --------------------------------------------------- */
12463 if (ctxt->error != XPATH_EXPRESSION_OK)
12464 goto error;
12465
12466 /*
12467 * Apply predicates.
12468 */
12469 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12470 /*
12471 * E.g. when we have a "/foo[some expression][n]".
12472 */
12473 /*
12474 * QUESTION TODO: The old predicate evaluation took into
12475 * account location-sets.
12476 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12477 * Do we expect such a set here?
12478 * All what I learned now from the evaluation semantics
12479 * does not indicate that a location-set will be processed
12480 * here, so this looks OK.
12481 */
12482 /*
12483 * Iterate over all predicates, starting with the outermost
12484 * predicate.
12485 * TODO: Problem: we cannot execute the inner predicates first
12486 * since we cannot go back *up* the operator tree!
12487 * Options we have:
12488 * 1) Use of recursive functions (like is it currently done
12489 * via xmlXPathCompOpEval())
12490 * 2) Add a predicate evaluation information stack to the
12491 * context struct
12492 * 3) Change the way the operators are linked; we need a
12493 * "parent" field on xmlXPathStepOp
12494 *
12495 * For the moment, I'll try to solve this with a recursive
12496 * function: xmlXPathCompOpEvalPredicate().
12497 */
12498 if (hasPredicateRange != 0)
12499 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12500 hasNsNodes);
12501 else
12502 xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12503 hasNsNodes);
12504
12505 if (ctxt->error != XPATH_EXPRESSION_OK) {
12506 total = 0;
12507 goto error;
12508 }
12509 }
12510
12511 if (seq->nodeNr > 0) {
12512 /*
12513 * Add to result set.
12514 */
12515 if (outSeq == NULL) {
12516 outSeq = seq;
12517 seq = NULL;
12518 } else {
12519 /* TODO: Check memory error. */
12520 outSeq = mergeAndClear(outSeq, seq);
12521 }
12522
12523 if (toBool)
12524 break;
12525 }
12526 }
12527
12528 error:
12529 if ((obj->boolval) && (obj->user != NULL)) {
12530 /*
12531 * QUESTION TODO: What does this do and why?
12532 * TODO: Do we have to do this also for the "error"
12533 * cleanup further down?
12534 */
12535 ctxt->value->boolval = 1;
12536 ctxt->value->user = obj->user;
12537 obj->user = NULL;
12538 obj->boolval = 0;
12539 }
12540 xmlXPathReleaseObject(xpctxt, obj);
12541
12542 /*
12543 * Ensure we return at least an empty set.
12544 */
12545 if (outSeq == NULL) {
12546 if ((seq != NULL) && (seq->nodeNr == 0))
12547 outSeq = seq;
12548 else
12549 /* TODO: Check memory error. */
12550 outSeq = xmlXPathNodeSetCreate(NULL);
12551 }
12552 if ((seq != NULL) && (seq != outSeq)) {
12553 xmlXPathFreeNodeSet(seq);
12554 }
12555 /*
12556 * Hand over the result. Better to push the set also in
12557 * case of errors.
12558 */
12559 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12560 /*
12561 * Reset the context node.
12562 */
12563 xpctxt->node = oldContextNode;
12564 /*
12565 * When traversing the namespace axis in "toBool" mode, it's
12566 * possible that tmpNsList wasn't freed.
12567 */
12568 if (xpctxt->tmpNsList != NULL) {
12569 xmlFree(xpctxt->tmpNsList);
12570 xpctxt->tmpNsList = NULL;
12571 }
12572
12573 #ifdef DEBUG_STEP
12574 xmlGenericError(xmlGenericErrorContext,
12575 "\nExamined %d nodes, found %d nodes at that step\n",
12576 total, nbMatches);
12577 #endif
12578
12579 return(total);
12580 }
12581
12582 static int
12583 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12584 xmlXPathStepOpPtr op, xmlNodePtr * first);
12585
12586 /**
12587 * xmlXPathCompOpEvalFirst:
12588 * @ctxt: the XPath parser context with the compiled expression
12589 * @op: an XPath compiled operation
12590 * @first: the first elem found so far
12591 *
12592 * Evaluate the Precompiled XPath operation searching only the first
12593 * element in document order
12594 *
12595 * Returns the number of examined objects.
12596 */
12597 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12598 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12599 xmlXPathStepOpPtr op, xmlNodePtr * first)
12600 {
12601 int total = 0, cur;
12602 xmlXPathCompExprPtr comp;
12603 xmlXPathObjectPtr arg1, arg2;
12604
12605 CHECK_ERROR0;
12606 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12607 return(0);
12608 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12609 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12610 ctxt->context->depth += 1;
12611 comp = ctxt->comp;
12612 switch (op->op) {
12613 case XPATH_OP_END:
12614 break;
12615 case XPATH_OP_UNION:
12616 total =
12617 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12618 first);
12619 CHECK_ERROR0;
12620 if ((ctxt->value != NULL)
12621 && (ctxt->value->type == XPATH_NODESET)
12622 && (ctxt->value->nodesetval != NULL)
12623 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12624 /*
12625 * limit tree traversing to first node in the result
12626 */
12627 /*
12628 * OPTIMIZE TODO: This implicitly sorts
12629 * the result, even if not needed. E.g. if the argument
12630 * of the count() function, no sorting is needed.
12631 * OPTIMIZE TODO: How do we know if the node-list wasn't
12632 * already sorted?
12633 */
12634 if (ctxt->value->nodesetval->nodeNr > 1)
12635 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12636 *first = ctxt->value->nodesetval->nodeTab[0];
12637 }
12638 cur =
12639 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12640 first);
12641 CHECK_ERROR0;
12642
12643 arg2 = valuePop(ctxt);
12644 arg1 = valuePop(ctxt);
12645 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12646 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12647 xmlXPathReleaseObject(ctxt->context, arg1);
12648 xmlXPathReleaseObject(ctxt->context, arg2);
12649 XP_ERROR0(XPATH_INVALID_TYPE);
12650 }
12651 if ((ctxt->context->opLimit != 0) &&
12652 (((arg1->nodesetval != NULL) &&
12653 (xmlXPathCheckOpLimit(ctxt,
12654 arg1->nodesetval->nodeNr) < 0)) ||
12655 ((arg2->nodesetval != NULL) &&
12656 (xmlXPathCheckOpLimit(ctxt,
12657 arg2->nodesetval->nodeNr) < 0)))) {
12658 xmlXPathReleaseObject(ctxt->context, arg1);
12659 xmlXPathReleaseObject(ctxt->context, arg2);
12660 break;
12661 }
12662
12663 /* TODO: Check memory error. */
12664 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12665 arg2->nodesetval);
12666 valuePush(ctxt, arg1);
12667 xmlXPathReleaseObject(ctxt->context, arg2);
12668 /* optimizer */
12669 if (total > cur)
12670 xmlXPathCompSwap(op);
12671 total += cur;
12672 break;
12673 case XPATH_OP_ROOT:
12674 xmlXPathRoot(ctxt);
12675 break;
12676 case XPATH_OP_NODE:
12677 if (op->ch1 != -1)
12678 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12679 CHECK_ERROR0;
12680 if (op->ch2 != -1)
12681 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12682 CHECK_ERROR0;
12683 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12684 ctxt->context->node));
12685 break;
12686 case XPATH_OP_COLLECT:{
12687 if (op->ch1 == -1)
12688 break;
12689
12690 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12691 CHECK_ERROR0;
12692
12693 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12694 break;
12695 }
12696 case XPATH_OP_VALUE:
12697 valuePush(ctxt,
12698 xmlXPathCacheObjectCopy(ctxt->context,
12699 (xmlXPathObjectPtr) op->value4));
12700 break;
12701 case XPATH_OP_SORT:
12702 if (op->ch1 != -1)
12703 total +=
12704 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12705 first);
12706 CHECK_ERROR0;
12707 if ((ctxt->value != NULL)
12708 && (ctxt->value->type == XPATH_NODESET)
12709 && (ctxt->value->nodesetval != NULL)
12710 && (ctxt->value->nodesetval->nodeNr > 1))
12711 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12712 break;
12713 #ifdef XP_OPTIMIZED_FILTER_FIRST
12714 case XPATH_OP_FILTER:
12715 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12716 break;
12717 #endif
12718 default:
12719 total += xmlXPathCompOpEval(ctxt, op);
12720 break;
12721 }
12722
12723 ctxt->context->depth -= 1;
12724 return(total);
12725 }
12726
12727 /**
12728 * xmlXPathCompOpEvalLast:
12729 * @ctxt: the XPath parser context with the compiled expression
12730 * @op: an XPath compiled operation
12731 * @last: the last elem found so far
12732 *
12733 * Evaluate the Precompiled XPath operation searching only the last
12734 * element in document order
12735 *
12736 * Returns the number of nodes traversed
12737 */
12738 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12739 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12740 xmlNodePtr * last)
12741 {
12742 int total = 0, cur;
12743 xmlXPathCompExprPtr comp;
12744 xmlXPathObjectPtr arg1, arg2;
12745
12746 CHECK_ERROR0;
12747 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12748 return(0);
12749 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12750 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12751 ctxt->context->depth += 1;
12752 comp = ctxt->comp;
12753 switch (op->op) {
12754 case XPATH_OP_END:
12755 break;
12756 case XPATH_OP_UNION:
12757 total =
12758 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12759 CHECK_ERROR0;
12760 if ((ctxt->value != NULL)
12761 && (ctxt->value->type == XPATH_NODESET)
12762 && (ctxt->value->nodesetval != NULL)
12763 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12764 /*
12765 * limit tree traversing to first node in the result
12766 */
12767 if (ctxt->value->nodesetval->nodeNr > 1)
12768 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12769 *last =
12770 ctxt->value->nodesetval->nodeTab[ctxt->value->
12771 nodesetval->nodeNr -
12772 1];
12773 }
12774 cur =
12775 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12776 CHECK_ERROR0;
12777 if ((ctxt->value != NULL)
12778 && (ctxt->value->type == XPATH_NODESET)
12779 && (ctxt->value->nodesetval != NULL)
12780 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12781 }
12782
12783 arg2 = valuePop(ctxt);
12784 arg1 = valuePop(ctxt);
12785 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12786 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12787 xmlXPathReleaseObject(ctxt->context, arg1);
12788 xmlXPathReleaseObject(ctxt->context, arg2);
12789 XP_ERROR0(XPATH_INVALID_TYPE);
12790 }
12791 if ((ctxt->context->opLimit != 0) &&
12792 (((arg1->nodesetval != NULL) &&
12793 (xmlXPathCheckOpLimit(ctxt,
12794 arg1->nodesetval->nodeNr) < 0)) ||
12795 ((arg2->nodesetval != NULL) &&
12796 (xmlXPathCheckOpLimit(ctxt,
12797 arg2->nodesetval->nodeNr) < 0)))) {
12798 xmlXPathReleaseObject(ctxt->context, arg1);
12799 xmlXPathReleaseObject(ctxt->context, arg2);
12800 break;
12801 }
12802
12803 /* TODO: Check memory error. */
12804 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12805 arg2->nodesetval);
12806 valuePush(ctxt, arg1);
12807 xmlXPathReleaseObject(ctxt->context, arg2);
12808 /* optimizer */
12809 if (total > cur)
12810 xmlXPathCompSwap(op);
12811 total += cur;
12812 break;
12813 case XPATH_OP_ROOT:
12814 xmlXPathRoot(ctxt);
12815 break;
12816 case XPATH_OP_NODE:
12817 if (op->ch1 != -1)
12818 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12819 CHECK_ERROR0;
12820 if (op->ch2 != -1)
12821 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12822 CHECK_ERROR0;
12823 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12824 ctxt->context->node));
12825 break;
12826 case XPATH_OP_COLLECT:{
12827 if (op->ch1 == -1)
12828 break;
12829
12830 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12831 CHECK_ERROR0;
12832
12833 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12834 break;
12835 }
12836 case XPATH_OP_VALUE:
12837 valuePush(ctxt,
12838 xmlXPathCacheObjectCopy(ctxt->context,
12839 (xmlXPathObjectPtr) op->value4));
12840 break;
12841 case XPATH_OP_SORT:
12842 if (op->ch1 != -1)
12843 total +=
12844 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12845 last);
12846 CHECK_ERROR0;
12847 if ((ctxt->value != NULL)
12848 && (ctxt->value->type == XPATH_NODESET)
12849 && (ctxt->value->nodesetval != NULL)
12850 && (ctxt->value->nodesetval->nodeNr > 1))
12851 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12852 break;
12853 default:
12854 total += xmlXPathCompOpEval(ctxt, op);
12855 break;
12856 }
12857
12858 ctxt->context->depth -= 1;
12859 return (total);
12860 }
12861
12862 #ifdef XP_OPTIMIZED_FILTER_FIRST
12863 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12864 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12865 xmlXPathStepOpPtr op, xmlNodePtr * first)
12866 {
12867 int total = 0;
12868 xmlXPathCompExprPtr comp;
12869 xmlNodeSetPtr set;
12870
12871 CHECK_ERROR0;
12872 comp = ctxt->comp;
12873 /*
12874 * Optimization for ()[last()] selection i.e. the last elem
12875 */
12876 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12877 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12878 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12879 int f = comp->steps[op->ch2].ch1;
12880
12881 if ((f != -1) &&
12882 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12883 (comp->steps[f].value5 == NULL) &&
12884 (comp->steps[f].value == 0) &&
12885 (comp->steps[f].value4 != NULL) &&
12886 (xmlStrEqual
12887 (comp->steps[f].value4, BAD_CAST "last"))) {
12888 xmlNodePtr last = NULL;
12889
12890 total +=
12891 xmlXPathCompOpEvalLast(ctxt,
12892 &comp->steps[op->ch1],
12893 &last);
12894 CHECK_ERROR0;
12895 /*
12896 * The nodeset should be in document order,
12897 * Keep only the last value
12898 */
12899 if ((ctxt->value != NULL) &&
12900 (ctxt->value->type == XPATH_NODESET) &&
12901 (ctxt->value->nodesetval != NULL) &&
12902 (ctxt->value->nodesetval->nodeTab != NULL) &&
12903 (ctxt->value->nodesetval->nodeNr > 1)) {
12904 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12905 *first = *(ctxt->value->nodesetval->nodeTab);
12906 }
12907 return (total);
12908 }
12909 }
12910
12911 if (op->ch1 != -1)
12912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12913 CHECK_ERROR0;
12914 if (op->ch2 == -1)
12915 return (total);
12916 if (ctxt->value == NULL)
12917 return (total);
12918
12919 #ifdef LIBXML_XPTR_ENABLED
12920 /*
12921 * Hum are we filtering the result of an XPointer expression
12922 */
12923 if (ctxt->value->type == XPATH_LOCATIONSET) {
12924 xmlLocationSetPtr locset = ctxt->value->user;
12925
12926 if (locset != NULL) {
12927 xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12928 if (locset->locNr > 0)
12929 *first = (xmlNodePtr) locset->locTab[0]->user;
12930 }
12931
12932 return (total);
12933 }
12934 #endif /* LIBXML_XPTR_ENABLED */
12935
12936 CHECK_TYPE0(XPATH_NODESET);
12937 set = ctxt->value->nodesetval;
12938 if (set != NULL) {
12939 xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12940 if (set->nodeNr > 0)
12941 *first = set->nodeTab[0];
12942 }
12943
12944 return (total);
12945 }
12946 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12947
12948 /**
12949 * xmlXPathCompOpEval:
12950 * @ctxt: the XPath parser context with the compiled expression
12951 * @op: an XPath compiled operation
12952 *
12953 * Evaluate the Precompiled XPath operation
12954 * Returns the number of nodes traversed
12955 */
12956 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)12957 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12958 {
12959 int total = 0;
12960 int equal, ret;
12961 xmlXPathCompExprPtr comp;
12962 xmlXPathObjectPtr arg1, arg2;
12963
12964 CHECK_ERROR0;
12965 if (OP_LIMIT_EXCEEDED(ctxt, 1))
12966 return(0);
12967 if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12968 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12969 ctxt->context->depth += 1;
12970 comp = ctxt->comp;
12971 switch (op->op) {
12972 case XPATH_OP_END:
12973 break;
12974 case XPATH_OP_AND:
12975 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12976 CHECK_ERROR0;
12977 xmlXPathBooleanFunction(ctxt, 1);
12978 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12979 break;
12980 arg2 = valuePop(ctxt);
12981 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12982 if (ctxt->error) {
12983 xmlXPathFreeObject(arg2);
12984 break;
12985 }
12986 xmlXPathBooleanFunction(ctxt, 1);
12987 if (ctxt->value != NULL)
12988 ctxt->value->boolval &= arg2->boolval;
12989 xmlXPathReleaseObject(ctxt->context, arg2);
12990 break;
12991 case XPATH_OP_OR:
12992 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12993 CHECK_ERROR0;
12994 xmlXPathBooleanFunction(ctxt, 1);
12995 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12996 break;
12997 arg2 = valuePop(ctxt);
12998 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12999 if (ctxt->error) {
13000 xmlXPathFreeObject(arg2);
13001 break;
13002 }
13003 xmlXPathBooleanFunction(ctxt, 1);
13004 if (ctxt->value != NULL)
13005 ctxt->value->boolval |= arg2->boolval;
13006 xmlXPathReleaseObject(ctxt->context, arg2);
13007 break;
13008 case XPATH_OP_EQUAL:
13009 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13010 CHECK_ERROR0;
13011 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13012 CHECK_ERROR0;
13013 if (op->value)
13014 equal = xmlXPathEqualValues(ctxt);
13015 else
13016 equal = xmlXPathNotEqualValues(ctxt);
13017 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13018 break;
13019 case XPATH_OP_CMP:
13020 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13021 CHECK_ERROR0;
13022 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13023 CHECK_ERROR0;
13024 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13025 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13026 break;
13027 case XPATH_OP_PLUS:
13028 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13029 CHECK_ERROR0;
13030 if (op->ch2 != -1) {
13031 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13032 }
13033 CHECK_ERROR0;
13034 if (op->value == 0)
13035 xmlXPathSubValues(ctxt);
13036 else if (op->value == 1)
13037 xmlXPathAddValues(ctxt);
13038 else if (op->value == 2)
13039 xmlXPathValueFlipSign(ctxt);
13040 else if (op->value == 3) {
13041 CAST_TO_NUMBER;
13042 CHECK_TYPE0(XPATH_NUMBER);
13043 }
13044 break;
13045 case XPATH_OP_MULT:
13046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13047 CHECK_ERROR0;
13048 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13049 CHECK_ERROR0;
13050 if (op->value == 0)
13051 xmlXPathMultValues(ctxt);
13052 else if (op->value == 1)
13053 xmlXPathDivValues(ctxt);
13054 else if (op->value == 2)
13055 xmlXPathModValues(ctxt);
13056 break;
13057 case XPATH_OP_UNION:
13058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13059 CHECK_ERROR0;
13060 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13061 CHECK_ERROR0;
13062
13063 arg2 = valuePop(ctxt);
13064 arg1 = valuePop(ctxt);
13065 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13066 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13067 xmlXPathReleaseObject(ctxt->context, arg1);
13068 xmlXPathReleaseObject(ctxt->context, arg2);
13069 XP_ERROR0(XPATH_INVALID_TYPE);
13070 }
13071 if ((ctxt->context->opLimit != 0) &&
13072 (((arg1->nodesetval != NULL) &&
13073 (xmlXPathCheckOpLimit(ctxt,
13074 arg1->nodesetval->nodeNr) < 0)) ||
13075 ((arg2->nodesetval != NULL) &&
13076 (xmlXPathCheckOpLimit(ctxt,
13077 arg2->nodesetval->nodeNr) < 0)))) {
13078 xmlXPathReleaseObject(ctxt->context, arg1);
13079 xmlXPathReleaseObject(ctxt->context, arg2);
13080 break;
13081 }
13082
13083 if ((arg1->nodesetval == NULL) ||
13084 ((arg2->nodesetval != NULL) &&
13085 (arg2->nodesetval->nodeNr != 0)))
13086 {
13087 /* TODO: Check memory error. */
13088 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13089 arg2->nodesetval);
13090 }
13091
13092 valuePush(ctxt, arg1);
13093 xmlXPathReleaseObject(ctxt->context, arg2);
13094 break;
13095 case XPATH_OP_ROOT:
13096 xmlXPathRoot(ctxt);
13097 break;
13098 case XPATH_OP_NODE:
13099 if (op->ch1 != -1)
13100 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13101 CHECK_ERROR0;
13102 if (op->ch2 != -1)
13103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13104 CHECK_ERROR0;
13105 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13106 ctxt->context->node));
13107 break;
13108 case XPATH_OP_COLLECT:{
13109 if (op->ch1 == -1)
13110 break;
13111
13112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13113 CHECK_ERROR0;
13114
13115 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13116 break;
13117 }
13118 case XPATH_OP_VALUE:
13119 valuePush(ctxt,
13120 xmlXPathCacheObjectCopy(ctxt->context,
13121 (xmlXPathObjectPtr) op->value4));
13122 break;
13123 case XPATH_OP_VARIABLE:{
13124 xmlXPathObjectPtr val;
13125
13126 if (op->ch1 != -1)
13127 total +=
13128 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13129 if (op->value5 == NULL) {
13130 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13131 if (val == NULL)
13132 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13133 valuePush(ctxt, val);
13134 } else {
13135 const xmlChar *URI;
13136
13137 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13138 if (URI == NULL) {
13139 xmlGenericError(xmlGenericErrorContext,
13140 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13141 (char *) op->value4, (char *)op->value5);
13142 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13143 break;
13144 }
13145 val = xmlXPathVariableLookupNS(ctxt->context,
13146 op->value4, URI);
13147 if (val == NULL)
13148 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13149 valuePush(ctxt, val);
13150 }
13151 break;
13152 }
13153 case XPATH_OP_FUNCTION:{
13154 xmlXPathFunction func;
13155 const xmlChar *oldFunc, *oldFuncURI;
13156 int i;
13157 int frame;
13158
13159 frame = xmlXPathSetFrame(ctxt);
13160 if (op->ch1 != -1) {
13161 total +=
13162 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13163 if (ctxt->error != XPATH_EXPRESSION_OK) {
13164 xmlXPathPopFrame(ctxt, frame);
13165 break;
13166 }
13167 }
13168 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13169 xmlGenericError(xmlGenericErrorContext,
13170 "xmlXPathCompOpEval: parameter error\n");
13171 ctxt->error = XPATH_INVALID_OPERAND;
13172 xmlXPathPopFrame(ctxt, frame);
13173 break;
13174 }
13175 for (i = 0; i < op->value; i++) {
13176 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13177 xmlGenericError(xmlGenericErrorContext,
13178 "xmlXPathCompOpEval: parameter error\n");
13179 ctxt->error = XPATH_INVALID_OPERAND;
13180 xmlXPathPopFrame(ctxt, frame);
13181 break;
13182 }
13183 }
13184 if (op->cache != NULL)
13185 func = op->cache;
13186 else {
13187 const xmlChar *URI = NULL;
13188
13189 if (op->value5 == NULL)
13190 func =
13191 xmlXPathFunctionLookup(ctxt->context,
13192 op->value4);
13193 else {
13194 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13195 if (URI == NULL) {
13196 xmlGenericError(xmlGenericErrorContext,
13197 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13198 (char *)op->value4, (char *)op->value5);
13199 xmlXPathPopFrame(ctxt, frame);
13200 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13201 break;
13202 }
13203 func = xmlXPathFunctionLookupNS(ctxt->context,
13204 op->value4, URI);
13205 }
13206 if (func == NULL) {
13207 xmlGenericError(xmlGenericErrorContext,
13208 "xmlXPathCompOpEval: function %s not found\n",
13209 (char *)op->value4);
13210 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13211 }
13212 op->cache = func;
13213 op->cacheURI = (void *) URI;
13214 }
13215 oldFunc = ctxt->context->function;
13216 oldFuncURI = ctxt->context->functionURI;
13217 ctxt->context->function = op->value4;
13218 ctxt->context->functionURI = op->cacheURI;
13219 func(ctxt, op->value);
13220 ctxt->context->function = oldFunc;
13221 ctxt->context->functionURI = oldFuncURI;
13222 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13223 (ctxt->valueNr != ctxt->valueFrame + 1))
13224 XP_ERROR0(XPATH_STACK_ERROR);
13225 xmlXPathPopFrame(ctxt, frame);
13226 break;
13227 }
13228 case XPATH_OP_ARG:
13229 if (op->ch1 != -1) {
13230 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13231 CHECK_ERROR0;
13232 }
13233 if (op->ch2 != -1) {
13234 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13235 CHECK_ERROR0;
13236 }
13237 break;
13238 case XPATH_OP_PREDICATE:
13239 case XPATH_OP_FILTER:{
13240 xmlNodeSetPtr set;
13241
13242 /*
13243 * Optimization for ()[1] selection i.e. the first elem
13244 */
13245 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13246 #ifdef XP_OPTIMIZED_FILTER_FIRST
13247 /*
13248 * FILTER TODO: Can we assume that the inner processing
13249 * will result in an ordered list if we have an
13250 * XPATH_OP_FILTER?
13251 * What about an additional field or flag on
13252 * xmlXPathObject like @sorted ? This way we wouldn't need
13253 * to assume anything, so it would be more robust and
13254 * easier to optimize.
13255 */
13256 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13257 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13258 #else
13259 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13260 #endif
13261 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13262 xmlXPathObjectPtr val;
13263
13264 val = comp->steps[op->ch2].value4;
13265 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13266 (val->floatval == 1.0)) {
13267 xmlNodePtr first = NULL;
13268
13269 total +=
13270 xmlXPathCompOpEvalFirst(ctxt,
13271 &comp->steps[op->ch1],
13272 &first);
13273 CHECK_ERROR0;
13274 /*
13275 * The nodeset should be in document order,
13276 * Keep only the first value
13277 */
13278 if ((ctxt->value != NULL) &&
13279 (ctxt->value->type == XPATH_NODESET) &&
13280 (ctxt->value->nodesetval != NULL) &&
13281 (ctxt->value->nodesetval->nodeNr > 1))
13282 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13283 1, 1);
13284 break;
13285 }
13286 }
13287 /*
13288 * Optimization for ()[last()] selection i.e. the last elem
13289 */
13290 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13291 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13292 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13293 int f = comp->steps[op->ch2].ch1;
13294
13295 if ((f != -1) &&
13296 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13297 (comp->steps[f].value5 == NULL) &&
13298 (comp->steps[f].value == 0) &&
13299 (comp->steps[f].value4 != NULL) &&
13300 (xmlStrEqual
13301 (comp->steps[f].value4, BAD_CAST "last"))) {
13302 xmlNodePtr last = NULL;
13303
13304 total +=
13305 xmlXPathCompOpEvalLast(ctxt,
13306 &comp->steps[op->ch1],
13307 &last);
13308 CHECK_ERROR0;
13309 /*
13310 * The nodeset should be in document order,
13311 * Keep only the last value
13312 */
13313 if ((ctxt->value != NULL) &&
13314 (ctxt->value->type == XPATH_NODESET) &&
13315 (ctxt->value->nodesetval != NULL) &&
13316 (ctxt->value->nodesetval->nodeTab != NULL) &&
13317 (ctxt->value->nodesetval->nodeNr > 1))
13318 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13319 break;
13320 }
13321 }
13322 /*
13323 * Process inner predicates first.
13324 * Example "index[parent::book][1]":
13325 * ...
13326 * PREDICATE <-- we are here "[1]"
13327 * PREDICATE <-- process "[parent::book]" first
13328 * SORT
13329 * COLLECT 'parent' 'name' 'node' book
13330 * NODE
13331 * ELEM Object is a number : 1
13332 */
13333 if (op->ch1 != -1)
13334 total +=
13335 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13336 CHECK_ERROR0;
13337 if (op->ch2 == -1)
13338 break;
13339 if (ctxt->value == NULL)
13340 break;
13341
13342 #ifdef LIBXML_XPTR_ENABLED
13343 /*
13344 * Hum are we filtering the result of an XPointer expression
13345 */
13346 if (ctxt->value->type == XPATH_LOCATIONSET) {
13347 xmlLocationSetPtr locset = ctxt->value->user;
13348 xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13349 1, locset->locNr);
13350 break;
13351 }
13352 #endif /* LIBXML_XPTR_ENABLED */
13353
13354 CHECK_TYPE0(XPATH_NODESET);
13355 set = ctxt->value->nodesetval;
13356 if (set != NULL)
13357 xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13358 1, set->nodeNr, 1);
13359 break;
13360 }
13361 case XPATH_OP_SORT:
13362 if (op->ch1 != -1)
13363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13364 CHECK_ERROR0;
13365 if ((ctxt->value != NULL) &&
13366 (ctxt->value->type == XPATH_NODESET) &&
13367 (ctxt->value->nodesetval != NULL) &&
13368 (ctxt->value->nodesetval->nodeNr > 1))
13369 {
13370 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13371 }
13372 break;
13373 #ifdef LIBXML_XPTR_ENABLED
13374 case XPATH_OP_RANGETO:{
13375 xmlXPathObjectPtr range;
13376 xmlXPathObjectPtr res, obj;
13377 xmlXPathObjectPtr tmp;
13378 xmlLocationSetPtr newlocset = NULL;
13379 xmlLocationSetPtr oldlocset;
13380 xmlNodeSetPtr oldset;
13381 xmlNodePtr oldnode = ctxt->context->node;
13382 int oldcs = ctxt->context->contextSize;
13383 int oldpp = ctxt->context->proximityPosition;
13384 int i, j;
13385
13386 if (op->ch1 != -1) {
13387 total +=
13388 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13389 CHECK_ERROR0;
13390 }
13391 if (ctxt->value == NULL) {
13392 XP_ERROR0(XPATH_INVALID_OPERAND);
13393 }
13394 if (op->ch2 == -1)
13395 break;
13396
13397 if (ctxt->value->type == XPATH_LOCATIONSET) {
13398 /*
13399 * Extract the old locset, and then evaluate the result of the
13400 * expression for all the element in the locset. use it to grow
13401 * up a new locset.
13402 */
13403 CHECK_TYPE0(XPATH_LOCATIONSET);
13404
13405 if ((ctxt->value->user == NULL) ||
13406 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13407 break;
13408
13409 obj = valuePop(ctxt);
13410 oldlocset = obj->user;
13411
13412 newlocset = xmlXPtrLocationSetCreate(NULL);
13413
13414 for (i = 0; i < oldlocset->locNr; i++) {
13415 /*
13416 * Run the evaluation with a node list made of a
13417 * single item in the nodelocset.
13418 */
13419 ctxt->context->node = oldlocset->locTab[i]->user;
13420 ctxt->context->contextSize = oldlocset->locNr;
13421 ctxt->context->proximityPosition = i + 1;
13422 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13423 ctxt->context->node);
13424 valuePush(ctxt, tmp);
13425
13426 if (op->ch2 != -1)
13427 total +=
13428 xmlXPathCompOpEval(ctxt,
13429 &comp->steps[op->ch2]);
13430 if (ctxt->error != XPATH_EXPRESSION_OK) {
13431 xmlXPtrFreeLocationSet(newlocset);
13432 goto rangeto_error;
13433 }
13434
13435 res = valuePop(ctxt);
13436 if (res->type == XPATH_LOCATIONSET) {
13437 xmlLocationSetPtr rloc =
13438 (xmlLocationSetPtr)res->user;
13439 for (j=0; j<rloc->locNr; j++) {
13440 range = xmlXPtrNewRange(
13441 oldlocset->locTab[i]->user,
13442 oldlocset->locTab[i]->index,
13443 rloc->locTab[j]->user2,
13444 rloc->locTab[j]->index2);
13445 if (range != NULL) {
13446 xmlXPtrLocationSetAdd(newlocset, range);
13447 }
13448 }
13449 } else {
13450 range = xmlXPtrNewRangeNodeObject(
13451 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13452 if (range != NULL) {
13453 xmlXPtrLocationSetAdd(newlocset,range);
13454 }
13455 }
13456
13457 /*
13458 * Cleanup
13459 */
13460 if (res != NULL) {
13461 xmlXPathReleaseObject(ctxt->context, res);
13462 }
13463 if (ctxt->value == tmp) {
13464 res = valuePop(ctxt);
13465 xmlXPathReleaseObject(ctxt->context, res);
13466 }
13467 }
13468 } else { /* Not a location set */
13469 CHECK_TYPE0(XPATH_NODESET);
13470 obj = valuePop(ctxt);
13471 oldset = obj->nodesetval;
13472
13473 newlocset = xmlXPtrLocationSetCreate(NULL);
13474
13475 if (oldset != NULL) {
13476 for (i = 0; i < oldset->nodeNr; i++) {
13477 /*
13478 * Run the evaluation with a node list made of a single item
13479 * in the nodeset.
13480 */
13481 ctxt->context->node = oldset->nodeTab[i];
13482 /*
13483 * OPTIMIZE TODO: Avoid recreation for every iteration.
13484 */
13485 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13486 ctxt->context->node);
13487 valuePush(ctxt, tmp);
13488
13489 if (op->ch2 != -1)
13490 total +=
13491 xmlXPathCompOpEval(ctxt,
13492 &comp->steps[op->ch2]);
13493 if (ctxt->error != XPATH_EXPRESSION_OK) {
13494 xmlXPtrFreeLocationSet(newlocset);
13495 goto rangeto_error;
13496 }
13497
13498 res = valuePop(ctxt);
13499 range =
13500 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13501 res);
13502 if (range != NULL) {
13503 xmlXPtrLocationSetAdd(newlocset, range);
13504 }
13505
13506 /*
13507 * Cleanup
13508 */
13509 if (res != NULL) {
13510 xmlXPathReleaseObject(ctxt->context, res);
13511 }
13512 if (ctxt->value == tmp) {
13513 res = valuePop(ctxt);
13514 xmlXPathReleaseObject(ctxt->context, res);
13515 }
13516 }
13517 }
13518 }
13519
13520 /*
13521 * The result is used as the new evaluation set.
13522 */
13523 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13524 rangeto_error:
13525 xmlXPathReleaseObject(ctxt->context, obj);
13526 ctxt->context->node = oldnode;
13527 ctxt->context->contextSize = oldcs;
13528 ctxt->context->proximityPosition = oldpp;
13529 break;
13530 }
13531 #endif /* LIBXML_XPTR_ENABLED */
13532 default:
13533 xmlGenericError(xmlGenericErrorContext,
13534 "XPath: unknown precompiled operation %d\n", op->op);
13535 ctxt->error = XPATH_INVALID_OPERAND;
13536 break;
13537 }
13538
13539 ctxt->context->depth -= 1;
13540 return (total);
13541 }
13542
13543 /**
13544 * xmlXPathCompOpEvalToBoolean:
13545 * @ctxt: the XPath parser context
13546 *
13547 * Evaluates if the expression evaluates to true.
13548 *
13549 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13550 */
13551 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)13552 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13553 xmlXPathStepOpPtr op,
13554 int isPredicate)
13555 {
13556 xmlXPathObjectPtr resObj = NULL;
13557
13558 start:
13559 if (OP_LIMIT_EXCEEDED(ctxt, 1))
13560 return(0);
13561 /* comp = ctxt->comp; */
13562 switch (op->op) {
13563 case XPATH_OP_END:
13564 return (0);
13565 case XPATH_OP_VALUE:
13566 resObj = (xmlXPathObjectPtr) op->value4;
13567 if (isPredicate)
13568 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13569 return(xmlXPathCastToBoolean(resObj));
13570 case XPATH_OP_SORT:
13571 /*
13572 * We don't need sorting for boolean results. Skip this one.
13573 */
13574 if (op->ch1 != -1) {
13575 op = &ctxt->comp->steps[op->ch1];
13576 goto start;
13577 }
13578 return(0);
13579 case XPATH_OP_COLLECT:
13580 if (op->ch1 == -1)
13581 return(0);
13582
13583 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13584 if (ctxt->error != XPATH_EXPRESSION_OK)
13585 return(-1);
13586
13587 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13588 if (ctxt->error != XPATH_EXPRESSION_OK)
13589 return(-1);
13590
13591 resObj = valuePop(ctxt);
13592 if (resObj == NULL)
13593 return(-1);
13594 break;
13595 default:
13596 /*
13597 * Fallback to call xmlXPathCompOpEval().
13598 */
13599 xmlXPathCompOpEval(ctxt, op);
13600 if (ctxt->error != XPATH_EXPRESSION_OK)
13601 return(-1);
13602
13603 resObj = valuePop(ctxt);
13604 if (resObj == NULL)
13605 return(-1);
13606 break;
13607 }
13608
13609 if (resObj) {
13610 int res;
13611
13612 if (resObj->type == XPATH_BOOLEAN) {
13613 res = resObj->boolval;
13614 } else if (isPredicate) {
13615 /*
13616 * For predicates a result of type "number" is handled
13617 * differently:
13618 * SPEC XPath 1.0:
13619 * "If the result is a number, the result will be converted
13620 * to true if the number is equal to the context position
13621 * and will be converted to false otherwise;"
13622 */
13623 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13624 } else {
13625 res = xmlXPathCastToBoolean(resObj);
13626 }
13627 xmlXPathReleaseObject(ctxt->context, resObj);
13628 return(res);
13629 }
13630
13631 return(0);
13632 }
13633
13634 #ifdef XPATH_STREAMING
13635 /**
13636 * xmlXPathRunStreamEval:
13637 * @ctxt: the XPath parser context with the compiled expression
13638 *
13639 * Evaluate the Precompiled Streamable XPath expression in the given context.
13640 */
13641 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)13642 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13643 xmlXPathObjectPtr *resultSeq, int toBool)
13644 {
13645 int max_depth, min_depth;
13646 int from_root;
13647 int ret, depth;
13648 int eval_all_nodes;
13649 xmlNodePtr cur = NULL, limit = NULL;
13650 xmlStreamCtxtPtr patstream = NULL;
13651
13652 int nb_nodes = 0;
13653
13654 if ((ctxt == NULL) || (comp == NULL))
13655 return(-1);
13656 max_depth = xmlPatternMaxDepth(comp);
13657 if (max_depth == -1)
13658 return(-1);
13659 if (max_depth == -2)
13660 max_depth = 10000;
13661 min_depth = xmlPatternMinDepth(comp);
13662 if (min_depth == -1)
13663 return(-1);
13664 from_root = xmlPatternFromRoot(comp);
13665 if (from_root < 0)
13666 return(-1);
13667 #if 0
13668 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13669 #endif
13670
13671 if (! toBool) {
13672 if (resultSeq == NULL)
13673 return(-1);
13674 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13675 if (*resultSeq == NULL)
13676 return(-1);
13677 }
13678
13679 /*
13680 * handle the special cases of "/" amd "." being matched
13681 */
13682 if (min_depth == 0) {
13683 if (from_root) {
13684 /* Select "/" */
13685 if (toBool)
13686 return(1);
13687 /* TODO: Check memory error. */
13688 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13689 (xmlNodePtr) ctxt->doc);
13690 } else {
13691 /* Select "self::node()" */
13692 if (toBool)
13693 return(1);
13694 /* TODO: Check memory error. */
13695 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13696 }
13697 }
13698 if (max_depth == 0) {
13699 return(0);
13700 }
13701
13702 if (from_root) {
13703 cur = (xmlNodePtr)ctxt->doc;
13704 } else if (ctxt->node != NULL) {
13705 switch (ctxt->node->type) {
13706 case XML_ELEMENT_NODE:
13707 case XML_DOCUMENT_NODE:
13708 case XML_DOCUMENT_FRAG_NODE:
13709 case XML_HTML_DOCUMENT_NODE:
13710 #ifdef LIBXML_DOCB_ENABLED
13711 case XML_DOCB_DOCUMENT_NODE:
13712 #endif
13713 cur = ctxt->node;
13714 break;
13715 case XML_ATTRIBUTE_NODE:
13716 case XML_TEXT_NODE:
13717 case XML_CDATA_SECTION_NODE:
13718 case XML_ENTITY_REF_NODE:
13719 case XML_ENTITY_NODE:
13720 case XML_PI_NODE:
13721 case XML_COMMENT_NODE:
13722 case XML_NOTATION_NODE:
13723 case XML_DTD_NODE:
13724 case XML_DOCUMENT_TYPE_NODE:
13725 case XML_ELEMENT_DECL:
13726 case XML_ATTRIBUTE_DECL:
13727 case XML_ENTITY_DECL:
13728 case XML_NAMESPACE_DECL:
13729 case XML_XINCLUDE_START:
13730 case XML_XINCLUDE_END:
13731 break;
13732 }
13733 limit = cur;
13734 }
13735 if (cur == NULL) {
13736 return(0);
13737 }
13738
13739 patstream = xmlPatternGetStreamCtxt(comp);
13740 if (patstream == NULL) {
13741 /*
13742 * QUESTION TODO: Is this an error?
13743 */
13744 return(0);
13745 }
13746
13747 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13748
13749 if (from_root) {
13750 ret = xmlStreamPush(patstream, NULL, NULL);
13751 if (ret < 0) {
13752 } else if (ret == 1) {
13753 if (toBool)
13754 goto return_1;
13755 /* TODO: Check memory error. */
13756 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13757 }
13758 }
13759 depth = 0;
13760 goto scan_children;
13761 next_node:
13762 do {
13763 if (ctxt->opLimit != 0) {
13764 if (ctxt->opCount >= ctxt->opLimit) {
13765 xmlGenericError(xmlGenericErrorContext,
13766 "XPath operation limit exceeded\n");
13767 xmlFreeStreamCtxt(patstream);
13768 return(-1);
13769 }
13770 ctxt->opCount++;
13771 }
13772
13773 nb_nodes++;
13774
13775 switch (cur->type) {
13776 case XML_ELEMENT_NODE:
13777 case XML_TEXT_NODE:
13778 case XML_CDATA_SECTION_NODE:
13779 case XML_COMMENT_NODE:
13780 case XML_PI_NODE:
13781 if (cur->type == XML_ELEMENT_NODE) {
13782 ret = xmlStreamPush(patstream, cur->name,
13783 (cur->ns ? cur->ns->href : NULL));
13784 } else if (eval_all_nodes)
13785 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13786 else
13787 break;
13788
13789 if (ret < 0) {
13790 /* NOP. */
13791 } else if (ret == 1) {
13792 if (toBool)
13793 goto return_1;
13794 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13795 < 0) {
13796 ctxt->lastError.domain = XML_FROM_XPATH;
13797 ctxt->lastError.code = XML_ERR_NO_MEMORY;
13798 }
13799 }
13800 if ((cur->children == NULL) || (depth >= max_depth)) {
13801 ret = xmlStreamPop(patstream);
13802 while (cur->next != NULL) {
13803 cur = cur->next;
13804 if ((cur->type != XML_ENTITY_DECL) &&
13805 (cur->type != XML_DTD_NODE))
13806 goto next_node;
13807 }
13808 }
13809 default:
13810 break;
13811 }
13812
13813 scan_children:
13814 if (cur->type == XML_NAMESPACE_DECL) break;
13815 if ((cur->children != NULL) && (depth < max_depth)) {
13816 /*
13817 * Do not descend on entities declarations
13818 */
13819 if (cur->children->type != XML_ENTITY_DECL) {
13820 cur = cur->children;
13821 depth++;
13822 /*
13823 * Skip DTDs
13824 */
13825 if (cur->type != XML_DTD_NODE)
13826 continue;
13827 }
13828 }
13829
13830 if (cur == limit)
13831 break;
13832
13833 while (cur->next != NULL) {
13834 cur = cur->next;
13835 if ((cur->type != XML_ENTITY_DECL) &&
13836 (cur->type != XML_DTD_NODE))
13837 goto next_node;
13838 }
13839
13840 do {
13841 cur = cur->parent;
13842 depth--;
13843 if ((cur == NULL) || (cur == limit) ||
13844 (cur->type == XML_DOCUMENT_NODE))
13845 goto done;
13846 if (cur->type == XML_ELEMENT_NODE) {
13847 ret = xmlStreamPop(patstream);
13848 } else if ((eval_all_nodes) &&
13849 ((cur->type == XML_TEXT_NODE) ||
13850 (cur->type == XML_CDATA_SECTION_NODE) ||
13851 (cur->type == XML_COMMENT_NODE) ||
13852 (cur->type == XML_PI_NODE)))
13853 {
13854 ret = xmlStreamPop(patstream);
13855 }
13856 if (cur->next != NULL) {
13857 cur = cur->next;
13858 break;
13859 }
13860 } while (cur != NULL);
13861
13862 } while ((cur != NULL) && (depth >= 0));
13863
13864 done:
13865
13866 #if 0
13867 printf("stream eval: checked %d nodes selected %d\n",
13868 nb_nodes, retObj->nodesetval->nodeNr);
13869 #endif
13870
13871 if (patstream)
13872 xmlFreeStreamCtxt(patstream);
13873 return(0);
13874
13875 return_1:
13876 if (patstream)
13877 xmlFreeStreamCtxt(patstream);
13878 return(1);
13879 }
13880 #endif /* XPATH_STREAMING */
13881
13882 /**
13883 * xmlXPathRunEval:
13884 * @ctxt: the XPath parser context with the compiled expression
13885 * @toBool: evaluate to a boolean result
13886 *
13887 * Evaluate the Precompiled XPath expression in the given context.
13888 */
13889 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)13890 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13891 {
13892 xmlXPathCompExprPtr comp;
13893
13894 if ((ctxt == NULL) || (ctxt->comp == NULL))
13895 return(-1);
13896
13897 ctxt->context->depth = 0;
13898
13899 if (ctxt->valueTab == NULL) {
13900 /* Allocate the value stack */
13901 ctxt->valueTab = (xmlXPathObjectPtr *)
13902 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13903 if (ctxt->valueTab == NULL) {
13904 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13905 xmlFree(ctxt);
13906 }
13907 ctxt->valueNr = 0;
13908 ctxt->valueMax = 10;
13909 ctxt->value = NULL;
13910 ctxt->valueFrame = 0;
13911 }
13912 #ifdef XPATH_STREAMING
13913 if (ctxt->comp->stream) {
13914 int res;
13915
13916 if (toBool) {
13917 /*
13918 * Evaluation to boolean result.
13919 */
13920 res = xmlXPathRunStreamEval(ctxt->context,
13921 ctxt->comp->stream, NULL, 1);
13922 if (res != -1)
13923 return(res);
13924 } else {
13925 xmlXPathObjectPtr resObj = NULL;
13926
13927 /*
13928 * Evaluation to a sequence.
13929 */
13930 res = xmlXPathRunStreamEval(ctxt->context,
13931 ctxt->comp->stream, &resObj, 0);
13932
13933 if ((res != -1) && (resObj != NULL)) {
13934 valuePush(ctxt, resObj);
13935 return(0);
13936 }
13937 if (resObj != NULL)
13938 xmlXPathReleaseObject(ctxt->context, resObj);
13939 }
13940 /*
13941 * QUESTION TODO: This falls back to normal XPath evaluation
13942 * if res == -1. Is this intended?
13943 */
13944 }
13945 #endif
13946 comp = ctxt->comp;
13947 if (comp->last < 0) {
13948 xmlGenericError(xmlGenericErrorContext,
13949 "xmlXPathRunEval: last is less than zero\n");
13950 return(-1);
13951 }
13952 if (toBool)
13953 return(xmlXPathCompOpEvalToBoolean(ctxt,
13954 &comp->steps[comp->last], 0));
13955 else
13956 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13957
13958 return(0);
13959 }
13960
13961 /************************************************************************
13962 * *
13963 * Public interfaces *
13964 * *
13965 ************************************************************************/
13966
13967 /**
13968 * xmlXPathEvalPredicate:
13969 * @ctxt: the XPath context
13970 * @res: the Predicate Expression evaluation result
13971 *
13972 * Evaluate a predicate result for the current node.
13973 * A PredicateExpr is evaluated by evaluating the Expr and converting
13974 * the result to a boolean. If the result is a number, the result will
13975 * be converted to true if the number is equal to the position of the
13976 * context node in the context node list (as returned by the position
13977 * function) and will be converted to false otherwise; if the result
13978 * is not a number, then the result will be converted as if by a call
13979 * to the boolean function.
13980 *
13981 * Returns 1 if predicate is true, 0 otherwise
13982 */
13983 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)13984 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13985 if ((ctxt == NULL) || (res == NULL)) return(0);
13986 switch (res->type) {
13987 case XPATH_BOOLEAN:
13988 return(res->boolval);
13989 case XPATH_NUMBER:
13990 return(res->floatval == ctxt->proximityPosition);
13991 case XPATH_NODESET:
13992 case XPATH_XSLT_TREE:
13993 if (res->nodesetval == NULL)
13994 return(0);
13995 return(res->nodesetval->nodeNr != 0);
13996 case XPATH_STRING:
13997 return((res->stringval != NULL) &&
13998 (xmlStrlen(res->stringval) != 0));
13999 default:
14000 STRANGE
14001 }
14002 return(0);
14003 }
14004
14005 /**
14006 * xmlXPathEvaluatePredicateResult:
14007 * @ctxt: the XPath Parser context
14008 * @res: the Predicate Expression evaluation result
14009 *
14010 * Evaluate a predicate result for the current node.
14011 * A PredicateExpr is evaluated by evaluating the Expr and converting
14012 * the result to a boolean. If the result is a number, the result will
14013 * be converted to true if the number is equal to the position of the
14014 * context node in the context node list (as returned by the position
14015 * function) and will be converted to false otherwise; if the result
14016 * is not a number, then the result will be converted as if by a call
14017 * to the boolean function.
14018 *
14019 * Returns 1 if predicate is true, 0 otherwise
14020 */
14021 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14022 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14023 xmlXPathObjectPtr res) {
14024 if ((ctxt == NULL) || (res == NULL)) return(0);
14025 switch (res->type) {
14026 case XPATH_BOOLEAN:
14027 return(res->boolval);
14028 case XPATH_NUMBER:
14029 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14030 return((res->floatval == ctxt->context->proximityPosition) &&
14031 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14032 #else
14033 return(res->floatval == ctxt->context->proximityPosition);
14034 #endif
14035 case XPATH_NODESET:
14036 case XPATH_XSLT_TREE:
14037 if (res->nodesetval == NULL)
14038 return(0);
14039 return(res->nodesetval->nodeNr != 0);
14040 case XPATH_STRING:
14041 return((res->stringval != NULL) && (res->stringval[0] != 0));
14042 #ifdef LIBXML_XPTR_ENABLED
14043 case XPATH_LOCATIONSET:{
14044 xmlLocationSetPtr ptr = res->user;
14045 if (ptr == NULL)
14046 return(0);
14047 return (ptr->locNr != 0);
14048 }
14049 #endif
14050 default:
14051 STRANGE
14052 }
14053 return(0);
14054 }
14055
14056 #ifdef XPATH_STREAMING
14057 /**
14058 * xmlXPathTryStreamCompile:
14059 * @ctxt: an XPath context
14060 * @str: the XPath expression
14061 *
14062 * Try to compile the XPath expression as a streamable subset.
14063 *
14064 * Returns the compiled expression or NULL if failed to compile.
14065 */
14066 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14067 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14068 /*
14069 * Optimization: use streaming patterns when the XPath expression can
14070 * be compiled to a stream lookup
14071 */
14072 xmlPatternPtr stream;
14073 xmlXPathCompExprPtr comp;
14074 xmlDictPtr dict = NULL;
14075 const xmlChar **namespaces = NULL;
14076 xmlNsPtr ns;
14077 int i, j;
14078
14079 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14080 (!xmlStrchr(str, '@'))) {
14081 const xmlChar *tmp;
14082
14083 /*
14084 * We don't try to handle expressions using the verbose axis
14085 * specifiers ("::"), just the simplified form at this point.
14086 * Additionally, if there is no list of namespaces available and
14087 * there's a ":" in the expression, indicating a prefixed QName,
14088 * then we won't try to compile either. xmlPatterncompile() needs
14089 * to have a list of namespaces at compilation time in order to
14090 * compile prefixed name tests.
14091 */
14092 tmp = xmlStrchr(str, ':');
14093 if ((tmp != NULL) &&
14094 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14095 return(NULL);
14096
14097 if (ctxt != NULL) {
14098 dict = ctxt->dict;
14099 if (ctxt->nsNr > 0) {
14100 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14101 if (namespaces == NULL) {
14102 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14103 return(NULL);
14104 }
14105 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14106 ns = ctxt->namespaces[j];
14107 namespaces[i++] = ns->href;
14108 namespaces[i++] = ns->prefix;
14109 }
14110 namespaces[i++] = NULL;
14111 namespaces[i] = NULL;
14112 }
14113 }
14114
14115 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14116 if (namespaces != NULL) {
14117 xmlFree((xmlChar **)namespaces);
14118 }
14119 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14120 comp = xmlXPathNewCompExpr();
14121 if (comp == NULL) {
14122 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14123 return(NULL);
14124 }
14125 comp->stream = stream;
14126 comp->dict = dict;
14127 if (comp->dict)
14128 xmlDictReference(comp->dict);
14129 return(comp);
14130 }
14131 xmlFreePattern(stream);
14132 }
14133 return(NULL);
14134 }
14135 #endif /* XPATH_STREAMING */
14136
14137 static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,xmlXPathStepOpPtr op)14138 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14139 xmlXPathStepOpPtr op)
14140 {
14141 xmlXPathCompExprPtr comp = pctxt->comp;
14142 xmlXPathContextPtr ctxt;
14143
14144 /*
14145 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14146 * internal representation.
14147 */
14148
14149 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14150 (op->ch1 != -1) &&
14151 (op->ch2 == -1 /* no predicate */))
14152 {
14153 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14154
14155 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14156 ((xmlXPathAxisVal) prevop->value ==
14157 AXIS_DESCENDANT_OR_SELF) &&
14158 (prevop->ch2 == -1) &&
14159 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14160 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14161 {
14162 /*
14163 * This is a "descendant-or-self::node()" without predicates.
14164 * Try to eliminate it.
14165 */
14166
14167 switch ((xmlXPathAxisVal) op->value) {
14168 case AXIS_CHILD:
14169 case AXIS_DESCENDANT:
14170 /*
14171 * Convert "descendant-or-self::node()/child::" or
14172 * "descendant-or-self::node()/descendant::" to
14173 * "descendant::"
14174 */
14175 op->ch1 = prevop->ch1;
14176 op->value = AXIS_DESCENDANT;
14177 break;
14178 case AXIS_SELF:
14179 case AXIS_DESCENDANT_OR_SELF:
14180 /*
14181 * Convert "descendant-or-self::node()/self::" or
14182 * "descendant-or-self::node()/descendant-or-self::" to
14183 * to "descendant-or-self::"
14184 */
14185 op->ch1 = prevop->ch1;
14186 op->value = AXIS_DESCENDANT_OR_SELF;
14187 break;
14188 default:
14189 break;
14190 }
14191 }
14192 }
14193
14194 /* OP_VALUE has invalid ch1. */
14195 if (op->op == XPATH_OP_VALUE)
14196 return;
14197
14198 /* Recurse */
14199 ctxt = pctxt->context;
14200 if (ctxt != NULL) {
14201 if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14202 return;
14203 ctxt->depth += 1;
14204 }
14205 if (op->ch1 != -1)
14206 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14207 if (op->ch2 != -1)
14208 xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14209 if (ctxt != NULL)
14210 ctxt->depth -= 1;
14211 }
14212
14213 /**
14214 * xmlXPathCtxtCompile:
14215 * @ctxt: an XPath context
14216 * @str: the XPath expression
14217 *
14218 * Compile an XPath expression
14219 *
14220 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14221 * the caller has to free the object.
14222 */
14223 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14224 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14225 xmlXPathParserContextPtr pctxt;
14226 xmlXPathCompExprPtr comp;
14227
14228 #ifdef XPATH_STREAMING
14229 comp = xmlXPathTryStreamCompile(ctxt, str);
14230 if (comp != NULL)
14231 return(comp);
14232 #endif
14233
14234 xmlInitParser();
14235
14236 pctxt = xmlXPathNewParserContext(str, ctxt);
14237 if (pctxt == NULL)
14238 return NULL;
14239 if (ctxt != NULL)
14240 ctxt->depth = 0;
14241 xmlXPathCompileExpr(pctxt, 1);
14242
14243 if( pctxt->error != XPATH_EXPRESSION_OK )
14244 {
14245 xmlXPathFreeParserContext(pctxt);
14246 return(NULL);
14247 }
14248
14249 if (*pctxt->cur != 0) {
14250 /*
14251 * aleksey: in some cases this line prints *second* error message
14252 * (see bug #78858) and probably this should be fixed.
14253 * However, we are not sure that all error messages are printed
14254 * out in other places. It's not critical so we leave it as-is for now
14255 */
14256 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14257 comp = NULL;
14258 } else {
14259 comp = pctxt->comp;
14260 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14261 if (ctxt != NULL)
14262 ctxt->depth = 0;
14263 xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14264 }
14265 pctxt->comp = NULL;
14266 }
14267 xmlXPathFreeParserContext(pctxt);
14268
14269 if (comp != NULL) {
14270 comp->expr = xmlStrdup(str);
14271 #ifdef DEBUG_EVAL_COUNTS
14272 comp->string = xmlStrdup(str);
14273 comp->nb = 0;
14274 #endif
14275 }
14276 return(comp);
14277 }
14278
14279 /**
14280 * xmlXPathCompile:
14281 * @str: the XPath expression
14282 *
14283 * Compile an XPath expression
14284 *
14285 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14286 * the caller has to free the object.
14287 */
14288 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14289 xmlXPathCompile(const xmlChar *str) {
14290 return(xmlXPathCtxtCompile(NULL, str));
14291 }
14292
14293 /**
14294 * xmlXPathCompiledEvalInternal:
14295 * @comp: the compiled XPath expression
14296 * @ctxt: the XPath context
14297 * @resObj: the resulting XPath object or NULL
14298 * @toBool: 1 if only a boolean result is requested
14299 *
14300 * Evaluate the Precompiled XPath expression in the given context.
14301 * The caller has to free @resObj.
14302 *
14303 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14304 * the caller has to free the object.
14305 */
14306 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14307 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14308 xmlXPathContextPtr ctxt,
14309 xmlXPathObjectPtr *resObjPtr,
14310 int toBool)
14311 {
14312 xmlXPathParserContextPtr pctxt;
14313 xmlXPathObjectPtr resObj;
14314 #ifndef LIBXML_THREAD_ENABLED
14315 static int reentance = 0;
14316 #endif
14317 int res;
14318
14319 CHECK_CTXT_NEG(ctxt)
14320
14321 if (comp == NULL)
14322 return(-1);
14323 xmlInitParser();
14324
14325 #ifndef LIBXML_THREAD_ENABLED
14326 reentance++;
14327 if (reentance > 1)
14328 xmlXPathDisableOptimizer = 1;
14329 #endif
14330
14331 #ifdef DEBUG_EVAL_COUNTS
14332 comp->nb++;
14333 if ((comp->string != NULL) && (comp->nb > 100)) {
14334 fprintf(stderr, "100 x %s\n", comp->string);
14335 comp->nb = 0;
14336 }
14337 #endif
14338 pctxt = xmlXPathCompParserContext(comp, ctxt);
14339 res = xmlXPathRunEval(pctxt, toBool);
14340
14341 if (pctxt->error != XPATH_EXPRESSION_OK) {
14342 resObj = NULL;
14343 } else {
14344 resObj = valuePop(pctxt);
14345 if (resObj == NULL) {
14346 if (!toBool)
14347 xmlGenericError(xmlGenericErrorContext,
14348 "xmlXPathCompiledEval: No result on the stack.\n");
14349 } else if (pctxt->valueNr > 0) {
14350 xmlGenericError(xmlGenericErrorContext,
14351 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14352 pctxt->valueNr);
14353 }
14354 }
14355
14356 if (resObjPtr)
14357 *resObjPtr = resObj;
14358 else
14359 xmlXPathReleaseObject(ctxt, resObj);
14360
14361 pctxt->comp = NULL;
14362 xmlXPathFreeParserContext(pctxt);
14363 #ifndef LIBXML_THREAD_ENABLED
14364 reentance--;
14365 #endif
14366
14367 return(res);
14368 }
14369
14370 /**
14371 * xmlXPathCompiledEval:
14372 * @comp: the compiled XPath expression
14373 * @ctx: the XPath context
14374 *
14375 * Evaluate the Precompiled XPath expression in the given context.
14376 *
14377 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14378 * the caller has to free the object.
14379 */
14380 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14381 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14382 {
14383 xmlXPathObjectPtr res = NULL;
14384
14385 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14386 return(res);
14387 }
14388
14389 /**
14390 * xmlXPathCompiledEvalToBoolean:
14391 * @comp: the compiled XPath expression
14392 * @ctxt: the XPath context
14393 *
14394 * Applies the XPath boolean() function on the result of the given
14395 * compiled expression.
14396 *
14397 * Returns 1 if the expression evaluated to true, 0 if to false and
14398 * -1 in API and internal errors.
14399 */
14400 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14401 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14402 xmlXPathContextPtr ctxt)
14403 {
14404 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14405 }
14406
14407 /**
14408 * xmlXPathEvalExpr:
14409 * @ctxt: the XPath Parser context
14410 *
14411 * Parse and evaluate an XPath expression in the given context,
14412 * then push the result on the context stack
14413 */
14414 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14415 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14416 #ifdef XPATH_STREAMING
14417 xmlXPathCompExprPtr comp;
14418 #endif
14419
14420 if (ctxt == NULL) return;
14421
14422 #ifdef XPATH_STREAMING
14423 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14424 if (comp != NULL) {
14425 if (ctxt->comp != NULL)
14426 xmlXPathFreeCompExpr(ctxt->comp);
14427 ctxt->comp = comp;
14428 } else
14429 #endif
14430 {
14431 if (ctxt->context != NULL)
14432 ctxt->context->depth = 0;
14433 xmlXPathCompileExpr(ctxt, 1);
14434 CHECK_ERROR;
14435
14436 /* Check for trailing characters. */
14437 if (*ctxt->cur != 0)
14438 XP_ERROR(XPATH_EXPR_ERROR);
14439
14440 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14441 if (ctxt->context != NULL)
14442 ctxt->context->depth = 0;
14443 xmlXPathOptimizeExpression(ctxt,
14444 &ctxt->comp->steps[ctxt->comp->last]);
14445 }
14446 }
14447
14448 xmlXPathRunEval(ctxt, 0);
14449 }
14450
14451 /**
14452 * xmlXPathEval:
14453 * @str: the XPath expression
14454 * @ctx: the XPath context
14455 *
14456 * Evaluate the XPath Location Path in the given context.
14457 *
14458 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14459 * the caller has to free the object.
14460 */
14461 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14462 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14463 xmlXPathParserContextPtr ctxt;
14464 xmlXPathObjectPtr res;
14465
14466 CHECK_CTXT(ctx)
14467
14468 xmlInitParser();
14469
14470 ctxt = xmlXPathNewParserContext(str, ctx);
14471 if (ctxt == NULL)
14472 return NULL;
14473 xmlXPathEvalExpr(ctxt);
14474
14475 if (ctxt->error != XPATH_EXPRESSION_OK) {
14476 res = NULL;
14477 } else {
14478 res = valuePop(ctxt);
14479 if (res == NULL) {
14480 xmlGenericError(xmlGenericErrorContext,
14481 "xmlXPathCompiledEval: No result on the stack.\n");
14482 } else if (ctxt->valueNr > 0) {
14483 xmlGenericError(xmlGenericErrorContext,
14484 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14485 ctxt->valueNr);
14486 }
14487 }
14488
14489 xmlXPathFreeParserContext(ctxt);
14490 return(res);
14491 }
14492
14493 /**
14494 * xmlXPathSetContextNode:
14495 * @node: the node to to use as the context node
14496 * @ctx: the XPath context
14497 *
14498 * Sets 'node' as the context node. The node must be in the same
14499 * document as that associated with the context.
14500 *
14501 * Returns -1 in case of error or 0 if successful
14502 */
14503 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14504 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14505 if ((node == NULL) || (ctx == NULL))
14506 return(-1);
14507
14508 if (node->doc == ctx->doc) {
14509 ctx->node = node;
14510 return(0);
14511 }
14512 return(-1);
14513 }
14514
14515 /**
14516 * xmlXPathNodeEval:
14517 * @node: the node to to use as the context node
14518 * @str: the XPath expression
14519 * @ctx: the XPath context
14520 *
14521 * Evaluate the XPath Location Path in the given context. The node 'node'
14522 * is set as the context node. The context node is not restored.
14523 *
14524 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14525 * the caller has to free the object.
14526 */
14527 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14528 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14529 if (str == NULL)
14530 return(NULL);
14531 if (xmlXPathSetContextNode(node, ctx) < 0)
14532 return(NULL);
14533 return(xmlXPathEval(str, ctx));
14534 }
14535
14536 /**
14537 * xmlXPathEvalExpression:
14538 * @str: the XPath expression
14539 * @ctxt: the XPath context
14540 *
14541 * Alias for xmlXPathEval().
14542 *
14543 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14544 * the caller has to free the object.
14545 */
14546 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14547 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14548 return(xmlXPathEval(str, ctxt));
14549 }
14550
14551 /************************************************************************
14552 * *
14553 * Extra functions not pertaining to the XPath spec *
14554 * *
14555 ************************************************************************/
14556 /**
14557 * xmlXPathEscapeUriFunction:
14558 * @ctxt: the XPath Parser context
14559 * @nargs: the number of arguments
14560 *
14561 * Implement the escape-uri() XPath function
14562 * string escape-uri(string $str, bool $escape-reserved)
14563 *
14564 * This function applies the URI escaping rules defined in section 2 of [RFC
14565 * 2396] to the string supplied as $uri-part, which typically represents all
14566 * or part of a URI. The effect of the function is to replace any special
14567 * character in the string by an escape sequence of the form %xx%yy...,
14568 * where xxyy... is the hexadecimal representation of the octets used to
14569 * represent the character in UTF-8.
14570 *
14571 * The set of characters that are escaped depends on the setting of the
14572 * boolean argument $escape-reserved.
14573 *
14574 * If $escape-reserved is true, all characters are escaped other than lower
14575 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14576 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14577 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14578 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14579 * A-F).
14580 *
14581 * If $escape-reserved is false, the behavior differs in that characters
14582 * referred to in [RFC 2396] as reserved characters are not escaped. These
14583 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14584 *
14585 * [RFC 2396] does not define whether escaped URIs should use lower case or
14586 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14587 * compared using string comparison functions, this function must always use
14588 * the upper-case letters A-F.
14589 *
14590 * Generally, $escape-reserved should be set to true when escaping a string
14591 * that is to form a single part of a URI, and to false when escaping an
14592 * entire URI or URI reference.
14593 *
14594 * In the case of non-ascii characters, the string is encoded according to
14595 * utf-8 and then converted according to RFC 2396.
14596 *
14597 * Examples
14598 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14599 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14600 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14601 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14602 *
14603 */
14604 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)14605 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14606 xmlXPathObjectPtr str;
14607 int escape_reserved;
14608 xmlBufPtr target;
14609 xmlChar *cptr;
14610 xmlChar escape[4];
14611
14612 CHECK_ARITY(2);
14613
14614 escape_reserved = xmlXPathPopBoolean(ctxt);
14615
14616 CAST_TO_STRING;
14617 str = valuePop(ctxt);
14618
14619 target = xmlBufCreate();
14620
14621 escape[0] = '%';
14622 escape[3] = 0;
14623
14624 if (target) {
14625 for (cptr = str->stringval; *cptr; cptr++) {
14626 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14627 (*cptr >= 'a' && *cptr <= 'z') ||
14628 (*cptr >= '0' && *cptr <= '9') ||
14629 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14630 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14631 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14632 (*cptr == '%' &&
14633 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14634 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14635 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14636 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14637 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14638 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14639 (!escape_reserved &&
14640 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14641 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14642 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14643 *cptr == ','))) {
14644 xmlBufAdd(target, cptr, 1);
14645 } else {
14646 if ((*cptr >> 4) < 10)
14647 escape[1] = '0' + (*cptr >> 4);
14648 else
14649 escape[1] = 'A' - 10 + (*cptr >> 4);
14650 if ((*cptr & 0xF) < 10)
14651 escape[2] = '0' + (*cptr & 0xF);
14652 else
14653 escape[2] = 'A' - 10 + (*cptr & 0xF);
14654
14655 xmlBufAdd(target, &escape[0], 3);
14656 }
14657 }
14658 }
14659 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14660 xmlBufContent(target)));
14661 xmlBufFree(target);
14662 xmlXPathReleaseObject(ctxt->context, str);
14663 }
14664
14665 /**
14666 * xmlXPathRegisterAllFunctions:
14667 * @ctxt: the XPath context
14668 *
14669 * Registers all default XPath functions in this context
14670 */
14671 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)14672 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14673 {
14674 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14675 xmlXPathBooleanFunction);
14676 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14677 xmlXPathCeilingFunction);
14678 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14679 xmlXPathCountFunction);
14680 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14681 xmlXPathConcatFunction);
14682 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14683 xmlXPathContainsFunction);
14684 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14685 xmlXPathIdFunction);
14686 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14687 xmlXPathFalseFunction);
14688 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14689 xmlXPathFloorFunction);
14690 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14691 xmlXPathLastFunction);
14692 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14693 xmlXPathLangFunction);
14694 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14695 xmlXPathLocalNameFunction);
14696 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14697 xmlXPathNotFunction);
14698 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14699 xmlXPathNameFunction);
14700 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14701 xmlXPathNamespaceURIFunction);
14702 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14703 xmlXPathNormalizeFunction);
14704 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14705 xmlXPathNumberFunction);
14706 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14707 xmlXPathPositionFunction);
14708 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14709 xmlXPathRoundFunction);
14710 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14711 xmlXPathStringFunction);
14712 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14713 xmlXPathStringLengthFunction);
14714 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14715 xmlXPathStartsWithFunction);
14716 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14717 xmlXPathSubstringFunction);
14718 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14719 xmlXPathSubstringBeforeFunction);
14720 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14721 xmlXPathSubstringAfterFunction);
14722 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14723 xmlXPathSumFunction);
14724 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14725 xmlXPathTrueFunction);
14726 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14727 xmlXPathTranslateFunction);
14728
14729 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14730 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14731 xmlXPathEscapeUriFunction);
14732 }
14733
14734 #endif /* LIBXML_XPATH_ENABLED */
14735 #define bottom_xpath
14736 #include "elfgcchack.h"
14737