1 /* libxml2 - Library for parsing XML documents
2 * Copyright (C) 2006-2019 Free Software Foundation, Inc.
3 *
4 * This file is not part of the GNU gettext program, but is used with
5 * GNU gettext.
6 *
7 * The original copyright notice is as follows:
8 */
9
10 /*
11 * Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved.
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this software and associated documentation files (the "Software"), to deal
15 * in the Software without restriction, including without limitation the rights
16 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 * copies of the Software, and to permit persons to whom the Software is fur-
18 * nished to do so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
25 * NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 * THE SOFTWARE.
30 *
31 * Author: daniel@veillard.com
32 */
33
34 /*
35 * xpath.c: XML Path Language implementation
36 * XPath is a language for addressing parts of an XML document,
37 * designed to be used by both XSLT and XPointer
38 *
39 * Reference: W3C Recommendation 16 November 1999
40 * http://www.w3.org/TR/1999/REC-xpath-19991116
41 * Public reference:
42 * http://www.w3.org/TR/xpath
43 */
44
45 /* To avoid EBCDIC trouble when parsing on zOS */
46 #if defined(__MVS__)
47 #pragma convert("ISO8859-1")
48 #endif
49
50 #define IN_LIBXML
51 #include "libxml.h"
52
53 #include <limits.h>
54 #include <string.h>
55 #include <stddef.h>
56
57 #ifdef HAVE_SYS_TYPES_H
58 #include <sys/types.h>
59 #endif
60 #ifdef HAVE_MATH_H
61 #include <math.h>
62 #endif
63 #ifdef HAVE_FLOAT_H
64 #include <float.h>
65 #endif
66 #ifdef HAVE_CTYPE_H
67 #include <ctype.h>
68 #endif
69 #ifdef HAVE_SIGNAL_H
70 #include <signal.h>
71 #endif
72
73 #include <libxml/xmlmemory.h>
74 #include <libxml/tree.h>
75 #include <libxml/valid.h>
76 #include <libxml/xpath.h>
77 #include <libxml/xpathInternals.h>
78 #include <libxml/parserInternals.h>
79 #include <libxml/hash.h>
80 #ifdef LIBXML_XPTR_ENABLED
81 #include <libxml/xpointer.h>
82 #endif
83 #ifdef LIBXML_DEBUG_ENABLED
84 #include <libxml/debugXML.h>
85 #endif
86 #include <libxml/xmlerror.h>
87 #include <libxml/threads.h>
88 #include <libxml/globals.h>
89 #ifdef LIBXML_PATTERN_ENABLED
90 #include <libxml/pattern.h>
91 #endif
92
93 #include "buf.h"
94
95 #ifdef LIBXML_PATTERN_ENABLED
96 #define XPATH_STREAMING
97 #endif
98
99 #define TODO \
100 xmlGenericError(xmlGenericErrorContext, \
101 "Unimplemented block at %s:%d\n", \
102 __FILE__, __LINE__);
103
104 /**
105 * WITH_TIM_SORT:
106 *
107 * Use the Timsort algorithm provided in timsort.h to sort
108 * nodeset as this is a great improvement over the old Shell sort
109 * used in xmlXPathNodeSetSort()
110 */
111 #define WITH_TIM_SORT
112
113 /*
114 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
115 * If defined, this will use xmlXPathCmpNodesExt() instead of
116 * xmlXPathCmpNodes(). The new function is optimized comparison of
117 * non-element nodes; actually it will speed up comparison only if
118 * xmlXPathOrderDocElems() was called in order to index the elements of
119 * a tree in document order; Libxslt does such an indexing, thus it will
120 * benefit from this optimization.
121 */
122 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
123
124 /*
125 * XP_OPTIMIZED_FILTER_FIRST:
126 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
127 * in a way, that it stop evaluation at the first node.
128 */
129 #define XP_OPTIMIZED_FILTER_FIRST
130
131 /*
132 * XP_DEBUG_OBJ_USAGE:
133 * Internal flag to enable tracking of how much XPath objects have been
134 * created.
135 */
136 /* #define XP_DEBUG_OBJ_USAGE */
137
138 /*
139 * XPATH_MAX_STEPS:
140 * when compiling an XPath expression we arbitrary limit the maximum
141 * number of step operation in the compiled expression. 1000000 is
142 * an insanely large value which should never be reached under normal
143 * circumstances
144 */
145 #define XPATH_MAX_STEPS 1000000
146
147 /*
148 * XPATH_MAX_STACK_DEPTH:
149 * when evaluating an XPath expression we arbitrary limit the maximum
150 * number of object allowed to be pushed on the stack. 1000000 is
151 * an insanely large value which should never be reached under normal
152 * circumstances
153 */
154 #define XPATH_MAX_STACK_DEPTH 1000000
155
156 /*
157 * XPATH_MAX_NODESET_LENGTH:
158 * when evaluating an XPath expression nodesets are created and we
159 * arbitrary limit the maximum length of those node set. 10000000 is
160 * an insanely large value which should never be reached under normal
161 * circumstances, one would first need to construct an in memory tree
162 * with more than 10 millions nodes.
163 */
164 #define XPATH_MAX_NODESET_LENGTH 10000000
165
166 /*
167 * TODO:
168 * There are a few spots where some tests are done which depend upon ascii
169 * data. These should be enhanced for full UTF8 support (see particularly
170 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
171 */
172
173 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
174 /**
175 * xmlXPathCmpNodesExt:
176 * @node1: the first node
177 * @node2: the second node
178 *
179 * Compare two nodes w.r.t document order.
180 * This one is optimized for handling of non-element nodes.
181 *
182 * Returns -2 in case of error 1 if first point < second point, 0 if
183 * it's the same node, -1 otherwise
184 */
185 static int
xmlXPathCmpNodesExt(xmlNodePtr node1,xmlNodePtr node2)186 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
187 int depth1, depth2;
188 int misc = 0, precedence1 = 0, precedence2 = 0;
189 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
190 xmlNodePtr cur, root;
191 ptrdiff_t l1, l2;
192
193 if ((node1 == NULL) || (node2 == NULL))
194 return(-2);
195
196 if (node1 == node2)
197 return(0);
198
199 /*
200 * a couple of optimizations which will avoid computations in most cases
201 */
202 switch (node1->type) {
203 case XML_ELEMENT_NODE:
204 if (node2->type == XML_ELEMENT_NODE) {
205 if ((0 > (ptrdiff_t) node1->content) &&
206 (0 > (ptrdiff_t) node2->content) &&
207 (node1->doc == node2->doc))
208 {
209 l1 = -((ptrdiff_t) node1->content);
210 l2 = -((ptrdiff_t) node2->content);
211 if (l1 < l2)
212 return(1);
213 if (l1 > l2)
214 return(-1);
215 } else
216 goto turtle_comparison;
217 }
218 break;
219 case XML_ATTRIBUTE_NODE:
220 precedence1 = 1; /* element is owner */
221 miscNode1 = node1;
222 node1 = node1->parent;
223 misc = 1;
224 break;
225 case XML_TEXT_NODE:
226 case XML_CDATA_SECTION_NODE:
227 case XML_COMMENT_NODE:
228 case XML_PI_NODE: {
229 miscNode1 = node1;
230 /*
231 * Find nearest element node.
232 */
233 if (node1->prev != NULL) {
234 do {
235 node1 = node1->prev;
236 if (node1->type == XML_ELEMENT_NODE) {
237 precedence1 = 3; /* element in prev-sibl axis */
238 break;
239 }
240 if (node1->prev == NULL) {
241 precedence1 = 2; /* element is parent */
242 /*
243 * URGENT TODO: Are there any cases, where the
244 * parent of such a node is not an element node?
245 */
246 node1 = node1->parent;
247 break;
248 }
249 } while (1);
250 } else {
251 precedence1 = 2; /* element is parent */
252 node1 = node1->parent;
253 }
254 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
255 (0 <= (ptrdiff_t) node1->content)) {
256 /*
257 * Fallback for whatever case.
258 */
259 node1 = miscNode1;
260 precedence1 = 0;
261 } else
262 misc = 1;
263 }
264 break;
265 case XML_NAMESPACE_DECL:
266 /*
267 * TODO: why do we return 1 for namespace nodes?
268 */
269 return(1);
270 default:
271 break;
272 }
273 switch (node2->type) {
274 case XML_ELEMENT_NODE:
275 break;
276 case XML_ATTRIBUTE_NODE:
277 precedence2 = 1; /* element is owner */
278 miscNode2 = node2;
279 node2 = node2->parent;
280 misc = 1;
281 break;
282 case XML_TEXT_NODE:
283 case XML_CDATA_SECTION_NODE:
284 case XML_COMMENT_NODE:
285 case XML_PI_NODE: {
286 miscNode2 = node2;
287 if (node2->prev != NULL) {
288 do {
289 node2 = node2->prev;
290 if (node2->type == XML_ELEMENT_NODE) {
291 precedence2 = 3; /* element in prev-sibl axis */
292 break;
293 }
294 if (node2->prev == NULL) {
295 precedence2 = 2; /* element is parent */
296 node2 = node2->parent;
297 break;
298 }
299 } while (1);
300 } else {
301 precedence2 = 2; /* element is parent */
302 node2 = node2->parent;
303 }
304 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
305 (0 <= (ptrdiff_t) node2->content))
306 {
307 node2 = miscNode2;
308 precedence2 = 0;
309 } else
310 misc = 1;
311 }
312 break;
313 case XML_NAMESPACE_DECL:
314 return(1);
315 default:
316 break;
317 }
318 if (misc) {
319 if (node1 == node2) {
320 if (precedence1 == precedence2) {
321 /*
322 * The ugly case; but normally there aren't many
323 * adjacent non-element nodes around.
324 */
325 cur = miscNode2->prev;
326 while (cur != NULL) {
327 if (cur == miscNode1)
328 return(1);
329 if (cur->type == XML_ELEMENT_NODE)
330 return(-1);
331 cur = cur->prev;
332 }
333 return (-1);
334 } else {
335 /*
336 * Evaluate based on higher precedence wrt to the element.
337 * TODO: This assumes attributes are sorted before content.
338 * Is this 100% correct?
339 */
340 if (precedence1 < precedence2)
341 return(1);
342 else
343 return(-1);
344 }
345 }
346 /*
347 * Special case: One of the helper-elements is contained by the other.
348 * <foo>
349 * <node2>
350 * <node1>Text-1(precedence1 == 2)</node1>
351 * </node2>
352 * Text-6(precedence2 == 3)
353 * </foo>
354 */
355 if ((precedence2 == 3) && (precedence1 > 1)) {
356 cur = node1->parent;
357 while (cur) {
358 if (cur == node2)
359 return(1);
360 cur = cur->parent;
361 }
362 }
363 if ((precedence1 == 3) && (precedence2 > 1)) {
364 cur = node2->parent;
365 while (cur) {
366 if (cur == node1)
367 return(-1);
368 cur = cur->parent;
369 }
370 }
371 }
372
373 /*
374 * Speedup using document order if availble.
375 */
376 if ((node1->type == XML_ELEMENT_NODE) &&
377 (node2->type == XML_ELEMENT_NODE) &&
378 (0 > (ptrdiff_t) node1->content) &&
379 (0 > (ptrdiff_t) node2->content) &&
380 (node1->doc == node2->doc)) {
381
382 l1 = -((ptrdiff_t) node1->content);
383 l2 = -((ptrdiff_t) node2->content);
384 if (l1 < l2)
385 return(1);
386 if (l1 > l2)
387 return(-1);
388 }
389
390 turtle_comparison:
391
392 if (node1 == node2->prev)
393 return(1);
394 if (node1 == node2->next)
395 return(-1);
396 /*
397 * compute depth to root
398 */
399 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
400 if (cur->parent == node1)
401 return(1);
402 depth2++;
403 }
404 root = cur;
405 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
406 if (cur->parent == node2)
407 return(-1);
408 depth1++;
409 }
410 /*
411 * Distinct document (or distinct entities :-( ) case.
412 */
413 if (root != cur) {
414 return(-2);
415 }
416 /*
417 * get the nearest common ancestor.
418 */
419 while (depth1 > depth2) {
420 depth1--;
421 node1 = node1->parent;
422 }
423 while (depth2 > depth1) {
424 depth2--;
425 node2 = node2->parent;
426 }
427 while (node1->parent != node2->parent) {
428 node1 = node1->parent;
429 node2 = node2->parent;
430 /* should not happen but just in case ... */
431 if ((node1 == NULL) || (node2 == NULL))
432 return(-2);
433 }
434 /*
435 * Find who's first.
436 */
437 if (node1 == node2->prev)
438 return(1);
439 if (node1 == node2->next)
440 return(-1);
441 /*
442 * Speedup using document order if availble.
443 */
444 if ((node1->type == XML_ELEMENT_NODE) &&
445 (node2->type == XML_ELEMENT_NODE) &&
446 (0 > (ptrdiff_t) node1->content) &&
447 (0 > (ptrdiff_t) node2->content) &&
448 (node1->doc == node2->doc)) {
449
450 l1 = -((ptrdiff_t) node1->content);
451 l2 = -((ptrdiff_t) node2->content);
452 if (l1 < l2)
453 return(1);
454 if (l1 > l2)
455 return(-1);
456 }
457
458 for (cur = node1->next;cur != NULL;cur = cur->next)
459 if (cur == node2)
460 return(1);
461 return(-1); /* assume there is no sibling list corruption */
462 }
463 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
464
465 /*
466 * Wrapper for the Timsort argorithm from timsort.h
467 */
468 #ifdef WITH_TIM_SORT
469 #define SORT_NAME libxml_domnode
470 #define SORT_TYPE xmlNodePtr
471 /**
472 * wrap_cmp:
473 * @x: a node
474 * @y: another node
475 *
476 * Comparison function for the Timsort implementation
477 *
478 * Returns -2 in case of error -1 if first point < second point, 0 if
479 * it's the same node, +1 otherwise
480 */
481 static
482 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
483 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
wrap_cmp(xmlNodePtr x,xmlNodePtr y)484 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
485 {
486 int res = xmlXPathCmpNodesExt(x, y);
487 return res == -2 ? res : -res;
488 }
489 #else
wrap_cmp(xmlNodePtr x,xmlNodePtr y)490 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
491 {
492 int res = xmlXPathCmpNodes(x, y);
493 return res == -2 ? res : -res;
494 }
495 #endif
496 #define SORT_CMP(x, y) (wrap_cmp(x, y))
497 #include "timsort.h"
498 #endif /* WITH_TIM_SORT */
499
500 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
501
502 /************************************************************************
503 * *
504 * Floating point stuff *
505 * *
506 ************************************************************************/
507
508 #ifndef INFINITY
509 #define INFINITY (DBL_MAX * DBL_MAX)
510 #endif
511
512 #ifndef NAN
513 #define NAN (INFINITY / INFINITY)
514 #endif
515
516 double xmlXPathNAN;
517 double xmlXPathPINF;
518 double xmlXPathNINF;
519
520 /**
521 * xmlXPathInit:
522 *
523 * Initialize the XPath environment
524 */
525 void
xmlXPathInit(void)526 xmlXPathInit(void) {
527 xmlXPathNAN = NAN;
528 xmlXPathPINF = INFINITY;
529 xmlXPathNINF = -INFINITY;
530 }
531
532 /**
533 * xmlXPathIsNaN:
534 * @val: a double value
535 *
536 * Returns 1 if the value is a NaN, 0 otherwise
537 */
538 int
xmlXPathIsNaN(double val)539 xmlXPathIsNaN(double val) {
540 #ifdef isnan
541 return isnan(val);
542 #else
543 return !(val == val);
544 #endif
545 }
546
547 /**
548 * xmlXPathIsInf:
549 * @val: a double value
550 *
551 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
552 */
553 int
xmlXPathIsInf(double val)554 xmlXPathIsInf(double val) {
555 #ifdef isinf
556 return isinf(val) ? (val > 0 ? 1 : -1) : 0;
557 #else
558 if (val >= INFINITY)
559 return 1;
560 if (val <= -INFINITY)
561 return -1;
562 return 0;
563 #endif
564 }
565
566 #endif /* SCHEMAS or XPATH */
567
568 #ifdef LIBXML_XPATH_ENABLED
569
570 /*
571 * TODO: when compatibility allows remove all "fake node libxslt" strings
572 * the test should just be name[0] = ' '
573 */
574 #ifdef DEBUG_XPATH_EXPRESSION
575 #define DEBUG_STEP
576 #define DEBUG_EXPR
577 #define DEBUG_EVAL_COUNTS
578 #endif
579
580 static xmlNs xmlXPathXMLNamespaceStruct = {
581 NULL,
582 XML_NAMESPACE_DECL,
583 XML_XML_NAMESPACE,
584 BAD_CAST "xml",
585 NULL,
586 NULL
587 };
588 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
589 #ifndef LIBXML_THREAD_ENABLED
590 /*
591 * Optimizer is disabled only when threaded apps are detected while
592 * the library ain't compiled for thread safety.
593 */
594 static int xmlXPathDisableOptimizer = 0;
595 #endif
596
597 /************************************************************************
598 * *
599 * Error handling routines *
600 * *
601 ************************************************************************/
602
603 /**
604 * XP_ERRORNULL:
605 * @X: the error code
606 *
607 * Macro to raise an XPath error and return NULL.
608 */
609 #define XP_ERRORNULL(X) \
610 { xmlXPathErr(ctxt, X); return(NULL); }
611
612 /*
613 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
614 */
615 static const char *xmlXPathErrorMessages[] = {
616 "Ok\n",
617 "Number encoding\n",
618 "Unfinished literal\n",
619 "Start of literal\n",
620 "Expected $ for variable reference\n",
621 "Undefined variable\n",
622 "Invalid predicate\n",
623 "Invalid expression\n",
624 "Missing closing curly brace\n",
625 "Unregistered function\n",
626 "Invalid operand\n",
627 "Invalid type\n",
628 "Invalid number of arguments\n",
629 "Invalid context size\n",
630 "Invalid context position\n",
631 "Memory allocation error\n",
632 "Syntax error\n",
633 "Resource error\n",
634 "Sub resource error\n",
635 "Undefined namespace prefix\n",
636 "Encoding error\n",
637 "Char out of XML range\n",
638 "Invalid or incomplete context\n",
639 "Stack usage error\n",
640 "Forbidden variable\n",
641 "?? Unknown error ??\n" /* Must be last in the list! */
642 };
643 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
644 sizeof(xmlXPathErrorMessages[0])) - 1)
645 /**
646 * xmlXPathErrMemory:
647 * @ctxt: an XPath context
648 * @extra: extra informations
649 *
650 * Handle a redefinition of attribute error
651 */
652 static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt,const char * extra)653 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
654 {
655 if (ctxt != NULL) {
656 if (extra) {
657 xmlChar buf[200];
658
659 xmlStrPrintf(buf, 200,
660 "Memory allocation failed : %s\n",
661 extra);
662 ctxt->lastError.message = (char *) xmlStrdup(buf);
663 } else {
664 ctxt->lastError.message = (char *)
665 xmlStrdup(BAD_CAST "Memory allocation failed\n");
666 }
667 ctxt->lastError.domain = XML_FROM_XPATH;
668 ctxt->lastError.code = XML_ERR_NO_MEMORY;
669 if (ctxt->error != NULL)
670 ctxt->error(ctxt->userData, &ctxt->lastError);
671 } else {
672 if (extra)
673 __xmlRaiseError(NULL, NULL, NULL,
674 NULL, NULL, XML_FROM_XPATH,
675 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
676 extra, NULL, NULL, 0, 0,
677 "Memory allocation failed : %s\n", extra);
678 else
679 __xmlRaiseError(NULL, NULL, NULL,
680 NULL, NULL, XML_FROM_XPATH,
681 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
682 NULL, NULL, NULL, 0, 0,
683 "Memory allocation failed\n");
684 }
685 }
686
687 /**
688 * xmlXPathPErrMemory:
689 * @ctxt: an XPath parser context
690 * @extra: extra informations
691 *
692 * Handle a redefinition of attribute error
693 */
694 static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt,const char * extra)695 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
696 {
697 if (ctxt == NULL)
698 xmlXPathErrMemory(NULL, extra);
699 else {
700 ctxt->error = XPATH_MEMORY_ERROR;
701 xmlXPathErrMemory(ctxt->context, extra);
702 }
703 }
704
705 /**
706 * xmlXPathErr:
707 * @ctxt: a XPath parser context
708 * @error: the error code
709 *
710 * Handle an XPath error
711 */
712 void
xmlXPathErr(xmlXPathParserContextPtr ctxt,int error)713 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
714 {
715 if ((error < 0) || (error > MAXERRNO))
716 error = MAXERRNO;
717 if (ctxt == NULL) {
718 __xmlRaiseError(NULL, NULL, NULL,
719 NULL, NULL, XML_FROM_XPATH,
720 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
721 XML_ERR_ERROR, NULL, 0,
722 NULL, NULL, NULL, 0, 0,
723 "%s", xmlXPathErrorMessages[error]);
724 return;
725 }
726 ctxt->error = error;
727 if (ctxt->context == NULL) {
728 __xmlRaiseError(NULL, NULL, NULL,
729 NULL, NULL, XML_FROM_XPATH,
730 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
731 XML_ERR_ERROR, NULL, 0,
732 (const char *) ctxt->base, NULL, NULL,
733 ctxt->cur - ctxt->base, 0,
734 "%s", xmlXPathErrorMessages[error]);
735 return;
736 }
737
738 /* cleanup current last error */
739 xmlResetError(&ctxt->context->lastError);
740
741 ctxt->context->lastError.domain = XML_FROM_XPATH;
742 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
743 XPATH_EXPRESSION_OK;
744 ctxt->context->lastError.level = XML_ERR_ERROR;
745 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
746 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
747 ctxt->context->lastError.node = ctxt->context->debugNode;
748 if (ctxt->context->error != NULL) {
749 ctxt->context->error(ctxt->context->userData,
750 &ctxt->context->lastError);
751 } else {
752 __xmlRaiseError(NULL, NULL, NULL,
753 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
754 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
755 XML_ERR_ERROR, NULL, 0,
756 (const char *) ctxt->base, NULL, NULL,
757 ctxt->cur - ctxt->base, 0,
758 "%s", xmlXPathErrorMessages[error]);
759 }
760
761 }
762
763 /**
764 * xmlXPatherror:
765 * @ctxt: the XPath Parser context
766 * @file: the file name
767 * @line: the line number
768 * @no: the error number
769 *
770 * Formats an error message.
771 */
772 void
xmlXPatherror(xmlXPathParserContextPtr ctxt,const char * file ATTRIBUTE_UNUSED,int line ATTRIBUTE_UNUSED,int no)773 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
774 int line ATTRIBUTE_UNUSED, int no) {
775 xmlXPathErr(ctxt, no);
776 }
777
778 /************************************************************************
779 * *
780 * Utilities *
781 * *
782 ************************************************************************/
783
784 /**
785 * xsltPointerList:
786 *
787 * Pointer-list for various purposes.
788 */
789 typedef struct _xmlPointerList xmlPointerList;
790 typedef xmlPointerList *xmlPointerListPtr;
791 struct _xmlPointerList {
792 void **items;
793 int number;
794 int size;
795 };
796 /*
797 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
798 * and here, we should make the functions public.
799 */
800 static int
xmlPointerListAddSize(xmlPointerListPtr list,void * item,int initialSize)801 xmlPointerListAddSize(xmlPointerListPtr list,
802 void *item,
803 int initialSize)
804 {
805 if (list->items == NULL) {
806 if (initialSize <= 0)
807 initialSize = 1;
808 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
809 if (list->items == NULL) {
810 xmlXPathErrMemory(NULL,
811 "xmlPointerListCreate: allocating item\n");
812 return(-1);
813 }
814 list->number = 0;
815 list->size = initialSize;
816 } else if (list->size <= list->number) {
817 if (list->size > 50000000) {
818 xmlXPathErrMemory(NULL,
819 "xmlPointerListAddSize: re-allocating item\n");
820 return(-1);
821 }
822 list->size *= 2;
823 list->items = (void **) xmlRealloc(list->items,
824 list->size * sizeof(void *));
825 if (list->items == NULL) {
826 xmlXPathErrMemory(NULL,
827 "xmlPointerListAddSize: re-allocating item\n");
828 list->size = 0;
829 return(-1);
830 }
831 }
832 list->items[list->number++] = item;
833 return(0);
834 }
835
836 /**
837 * xsltPointerListCreate:
838 *
839 * Creates an xsltPointerList structure.
840 *
841 * Returns a xsltPointerList structure or NULL in case of an error.
842 */
843 static xmlPointerListPtr
xmlPointerListCreate(int initialSize)844 xmlPointerListCreate(int initialSize)
845 {
846 xmlPointerListPtr ret;
847
848 ret = xmlMalloc(sizeof(xmlPointerList));
849 if (ret == NULL) {
850 xmlXPathErrMemory(NULL,
851 "xmlPointerListCreate: allocating item\n");
852 return (NULL);
853 }
854 memset(ret, 0, sizeof(xmlPointerList));
855 if (initialSize > 0) {
856 xmlPointerListAddSize(ret, NULL, initialSize);
857 ret->number = 0;
858 }
859 return (ret);
860 }
861
862 /**
863 * xsltPointerListFree:
864 *
865 * Frees the xsltPointerList structure. This does not free
866 * the content of the list.
867 */
868 static void
xmlPointerListFree(xmlPointerListPtr list)869 xmlPointerListFree(xmlPointerListPtr list)
870 {
871 if (list == NULL)
872 return;
873 if (list->items != NULL)
874 xmlFree(list->items);
875 xmlFree(list);
876 }
877
878 /************************************************************************
879 * *
880 * Parser Types *
881 * *
882 ************************************************************************/
883
884 /*
885 * Types are private:
886 */
887
888 typedef enum {
889 XPATH_OP_END=0,
890 XPATH_OP_AND,
891 XPATH_OP_OR,
892 XPATH_OP_EQUAL,
893 XPATH_OP_CMP,
894 XPATH_OP_PLUS,
895 XPATH_OP_MULT,
896 XPATH_OP_UNION,
897 XPATH_OP_ROOT,
898 XPATH_OP_NODE,
899 XPATH_OP_COLLECT,
900 XPATH_OP_VALUE, /* 11 */
901 XPATH_OP_VARIABLE,
902 XPATH_OP_FUNCTION,
903 XPATH_OP_ARG,
904 XPATH_OP_PREDICATE,
905 XPATH_OP_FILTER, /* 16 */
906 XPATH_OP_SORT /* 17 */
907 #ifdef LIBXML_XPTR_ENABLED
908 ,XPATH_OP_RANGETO
909 #endif
910 } xmlXPathOp;
911
912 typedef enum {
913 AXIS_ANCESTOR = 1,
914 AXIS_ANCESTOR_OR_SELF,
915 AXIS_ATTRIBUTE,
916 AXIS_CHILD,
917 AXIS_DESCENDANT,
918 AXIS_DESCENDANT_OR_SELF,
919 AXIS_FOLLOWING,
920 AXIS_FOLLOWING_SIBLING,
921 AXIS_NAMESPACE,
922 AXIS_PARENT,
923 AXIS_PRECEDING,
924 AXIS_PRECEDING_SIBLING,
925 AXIS_SELF
926 } xmlXPathAxisVal;
927
928 typedef enum {
929 NODE_TEST_NONE = 0,
930 NODE_TEST_TYPE = 1,
931 NODE_TEST_PI = 2,
932 NODE_TEST_ALL = 3,
933 NODE_TEST_NS = 4,
934 NODE_TEST_NAME = 5
935 } xmlXPathTestVal;
936
937 typedef enum {
938 NODE_TYPE_NODE = 0,
939 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
940 NODE_TYPE_TEXT = XML_TEXT_NODE,
941 NODE_TYPE_PI = XML_PI_NODE
942 } xmlXPathTypeVal;
943
944 typedef struct _xmlXPathStepOp xmlXPathStepOp;
945 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
946 struct _xmlXPathStepOp {
947 xmlXPathOp op; /* The identifier of the operation */
948 int ch1; /* First child */
949 int ch2; /* Second child */
950 int value;
951 int value2;
952 int value3;
953 void *value4;
954 void *value5;
955 xmlXPathFunction cache;
956 void *cacheURI;
957 };
958
959 struct _xmlXPathCompExpr {
960 int nbStep; /* Number of steps in this expression */
961 int maxStep; /* Maximum number of steps allocated */
962 xmlXPathStepOp *steps; /* ops for computation of this expression */
963 int last; /* index of last step in expression */
964 xmlChar *expr; /* the expression being computed */
965 xmlDictPtr dict; /* the dictionary to use if any */
966 #ifdef DEBUG_EVAL_COUNTS
967 int nb;
968 xmlChar *string;
969 #endif
970 #ifdef XPATH_STREAMING
971 xmlPatternPtr stream;
972 #endif
973 };
974
975 /************************************************************************
976 * *
977 * Forward declarations *
978 * *
979 ************************************************************************/
980 static void
981 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
982 static void
983 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
984 static int
985 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
986 xmlXPathStepOpPtr op, xmlNodePtr *first);
987 static int
988 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
989 xmlXPathStepOpPtr op,
990 int isPredicate);
991 static void
992 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
993
994 /************************************************************************
995 * *
996 * Parser Type functions *
997 * *
998 ************************************************************************/
999
1000 /**
1001 * xmlXPathNewCompExpr:
1002 *
1003 * Create a new Xpath component
1004 *
1005 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1006 */
1007 static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void)1008 xmlXPathNewCompExpr(void) {
1009 xmlXPathCompExprPtr cur;
1010
1011 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1012 if (cur == NULL) {
1013 xmlXPathErrMemory(NULL, "allocating component\n");
1014 return(NULL);
1015 }
1016 memset(cur, 0, sizeof(xmlXPathCompExpr));
1017 cur->maxStep = 10;
1018 cur->nbStep = 0;
1019 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1020 sizeof(xmlXPathStepOp));
1021 if (cur->steps == NULL) {
1022 xmlXPathErrMemory(NULL, "allocating steps\n");
1023 xmlFree(cur);
1024 return(NULL);
1025 }
1026 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1027 cur->last = -1;
1028 #ifdef DEBUG_EVAL_COUNTS
1029 cur->nb = 0;
1030 #endif
1031 return(cur);
1032 }
1033
1034 /**
1035 * xmlXPathFreeCompExpr:
1036 * @comp: an XPATH comp
1037 *
1038 * Free up the memory allocated by @comp
1039 */
1040 void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)1041 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1042 {
1043 xmlXPathStepOpPtr op;
1044 int i;
1045
1046 if (comp == NULL)
1047 return;
1048 if (comp->dict == NULL) {
1049 for (i = 0; i < comp->nbStep; i++) {
1050 op = &comp->steps[i];
1051 if (op->value4 != NULL) {
1052 if (op->op == XPATH_OP_VALUE)
1053 xmlXPathFreeObject(op->value4);
1054 else
1055 xmlFree(op->value4);
1056 }
1057 if (op->value5 != NULL)
1058 xmlFree(op->value5);
1059 }
1060 } else {
1061 for (i = 0; i < comp->nbStep; i++) {
1062 op = &comp->steps[i];
1063 if (op->value4 != NULL) {
1064 if (op->op == XPATH_OP_VALUE)
1065 xmlXPathFreeObject(op->value4);
1066 }
1067 }
1068 xmlDictFree(comp->dict);
1069 }
1070 if (comp->steps != NULL) {
1071 xmlFree(comp->steps);
1072 }
1073 #ifdef DEBUG_EVAL_COUNTS
1074 if (comp->string != NULL) {
1075 xmlFree(comp->string);
1076 }
1077 #endif
1078 #ifdef XPATH_STREAMING
1079 if (comp->stream != NULL) {
1080 xmlFreePatternList(comp->stream);
1081 }
1082 #endif
1083 if (comp->expr != NULL) {
1084 xmlFree(comp->expr);
1085 }
1086
1087 xmlFree(comp);
1088 }
1089
1090 /**
1091 * xmlXPathCompExprAdd:
1092 * @comp: the compiled expression
1093 * @ch1: first child index
1094 * @ch2: second child index
1095 * @op: an op
1096 * @value: the first int value
1097 * @value2: the second int value
1098 * @value3: the third int value
1099 * @value4: the first string value
1100 * @value5: the second string value
1101 *
1102 * Add a step to an XPath Compiled Expression
1103 *
1104 * Returns -1 in case of failure, the index otherwise
1105 */
1106 static int
xmlXPathCompExprAdd(xmlXPathCompExprPtr comp,int ch1,int ch2,xmlXPathOp op,int value,int value2,int value3,void * value4,void * value5)1107 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1108 xmlXPathOp op, int value,
1109 int value2, int value3, void *value4, void *value5) {
1110 if (comp->nbStep >= comp->maxStep) {
1111 xmlXPathStepOp *real;
1112
1113 if (comp->maxStep >= XPATH_MAX_STEPS) {
1114 xmlXPathErrMemory(NULL, "adding step\n");
1115 return(-1);
1116 }
1117 comp->maxStep *= 2;
1118 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1119 comp->maxStep * sizeof(xmlXPathStepOp));
1120 if (real == NULL) {
1121 comp->maxStep /= 2;
1122 xmlXPathErrMemory(NULL, "adding step\n");
1123 return(-1);
1124 }
1125 comp->steps = real;
1126 }
1127 comp->last = comp->nbStep;
1128 comp->steps[comp->nbStep].ch1 = ch1;
1129 comp->steps[comp->nbStep].ch2 = ch2;
1130 comp->steps[comp->nbStep].op = op;
1131 comp->steps[comp->nbStep].value = value;
1132 comp->steps[comp->nbStep].value2 = value2;
1133 comp->steps[comp->nbStep].value3 = value3;
1134 if ((comp->dict != NULL) &&
1135 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1136 (op == XPATH_OP_COLLECT))) {
1137 if (value4 != NULL) {
1138 comp->steps[comp->nbStep].value4 = (xmlChar *)
1139 (void *)xmlDictLookup(comp->dict, value4, -1);
1140 xmlFree(value4);
1141 } else
1142 comp->steps[comp->nbStep].value4 = NULL;
1143 if (value5 != NULL) {
1144 comp->steps[comp->nbStep].value5 = (xmlChar *)
1145 (void *)xmlDictLookup(comp->dict, value5, -1);
1146 xmlFree(value5);
1147 } else
1148 comp->steps[comp->nbStep].value5 = NULL;
1149 } else {
1150 comp->steps[comp->nbStep].value4 = value4;
1151 comp->steps[comp->nbStep].value5 = value5;
1152 }
1153 comp->steps[comp->nbStep].cache = NULL;
1154 return(comp->nbStep++);
1155 }
1156
1157 /**
1158 * xmlXPathCompSwap:
1159 * @comp: the compiled expression
1160 * @op: operation index
1161 *
1162 * Swaps 2 operations in the compiled expression
1163 */
1164 static void
xmlXPathCompSwap(xmlXPathStepOpPtr op)1165 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1166 int tmp;
1167
1168 #ifndef LIBXML_THREAD_ENABLED
1169 /*
1170 * Since this manipulates possibly shared variables, this is
1171 * disabled if one detects that the library is used in a multithreaded
1172 * application
1173 */
1174 if (xmlXPathDisableOptimizer)
1175 return;
1176 #endif
1177
1178 tmp = op->ch1;
1179 op->ch1 = op->ch2;
1180 op->ch2 = tmp;
1181 }
1182
1183 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1184 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1185 (op), (val), (val2), (val3), (val4), (val5))
1186 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1187 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1188 (op), (val), (val2), (val3), (val4), (val5))
1189
1190 #define PUSH_LEAVE_EXPR(op, val, val2) \
1191 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1192
1193 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1194 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1195
1196 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1197 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1198 (val), (val2), 0 ,NULL ,NULL)
1199
1200 /************************************************************************
1201 * *
1202 * XPath object cache structures *
1203 * *
1204 ************************************************************************/
1205
1206 /* #define XP_DEFAULT_CACHE_ON */
1207
1208 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1209
1210 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1211 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1212 struct _xmlXPathContextCache {
1213 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1214 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1215 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1216 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1217 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1218 int maxNodeset;
1219 int maxString;
1220 int maxBoolean;
1221 int maxNumber;
1222 int maxMisc;
1223 #ifdef XP_DEBUG_OBJ_USAGE
1224 int dbgCachedAll;
1225 int dbgCachedNodeset;
1226 int dbgCachedString;
1227 int dbgCachedBool;
1228 int dbgCachedNumber;
1229 int dbgCachedPoint;
1230 int dbgCachedRange;
1231 int dbgCachedLocset;
1232 int dbgCachedUsers;
1233 int dbgCachedXSLTTree;
1234 int dbgCachedUndefined;
1235
1236
1237 int dbgReusedAll;
1238 int dbgReusedNodeset;
1239 int dbgReusedString;
1240 int dbgReusedBool;
1241 int dbgReusedNumber;
1242 int dbgReusedPoint;
1243 int dbgReusedRange;
1244 int dbgReusedLocset;
1245 int dbgReusedUsers;
1246 int dbgReusedXSLTTree;
1247 int dbgReusedUndefined;
1248
1249 #endif
1250 };
1251
1252 /************************************************************************
1253 * *
1254 * Debugging related functions *
1255 * *
1256 ************************************************************************/
1257
1258 #define STRANGE \
1259 xmlGenericError(xmlGenericErrorContext, \
1260 "Internal error at %s:%d\n", \
1261 __FILE__, __LINE__);
1262
1263 #ifdef LIBXML_DEBUG_ENABLED
1264 static void
xmlXPathDebugDumpNode(FILE * output,xmlNodePtr cur,int depth)1265 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1266 int i;
1267 char shift[100];
1268
1269 for (i = 0;((i < depth) && (i < 25));i++)
1270 shift[2 * i] = shift[2 * i + 1] = ' ';
1271 shift[2 * i] = shift[2 * i + 1] = 0;
1272 if (cur == NULL) {
1273 fprintf(output, "%s", shift);
1274 fprintf(output, "Node is NULL !\n");
1275 return;
1276
1277 }
1278
1279 if ((cur->type == XML_DOCUMENT_NODE) ||
1280 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1281 fprintf(output, "%s", shift);
1282 fprintf(output, " /\n");
1283 } else if (cur->type == XML_ATTRIBUTE_NODE)
1284 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1285 else
1286 xmlDebugDumpOneNode(output, cur, depth);
1287 }
1288 static void
xmlXPathDebugDumpNodeList(FILE * output,xmlNodePtr cur,int depth)1289 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1290 xmlNodePtr tmp;
1291 int i;
1292 char shift[100];
1293
1294 for (i = 0;((i < depth) && (i < 25));i++)
1295 shift[2 * i] = shift[2 * i + 1] = ' ';
1296 shift[2 * i] = shift[2 * i + 1] = 0;
1297 if (cur == NULL) {
1298 fprintf(output, "%s", shift);
1299 fprintf(output, "Node is NULL !\n");
1300 return;
1301
1302 }
1303
1304 while (cur != NULL) {
1305 tmp = cur;
1306 cur = cur->next;
1307 xmlDebugDumpOneNode(output, tmp, depth);
1308 }
1309 }
1310
1311 static void
xmlXPathDebugDumpNodeSet(FILE * output,xmlNodeSetPtr cur,int depth)1312 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1313 int i;
1314 char shift[100];
1315
1316 for (i = 0;((i < depth) && (i < 25));i++)
1317 shift[2 * i] = shift[2 * i + 1] = ' ';
1318 shift[2 * i] = shift[2 * i + 1] = 0;
1319
1320 if (cur == NULL) {
1321 fprintf(output, "%s", shift);
1322 fprintf(output, "NodeSet is NULL !\n");
1323 return;
1324
1325 }
1326
1327 if (cur != NULL) {
1328 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1329 for (i = 0;i < cur->nodeNr;i++) {
1330 fprintf(output, "%s", shift);
1331 fprintf(output, "%d", i + 1);
1332 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1333 }
1334 }
1335 }
1336
1337 static void
xmlXPathDebugDumpValueTree(FILE * output,xmlNodeSetPtr cur,int depth)1338 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1339 int i;
1340 char shift[100];
1341
1342 for (i = 0;((i < depth) && (i < 25));i++)
1343 shift[2 * i] = shift[2 * i + 1] = ' ';
1344 shift[2 * i] = shift[2 * i + 1] = 0;
1345
1346 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1347 fprintf(output, "%s", shift);
1348 fprintf(output, "Value Tree is NULL !\n");
1349 return;
1350
1351 }
1352
1353 fprintf(output, "%s", shift);
1354 fprintf(output, "%d", i + 1);
1355 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1356 }
1357 #if defined(LIBXML_XPTR_ENABLED)
1358 static void
xmlXPathDebugDumpLocationSet(FILE * output,xmlLocationSetPtr cur,int depth)1359 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1360 int i;
1361 char shift[100];
1362
1363 for (i = 0;((i < depth) && (i < 25));i++)
1364 shift[2 * i] = shift[2 * i + 1] = ' ';
1365 shift[2 * i] = shift[2 * i + 1] = 0;
1366
1367 if (cur == NULL) {
1368 fprintf(output, "%s", shift);
1369 fprintf(output, "LocationSet is NULL !\n");
1370 return;
1371
1372 }
1373
1374 for (i = 0;i < cur->locNr;i++) {
1375 fprintf(output, "%s", shift);
1376 fprintf(output, "%d : ", i + 1);
1377 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1378 }
1379 }
1380 #endif /* LIBXML_XPTR_ENABLED */
1381
1382 /**
1383 * xmlXPathDebugDumpObject:
1384 * @output: the FILE * to dump the output
1385 * @cur: the object to inspect
1386 * @depth: indentation level
1387 *
1388 * Dump the content of the object for debugging purposes
1389 */
1390 void
xmlXPathDebugDumpObject(FILE * output,xmlXPathObjectPtr cur,int depth)1391 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1392 int i;
1393 char shift[100];
1394
1395 if (output == NULL) return;
1396
1397 for (i = 0;((i < depth) && (i < 25));i++)
1398 shift[2 * i] = shift[2 * i + 1] = ' ';
1399 shift[2 * i] = shift[2 * i + 1] = 0;
1400
1401
1402 fprintf(output, "%s", shift);
1403
1404 if (cur == NULL) {
1405 fprintf(output, "Object is empty (NULL)\n");
1406 return;
1407 }
1408 switch(cur->type) {
1409 case XPATH_UNDEFINED:
1410 fprintf(output, "Object is uninitialized\n");
1411 break;
1412 case XPATH_NODESET:
1413 fprintf(output, "Object is a Node Set :\n");
1414 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1415 break;
1416 case XPATH_XSLT_TREE:
1417 fprintf(output, "Object is an XSLT value tree :\n");
1418 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1419 break;
1420 case XPATH_BOOLEAN:
1421 fprintf(output, "Object is a Boolean : ");
1422 if (cur->boolval) fprintf(output, "true\n");
1423 else fprintf(output, "false\n");
1424 break;
1425 case XPATH_NUMBER:
1426 switch (xmlXPathIsInf(cur->floatval)) {
1427 case 1:
1428 fprintf(output, "Object is a number : Infinity\n");
1429 break;
1430 case -1:
1431 fprintf(output, "Object is a number : -Infinity\n");
1432 break;
1433 default:
1434 if (xmlXPathIsNaN(cur->floatval)) {
1435 fprintf(output, "Object is a number : NaN\n");
1436 } else if (cur->floatval == 0) {
1437 /* Omit sign for negative zero. */
1438 fprintf(output, "Object is a number : 0\n");
1439 } else {
1440 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1441 }
1442 }
1443 break;
1444 case XPATH_STRING:
1445 fprintf(output, "Object is a string : ");
1446 xmlDebugDumpString(output, cur->stringval);
1447 fprintf(output, "\n");
1448 break;
1449 case XPATH_POINT:
1450 fprintf(output, "Object is a point : index %d in node", cur->index);
1451 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1452 fprintf(output, "\n");
1453 break;
1454 case XPATH_RANGE:
1455 if ((cur->user2 == NULL) ||
1456 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1457 fprintf(output, "Object is a collapsed range :\n");
1458 fprintf(output, "%s", shift);
1459 if (cur->index >= 0)
1460 fprintf(output, "index %d in ", cur->index);
1461 fprintf(output, "node\n");
1462 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1463 depth + 1);
1464 } else {
1465 fprintf(output, "Object is a range :\n");
1466 fprintf(output, "%s", shift);
1467 fprintf(output, "From ");
1468 if (cur->index >= 0)
1469 fprintf(output, "index %d in ", cur->index);
1470 fprintf(output, "node\n");
1471 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1472 depth + 1);
1473 fprintf(output, "%s", shift);
1474 fprintf(output, "To ");
1475 if (cur->index2 >= 0)
1476 fprintf(output, "index %d in ", cur->index2);
1477 fprintf(output, "node\n");
1478 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1479 depth + 1);
1480 fprintf(output, "\n");
1481 }
1482 break;
1483 case XPATH_LOCATIONSET:
1484 #if defined(LIBXML_XPTR_ENABLED)
1485 fprintf(output, "Object is a Location Set:\n");
1486 xmlXPathDebugDumpLocationSet(output,
1487 (xmlLocationSetPtr) cur->user, depth);
1488 #endif
1489 break;
1490 case XPATH_USERS:
1491 fprintf(output, "Object is user defined\n");
1492 break;
1493 }
1494 }
1495
1496 static void
xmlXPathDebugDumpStepOp(FILE * output,xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op,int depth)1497 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1498 xmlXPathStepOpPtr op, int depth) {
1499 int i;
1500 char shift[100];
1501
1502 for (i = 0;((i < depth) && (i < 25));i++)
1503 shift[2 * i] = shift[2 * i + 1] = ' ';
1504 shift[2 * i] = shift[2 * i + 1] = 0;
1505
1506 fprintf(output, "%s", shift);
1507 if (op == NULL) {
1508 fprintf(output, "Step is NULL\n");
1509 return;
1510 }
1511 switch (op->op) {
1512 case XPATH_OP_END:
1513 fprintf(output, "END"); break;
1514 case XPATH_OP_AND:
1515 fprintf(output, "AND"); break;
1516 case XPATH_OP_OR:
1517 fprintf(output, "OR"); break;
1518 case XPATH_OP_EQUAL:
1519 if (op->value)
1520 fprintf(output, "EQUAL =");
1521 else
1522 fprintf(output, "EQUAL !=");
1523 break;
1524 case XPATH_OP_CMP:
1525 if (op->value)
1526 fprintf(output, "CMP <");
1527 else
1528 fprintf(output, "CMP >");
1529 if (!op->value2)
1530 fprintf(output, "=");
1531 break;
1532 case XPATH_OP_PLUS:
1533 if (op->value == 0)
1534 fprintf(output, "PLUS -");
1535 else if (op->value == 1)
1536 fprintf(output, "PLUS +");
1537 else if (op->value == 2)
1538 fprintf(output, "PLUS unary -");
1539 else if (op->value == 3)
1540 fprintf(output, "PLUS unary - -");
1541 break;
1542 case XPATH_OP_MULT:
1543 if (op->value == 0)
1544 fprintf(output, "MULT *");
1545 else if (op->value == 1)
1546 fprintf(output, "MULT div");
1547 else
1548 fprintf(output, "MULT mod");
1549 break;
1550 case XPATH_OP_UNION:
1551 fprintf(output, "UNION"); break;
1552 case XPATH_OP_ROOT:
1553 fprintf(output, "ROOT"); break;
1554 case XPATH_OP_NODE:
1555 fprintf(output, "NODE"); break;
1556 case XPATH_OP_SORT:
1557 fprintf(output, "SORT"); break;
1558 case XPATH_OP_COLLECT: {
1559 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1560 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1561 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1562 const xmlChar *prefix = op->value4;
1563 const xmlChar *name = op->value5;
1564
1565 fprintf(output, "COLLECT ");
1566 switch (axis) {
1567 case AXIS_ANCESTOR:
1568 fprintf(output, " 'ancestors' "); break;
1569 case AXIS_ANCESTOR_OR_SELF:
1570 fprintf(output, " 'ancestors-or-self' "); break;
1571 case AXIS_ATTRIBUTE:
1572 fprintf(output, " 'attributes' "); break;
1573 case AXIS_CHILD:
1574 fprintf(output, " 'child' "); break;
1575 case AXIS_DESCENDANT:
1576 fprintf(output, " 'descendant' "); break;
1577 case AXIS_DESCENDANT_OR_SELF:
1578 fprintf(output, " 'descendant-or-self' "); break;
1579 case AXIS_FOLLOWING:
1580 fprintf(output, " 'following' "); break;
1581 case AXIS_FOLLOWING_SIBLING:
1582 fprintf(output, " 'following-siblings' "); break;
1583 case AXIS_NAMESPACE:
1584 fprintf(output, " 'namespace' "); break;
1585 case AXIS_PARENT:
1586 fprintf(output, " 'parent' "); break;
1587 case AXIS_PRECEDING:
1588 fprintf(output, " 'preceding' "); break;
1589 case AXIS_PRECEDING_SIBLING:
1590 fprintf(output, " 'preceding-sibling' "); break;
1591 case AXIS_SELF:
1592 fprintf(output, " 'self' "); break;
1593 }
1594 switch (test) {
1595 case NODE_TEST_NONE:
1596 fprintf(output, "'none' "); break;
1597 case NODE_TEST_TYPE:
1598 fprintf(output, "'type' "); break;
1599 case NODE_TEST_PI:
1600 fprintf(output, "'PI' "); break;
1601 case NODE_TEST_ALL:
1602 fprintf(output, "'all' "); break;
1603 case NODE_TEST_NS:
1604 fprintf(output, "'namespace' "); break;
1605 case NODE_TEST_NAME:
1606 fprintf(output, "'name' "); break;
1607 }
1608 switch (type) {
1609 case NODE_TYPE_NODE:
1610 fprintf(output, "'node' "); break;
1611 case NODE_TYPE_COMMENT:
1612 fprintf(output, "'comment' "); break;
1613 case NODE_TYPE_TEXT:
1614 fprintf(output, "'text' "); break;
1615 case NODE_TYPE_PI:
1616 fprintf(output, "'PI' "); break;
1617 }
1618 if (prefix != NULL)
1619 fprintf(output, "%s:", prefix);
1620 if (name != NULL)
1621 fprintf(output, "%s", (const char *) name);
1622 break;
1623
1624 }
1625 case XPATH_OP_VALUE: {
1626 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1627
1628 fprintf(output, "ELEM ");
1629 xmlXPathDebugDumpObject(output, object, 0);
1630 goto finish;
1631 }
1632 case XPATH_OP_VARIABLE: {
1633 const xmlChar *prefix = op->value5;
1634 const xmlChar *name = op->value4;
1635
1636 if (prefix != NULL)
1637 fprintf(output, "VARIABLE %s:%s", prefix, name);
1638 else
1639 fprintf(output, "VARIABLE %s", name);
1640 break;
1641 }
1642 case XPATH_OP_FUNCTION: {
1643 int nbargs = op->value;
1644 const xmlChar *prefix = op->value5;
1645 const xmlChar *name = op->value4;
1646
1647 if (prefix != NULL)
1648 fprintf(output, "FUNCTION %s:%s(%d args)",
1649 prefix, name, nbargs);
1650 else
1651 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1652 break;
1653 }
1654 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1655 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1656 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1657 #ifdef LIBXML_XPTR_ENABLED
1658 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1659 #endif
1660 default:
1661 fprintf(output, "UNKNOWN %d\n", op->op); return;
1662 }
1663 fprintf(output, "\n");
1664 finish:
1665 if (op->ch1 >= 0)
1666 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1667 if (op->ch2 >= 0)
1668 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1669 }
1670
1671 /**
1672 * xmlXPathDebugDumpCompExpr:
1673 * @output: the FILE * for the output
1674 * @comp: the precompiled XPath expression
1675 * @depth: the indentation level.
1676 *
1677 * Dumps the tree of the compiled XPath expression.
1678 */
1679 void
xmlXPathDebugDumpCompExpr(FILE * output,xmlXPathCompExprPtr comp,int depth)1680 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1681 int depth) {
1682 int i;
1683 char shift[100];
1684
1685 if ((output == NULL) || (comp == NULL)) return;
1686
1687 for (i = 0;((i < depth) && (i < 25));i++)
1688 shift[2 * i] = shift[2 * i + 1] = ' ';
1689 shift[2 * i] = shift[2 * i + 1] = 0;
1690
1691 fprintf(output, "%s", shift);
1692
1693 #ifdef XPATH_STREAMING
1694 if (comp->stream) {
1695 fprintf(output, "Streaming Expression\n");
1696 } else
1697 #endif
1698 {
1699 fprintf(output, "Compiled Expression : %d elements\n",
1700 comp->nbStep);
1701 i = comp->last;
1702 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1703 }
1704 }
1705
1706 #ifdef XP_DEBUG_OBJ_USAGE
1707
1708 /*
1709 * XPath object usage related debugging variables.
1710 */
1711 static int xmlXPathDebugObjCounterUndefined = 0;
1712 static int xmlXPathDebugObjCounterNodeset = 0;
1713 static int xmlXPathDebugObjCounterBool = 0;
1714 static int xmlXPathDebugObjCounterNumber = 0;
1715 static int xmlXPathDebugObjCounterString = 0;
1716 static int xmlXPathDebugObjCounterPoint = 0;
1717 static int xmlXPathDebugObjCounterRange = 0;
1718 static int xmlXPathDebugObjCounterLocset = 0;
1719 static int xmlXPathDebugObjCounterUsers = 0;
1720 static int xmlXPathDebugObjCounterXSLTTree = 0;
1721 static int xmlXPathDebugObjCounterAll = 0;
1722
1723 static int xmlXPathDebugObjTotalUndefined = 0;
1724 static int xmlXPathDebugObjTotalNodeset = 0;
1725 static int xmlXPathDebugObjTotalBool = 0;
1726 static int xmlXPathDebugObjTotalNumber = 0;
1727 static int xmlXPathDebugObjTotalString = 0;
1728 static int xmlXPathDebugObjTotalPoint = 0;
1729 static int xmlXPathDebugObjTotalRange = 0;
1730 static int xmlXPathDebugObjTotalLocset = 0;
1731 static int xmlXPathDebugObjTotalUsers = 0;
1732 static int xmlXPathDebugObjTotalXSLTTree = 0;
1733 static int xmlXPathDebugObjTotalAll = 0;
1734
1735 static int xmlXPathDebugObjMaxUndefined = 0;
1736 static int xmlXPathDebugObjMaxNodeset = 0;
1737 static int xmlXPathDebugObjMaxBool = 0;
1738 static int xmlXPathDebugObjMaxNumber = 0;
1739 static int xmlXPathDebugObjMaxString = 0;
1740 static int xmlXPathDebugObjMaxPoint = 0;
1741 static int xmlXPathDebugObjMaxRange = 0;
1742 static int xmlXPathDebugObjMaxLocset = 0;
1743 static int xmlXPathDebugObjMaxUsers = 0;
1744 static int xmlXPathDebugObjMaxXSLTTree = 0;
1745 static int xmlXPathDebugObjMaxAll = 0;
1746
1747 /* REVISIT TODO: Make this static when committing */
1748 static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)1749 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1750 {
1751 if (ctxt != NULL) {
1752 if (ctxt->cache != NULL) {
1753 xmlXPathContextCachePtr cache =
1754 (xmlXPathContextCachePtr) ctxt->cache;
1755
1756 cache->dbgCachedAll = 0;
1757 cache->dbgCachedNodeset = 0;
1758 cache->dbgCachedString = 0;
1759 cache->dbgCachedBool = 0;
1760 cache->dbgCachedNumber = 0;
1761 cache->dbgCachedPoint = 0;
1762 cache->dbgCachedRange = 0;
1763 cache->dbgCachedLocset = 0;
1764 cache->dbgCachedUsers = 0;
1765 cache->dbgCachedXSLTTree = 0;
1766 cache->dbgCachedUndefined = 0;
1767
1768 cache->dbgReusedAll = 0;
1769 cache->dbgReusedNodeset = 0;
1770 cache->dbgReusedString = 0;
1771 cache->dbgReusedBool = 0;
1772 cache->dbgReusedNumber = 0;
1773 cache->dbgReusedPoint = 0;
1774 cache->dbgReusedRange = 0;
1775 cache->dbgReusedLocset = 0;
1776 cache->dbgReusedUsers = 0;
1777 cache->dbgReusedXSLTTree = 0;
1778 cache->dbgReusedUndefined = 0;
1779 }
1780 }
1781
1782 xmlXPathDebugObjCounterUndefined = 0;
1783 xmlXPathDebugObjCounterNodeset = 0;
1784 xmlXPathDebugObjCounterBool = 0;
1785 xmlXPathDebugObjCounterNumber = 0;
1786 xmlXPathDebugObjCounterString = 0;
1787 xmlXPathDebugObjCounterPoint = 0;
1788 xmlXPathDebugObjCounterRange = 0;
1789 xmlXPathDebugObjCounterLocset = 0;
1790 xmlXPathDebugObjCounterUsers = 0;
1791 xmlXPathDebugObjCounterXSLTTree = 0;
1792 xmlXPathDebugObjCounterAll = 0;
1793
1794 xmlXPathDebugObjTotalUndefined = 0;
1795 xmlXPathDebugObjTotalNodeset = 0;
1796 xmlXPathDebugObjTotalBool = 0;
1797 xmlXPathDebugObjTotalNumber = 0;
1798 xmlXPathDebugObjTotalString = 0;
1799 xmlXPathDebugObjTotalPoint = 0;
1800 xmlXPathDebugObjTotalRange = 0;
1801 xmlXPathDebugObjTotalLocset = 0;
1802 xmlXPathDebugObjTotalUsers = 0;
1803 xmlXPathDebugObjTotalXSLTTree = 0;
1804 xmlXPathDebugObjTotalAll = 0;
1805
1806 xmlXPathDebugObjMaxUndefined = 0;
1807 xmlXPathDebugObjMaxNodeset = 0;
1808 xmlXPathDebugObjMaxBool = 0;
1809 xmlXPathDebugObjMaxNumber = 0;
1810 xmlXPathDebugObjMaxString = 0;
1811 xmlXPathDebugObjMaxPoint = 0;
1812 xmlXPathDebugObjMaxRange = 0;
1813 xmlXPathDebugObjMaxLocset = 0;
1814 xmlXPathDebugObjMaxUsers = 0;
1815 xmlXPathDebugObjMaxXSLTTree = 0;
1816 xmlXPathDebugObjMaxAll = 0;
1817
1818 }
1819
1820 static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1821 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1822 xmlXPathObjectType objType)
1823 {
1824 int isCached = 0;
1825
1826 if (ctxt != NULL) {
1827 if (ctxt->cache != NULL) {
1828 xmlXPathContextCachePtr cache =
1829 (xmlXPathContextCachePtr) ctxt->cache;
1830
1831 isCached = 1;
1832
1833 cache->dbgReusedAll++;
1834 switch (objType) {
1835 case XPATH_UNDEFINED:
1836 cache->dbgReusedUndefined++;
1837 break;
1838 case XPATH_NODESET:
1839 cache->dbgReusedNodeset++;
1840 break;
1841 case XPATH_BOOLEAN:
1842 cache->dbgReusedBool++;
1843 break;
1844 case XPATH_NUMBER:
1845 cache->dbgReusedNumber++;
1846 break;
1847 case XPATH_STRING:
1848 cache->dbgReusedString++;
1849 break;
1850 case XPATH_POINT:
1851 cache->dbgReusedPoint++;
1852 break;
1853 case XPATH_RANGE:
1854 cache->dbgReusedRange++;
1855 break;
1856 case XPATH_LOCATIONSET:
1857 cache->dbgReusedLocset++;
1858 break;
1859 case XPATH_USERS:
1860 cache->dbgReusedUsers++;
1861 break;
1862 case XPATH_XSLT_TREE:
1863 cache->dbgReusedXSLTTree++;
1864 break;
1865 default:
1866 break;
1867 }
1868 }
1869 }
1870
1871 switch (objType) {
1872 case XPATH_UNDEFINED:
1873 if (! isCached)
1874 xmlXPathDebugObjTotalUndefined++;
1875 xmlXPathDebugObjCounterUndefined++;
1876 if (xmlXPathDebugObjCounterUndefined >
1877 xmlXPathDebugObjMaxUndefined)
1878 xmlXPathDebugObjMaxUndefined =
1879 xmlXPathDebugObjCounterUndefined;
1880 break;
1881 case XPATH_NODESET:
1882 if (! isCached)
1883 xmlXPathDebugObjTotalNodeset++;
1884 xmlXPathDebugObjCounterNodeset++;
1885 if (xmlXPathDebugObjCounterNodeset >
1886 xmlXPathDebugObjMaxNodeset)
1887 xmlXPathDebugObjMaxNodeset =
1888 xmlXPathDebugObjCounterNodeset;
1889 break;
1890 case XPATH_BOOLEAN:
1891 if (! isCached)
1892 xmlXPathDebugObjTotalBool++;
1893 xmlXPathDebugObjCounterBool++;
1894 if (xmlXPathDebugObjCounterBool >
1895 xmlXPathDebugObjMaxBool)
1896 xmlXPathDebugObjMaxBool =
1897 xmlXPathDebugObjCounterBool;
1898 break;
1899 case XPATH_NUMBER:
1900 if (! isCached)
1901 xmlXPathDebugObjTotalNumber++;
1902 xmlXPathDebugObjCounterNumber++;
1903 if (xmlXPathDebugObjCounterNumber >
1904 xmlXPathDebugObjMaxNumber)
1905 xmlXPathDebugObjMaxNumber =
1906 xmlXPathDebugObjCounterNumber;
1907 break;
1908 case XPATH_STRING:
1909 if (! isCached)
1910 xmlXPathDebugObjTotalString++;
1911 xmlXPathDebugObjCounterString++;
1912 if (xmlXPathDebugObjCounterString >
1913 xmlXPathDebugObjMaxString)
1914 xmlXPathDebugObjMaxString =
1915 xmlXPathDebugObjCounterString;
1916 break;
1917 case XPATH_POINT:
1918 if (! isCached)
1919 xmlXPathDebugObjTotalPoint++;
1920 xmlXPathDebugObjCounterPoint++;
1921 if (xmlXPathDebugObjCounterPoint >
1922 xmlXPathDebugObjMaxPoint)
1923 xmlXPathDebugObjMaxPoint =
1924 xmlXPathDebugObjCounterPoint;
1925 break;
1926 case XPATH_RANGE:
1927 if (! isCached)
1928 xmlXPathDebugObjTotalRange++;
1929 xmlXPathDebugObjCounterRange++;
1930 if (xmlXPathDebugObjCounterRange >
1931 xmlXPathDebugObjMaxRange)
1932 xmlXPathDebugObjMaxRange =
1933 xmlXPathDebugObjCounterRange;
1934 break;
1935 case XPATH_LOCATIONSET:
1936 if (! isCached)
1937 xmlXPathDebugObjTotalLocset++;
1938 xmlXPathDebugObjCounterLocset++;
1939 if (xmlXPathDebugObjCounterLocset >
1940 xmlXPathDebugObjMaxLocset)
1941 xmlXPathDebugObjMaxLocset =
1942 xmlXPathDebugObjCounterLocset;
1943 break;
1944 case XPATH_USERS:
1945 if (! isCached)
1946 xmlXPathDebugObjTotalUsers++;
1947 xmlXPathDebugObjCounterUsers++;
1948 if (xmlXPathDebugObjCounterUsers >
1949 xmlXPathDebugObjMaxUsers)
1950 xmlXPathDebugObjMaxUsers =
1951 xmlXPathDebugObjCounterUsers;
1952 break;
1953 case XPATH_XSLT_TREE:
1954 if (! isCached)
1955 xmlXPathDebugObjTotalXSLTTree++;
1956 xmlXPathDebugObjCounterXSLTTree++;
1957 if (xmlXPathDebugObjCounterXSLTTree >
1958 xmlXPathDebugObjMaxXSLTTree)
1959 xmlXPathDebugObjMaxXSLTTree =
1960 xmlXPathDebugObjCounterXSLTTree;
1961 break;
1962 default:
1963 break;
1964 }
1965 if (! isCached)
1966 xmlXPathDebugObjTotalAll++;
1967 xmlXPathDebugObjCounterAll++;
1968 if (xmlXPathDebugObjCounterAll >
1969 xmlXPathDebugObjMaxAll)
1970 xmlXPathDebugObjMaxAll =
1971 xmlXPathDebugObjCounterAll;
1972 }
1973
1974 static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,xmlXPathObjectType objType)1975 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1976 xmlXPathObjectType objType)
1977 {
1978 int isCached = 0;
1979
1980 if (ctxt != NULL) {
1981 if (ctxt->cache != NULL) {
1982 xmlXPathContextCachePtr cache =
1983 (xmlXPathContextCachePtr) ctxt->cache;
1984
1985 isCached = 1;
1986
1987 cache->dbgCachedAll++;
1988 switch (objType) {
1989 case XPATH_UNDEFINED:
1990 cache->dbgCachedUndefined++;
1991 break;
1992 case XPATH_NODESET:
1993 cache->dbgCachedNodeset++;
1994 break;
1995 case XPATH_BOOLEAN:
1996 cache->dbgCachedBool++;
1997 break;
1998 case XPATH_NUMBER:
1999 cache->dbgCachedNumber++;
2000 break;
2001 case XPATH_STRING:
2002 cache->dbgCachedString++;
2003 break;
2004 case XPATH_POINT:
2005 cache->dbgCachedPoint++;
2006 break;
2007 case XPATH_RANGE:
2008 cache->dbgCachedRange++;
2009 break;
2010 case XPATH_LOCATIONSET:
2011 cache->dbgCachedLocset++;
2012 break;
2013 case XPATH_USERS:
2014 cache->dbgCachedUsers++;
2015 break;
2016 case XPATH_XSLT_TREE:
2017 cache->dbgCachedXSLTTree++;
2018 break;
2019 default:
2020 break;
2021 }
2022
2023 }
2024 }
2025 switch (objType) {
2026 case XPATH_UNDEFINED:
2027 xmlXPathDebugObjCounterUndefined--;
2028 break;
2029 case XPATH_NODESET:
2030 xmlXPathDebugObjCounterNodeset--;
2031 break;
2032 case XPATH_BOOLEAN:
2033 xmlXPathDebugObjCounterBool--;
2034 break;
2035 case XPATH_NUMBER:
2036 xmlXPathDebugObjCounterNumber--;
2037 break;
2038 case XPATH_STRING:
2039 xmlXPathDebugObjCounterString--;
2040 break;
2041 case XPATH_POINT:
2042 xmlXPathDebugObjCounterPoint--;
2043 break;
2044 case XPATH_RANGE:
2045 xmlXPathDebugObjCounterRange--;
2046 break;
2047 case XPATH_LOCATIONSET:
2048 xmlXPathDebugObjCounterLocset--;
2049 break;
2050 case XPATH_USERS:
2051 xmlXPathDebugObjCounterUsers--;
2052 break;
2053 case XPATH_XSLT_TREE:
2054 xmlXPathDebugObjCounterXSLTTree--;
2055 break;
2056 default:
2057 break;
2058 }
2059 xmlXPathDebugObjCounterAll--;
2060 }
2061
2062 /* REVISIT TODO: Make this static when committing */
2063 static void
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)2064 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2065 {
2066 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2067 reqXSLTTree, reqUndefined;
2068 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2069 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2070 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2071 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2072 int leftObjs = xmlXPathDebugObjCounterAll;
2073
2074 reqAll = xmlXPathDebugObjTotalAll;
2075 reqNodeset = xmlXPathDebugObjTotalNodeset;
2076 reqString = xmlXPathDebugObjTotalString;
2077 reqBool = xmlXPathDebugObjTotalBool;
2078 reqNumber = xmlXPathDebugObjTotalNumber;
2079 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2080 reqUndefined = xmlXPathDebugObjTotalUndefined;
2081
2082 printf("# XPath object usage:\n");
2083
2084 if (ctxt != NULL) {
2085 if (ctxt->cache != NULL) {
2086 xmlXPathContextCachePtr cache =
2087 (xmlXPathContextCachePtr) ctxt->cache;
2088
2089 reAll = cache->dbgReusedAll;
2090 reqAll += reAll;
2091 reNodeset = cache->dbgReusedNodeset;
2092 reqNodeset += reNodeset;
2093 reString = cache->dbgReusedString;
2094 reqString += reString;
2095 reBool = cache->dbgReusedBool;
2096 reqBool += reBool;
2097 reNumber = cache->dbgReusedNumber;
2098 reqNumber += reNumber;
2099 reXSLTTree = cache->dbgReusedXSLTTree;
2100 reqXSLTTree += reXSLTTree;
2101 reUndefined = cache->dbgReusedUndefined;
2102 reqUndefined += reUndefined;
2103
2104 caAll = cache->dbgCachedAll;
2105 caBool = cache->dbgCachedBool;
2106 caNodeset = cache->dbgCachedNodeset;
2107 caString = cache->dbgCachedString;
2108 caNumber = cache->dbgCachedNumber;
2109 caXSLTTree = cache->dbgCachedXSLTTree;
2110 caUndefined = cache->dbgCachedUndefined;
2111
2112 if (cache->nodesetObjs)
2113 leftObjs -= cache->nodesetObjs->number;
2114 if (cache->stringObjs)
2115 leftObjs -= cache->stringObjs->number;
2116 if (cache->booleanObjs)
2117 leftObjs -= cache->booleanObjs->number;
2118 if (cache->numberObjs)
2119 leftObjs -= cache->numberObjs->number;
2120 if (cache->miscObjs)
2121 leftObjs -= cache->miscObjs->number;
2122 }
2123 }
2124
2125 printf("# all\n");
2126 printf("# total : %d\n", reqAll);
2127 printf("# left : %d\n", leftObjs);
2128 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2129 printf("# reused : %d\n", reAll);
2130 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2131
2132 printf("# node-sets\n");
2133 printf("# total : %d\n", reqNodeset);
2134 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2135 printf("# reused : %d\n", reNodeset);
2136 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2137
2138 printf("# strings\n");
2139 printf("# total : %d\n", reqString);
2140 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2141 printf("# reused : %d\n", reString);
2142 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2143
2144 printf("# booleans\n");
2145 printf("# total : %d\n", reqBool);
2146 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2147 printf("# reused : %d\n", reBool);
2148 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2149
2150 printf("# numbers\n");
2151 printf("# total : %d\n", reqNumber);
2152 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2153 printf("# reused : %d\n", reNumber);
2154 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2155
2156 printf("# XSLT result tree fragments\n");
2157 printf("# total : %d\n", reqXSLTTree);
2158 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2159 printf("# reused : %d\n", reXSLTTree);
2160 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2161
2162 printf("# undefined\n");
2163 printf("# total : %d\n", reqUndefined);
2164 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2165 printf("# reused : %d\n", reUndefined);
2166 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2167
2168 }
2169
2170 #endif /* XP_DEBUG_OBJ_USAGE */
2171
2172 #endif /* LIBXML_DEBUG_ENABLED */
2173
2174 /************************************************************************
2175 * *
2176 * XPath object caching *
2177 * *
2178 ************************************************************************/
2179
2180 /**
2181 * xmlXPathNewCache:
2182 *
2183 * Create a new object cache
2184 *
2185 * Returns the xmlXPathCache just allocated.
2186 */
2187 static xmlXPathContextCachePtr
xmlXPathNewCache(void)2188 xmlXPathNewCache(void)
2189 {
2190 xmlXPathContextCachePtr ret;
2191
2192 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2193 if (ret == NULL) {
2194 xmlXPathErrMemory(NULL, "creating object cache\n");
2195 return(NULL);
2196 }
2197 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2198 ret->maxNodeset = 100;
2199 ret->maxString = 100;
2200 ret->maxBoolean = 100;
2201 ret->maxNumber = 100;
2202 ret->maxMisc = 100;
2203 return(ret);
2204 }
2205
2206 static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)2207 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2208 {
2209 int i;
2210 xmlXPathObjectPtr obj;
2211
2212 if (list == NULL)
2213 return;
2214
2215 for (i = 0; i < list->number; i++) {
2216 obj = list->items[i];
2217 /*
2218 * Note that it is already assured that we don't need to
2219 * look out for namespace nodes in the node-set.
2220 */
2221 if (obj->nodesetval != NULL) {
2222 if (obj->nodesetval->nodeTab != NULL)
2223 xmlFree(obj->nodesetval->nodeTab);
2224 xmlFree(obj->nodesetval);
2225 }
2226 xmlFree(obj);
2227 #ifdef XP_DEBUG_OBJ_USAGE
2228 xmlXPathDebugObjCounterAll--;
2229 #endif
2230 }
2231 xmlPointerListFree(list);
2232 }
2233
2234 static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)2235 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2236 {
2237 if (cache == NULL)
2238 return;
2239 if (cache->nodesetObjs)
2240 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2241 if (cache->stringObjs)
2242 xmlXPathCacheFreeObjectList(cache->stringObjs);
2243 if (cache->booleanObjs)
2244 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2245 if (cache->numberObjs)
2246 xmlXPathCacheFreeObjectList(cache->numberObjs);
2247 if (cache->miscObjs)
2248 xmlXPathCacheFreeObjectList(cache->miscObjs);
2249 xmlFree(cache);
2250 }
2251
2252 /**
2253 * xmlXPathContextSetCache:
2254 *
2255 * @ctxt: the XPath context
2256 * @active: enables/disables (creates/frees) the cache
2257 * @value: a value with semantics dependant on @options
2258 * @options: options (currently only the value 0 is used)
2259 *
2260 * Creates/frees an object cache on the XPath context.
2261 * If activates XPath objects (xmlXPathObject) will be cached internally
2262 * to be reused.
2263 * @options:
2264 * 0: This will set the XPath object caching:
2265 * @value:
2266 * This will set the maximum number of XPath objects
2267 * to be cached per slot
2268 * There are 5 slots for: node-set, string, number, boolean, and
2269 * misc objects. Use <0 for the default number (100).
2270 * Other values for @options have currently no effect.
2271 *
2272 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2273 */
2274 int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,int active,int value,int options)2275 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2276 int active,
2277 int value,
2278 int options)
2279 {
2280 if (ctxt == NULL)
2281 return(-1);
2282 if (active) {
2283 xmlXPathContextCachePtr cache;
2284
2285 if (ctxt->cache == NULL) {
2286 ctxt->cache = xmlXPathNewCache();
2287 if (ctxt->cache == NULL)
2288 return(-1);
2289 }
2290 cache = (xmlXPathContextCachePtr) ctxt->cache;
2291 if (options == 0) {
2292 if (value < 0)
2293 value = 100;
2294 cache->maxNodeset = value;
2295 cache->maxString = value;
2296 cache->maxNumber = value;
2297 cache->maxBoolean = value;
2298 cache->maxMisc = value;
2299 }
2300 } else if (ctxt->cache != NULL) {
2301 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2302 ctxt->cache = NULL;
2303 }
2304 return(0);
2305 }
2306
2307 /**
2308 * xmlXPathCacheWrapNodeSet:
2309 * @ctxt: the XPath context
2310 * @val: the NodePtr value
2311 *
2312 * This is the cached version of xmlXPathWrapNodeSet().
2313 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2314 *
2315 * Returns the created or reused object.
2316 */
2317 static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt,xmlNodeSetPtr val)2318 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2319 {
2320 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2321 xmlXPathContextCachePtr cache =
2322 (xmlXPathContextCachePtr) ctxt->cache;
2323
2324 if ((cache->miscObjs != NULL) &&
2325 (cache->miscObjs->number != 0))
2326 {
2327 xmlXPathObjectPtr ret;
2328
2329 ret = (xmlXPathObjectPtr)
2330 cache->miscObjs->items[--cache->miscObjs->number];
2331 ret->type = XPATH_NODESET;
2332 ret->nodesetval = val;
2333 #ifdef XP_DEBUG_OBJ_USAGE
2334 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2335 #endif
2336 return(ret);
2337 }
2338 }
2339
2340 return(xmlXPathWrapNodeSet(val));
2341
2342 }
2343
2344 /**
2345 * xmlXPathCacheWrapString:
2346 * @ctxt: the XPath context
2347 * @val: the xmlChar * value
2348 *
2349 * This is the cached version of xmlXPathWrapString().
2350 * Wraps the @val string into an XPath object.
2351 *
2352 * Returns the created or reused object.
2353 */
2354 static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt,xmlChar * val)2355 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2356 {
2357 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2358 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2359
2360 if ((cache->stringObjs != NULL) &&
2361 (cache->stringObjs->number != 0))
2362 {
2363
2364 xmlXPathObjectPtr ret;
2365
2366 ret = (xmlXPathObjectPtr)
2367 cache->stringObjs->items[--cache->stringObjs->number];
2368 ret->type = XPATH_STRING;
2369 ret->stringval = val;
2370 #ifdef XP_DEBUG_OBJ_USAGE
2371 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2372 #endif
2373 return(ret);
2374 } else if ((cache->miscObjs != NULL) &&
2375 (cache->miscObjs->number != 0))
2376 {
2377 xmlXPathObjectPtr ret;
2378 /*
2379 * Fallback to misc-cache.
2380 */
2381 ret = (xmlXPathObjectPtr)
2382 cache->miscObjs->items[--cache->miscObjs->number];
2383
2384 ret->type = XPATH_STRING;
2385 ret->stringval = val;
2386 #ifdef XP_DEBUG_OBJ_USAGE
2387 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2388 #endif
2389 return(ret);
2390 }
2391 }
2392 return(xmlXPathWrapString(val));
2393 }
2394
2395 /**
2396 * xmlXPathCacheNewNodeSet:
2397 * @ctxt: the XPath context
2398 * @val: the NodePtr value
2399 *
2400 * This is the cached version of xmlXPathNewNodeSet().
2401 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2402 * it with the single Node @val
2403 *
2404 * Returns the created or reused object.
2405 */
2406 static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt,xmlNodePtr val)2407 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2408 {
2409 if ((ctxt != NULL) && (ctxt->cache)) {
2410 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2411
2412 if ((cache->nodesetObjs != NULL) &&
2413 (cache->nodesetObjs->number != 0))
2414 {
2415 xmlXPathObjectPtr ret;
2416 /*
2417 * Use the nodset-cache.
2418 */
2419 ret = (xmlXPathObjectPtr)
2420 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2421 ret->type = XPATH_NODESET;
2422 ret->boolval = 0;
2423 if (val) {
2424 if ((ret->nodesetval->nodeMax == 0) ||
2425 (val->type == XML_NAMESPACE_DECL))
2426 {
2427 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2428 } else {
2429 ret->nodesetval->nodeTab[0] = val;
2430 ret->nodesetval->nodeNr = 1;
2431 }
2432 }
2433 #ifdef XP_DEBUG_OBJ_USAGE
2434 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2435 #endif
2436 return(ret);
2437 } else if ((cache->miscObjs != NULL) &&
2438 (cache->miscObjs->number != 0))
2439 {
2440 xmlXPathObjectPtr ret;
2441 /*
2442 * Fallback to misc-cache.
2443 */
2444
2445 ret = (xmlXPathObjectPtr)
2446 cache->miscObjs->items[--cache->miscObjs->number];
2447
2448 ret->type = XPATH_NODESET;
2449 ret->boolval = 0;
2450 ret->nodesetval = xmlXPathNodeSetCreate(val);
2451 if (ret->nodesetval == NULL) {
2452 ctxt->lastError.domain = XML_FROM_XPATH;
2453 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2454 return(NULL);
2455 }
2456 #ifdef XP_DEBUG_OBJ_USAGE
2457 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2458 #endif
2459 return(ret);
2460 }
2461 }
2462 return(xmlXPathNewNodeSet(val));
2463 }
2464
2465 /**
2466 * xmlXPathCacheNewCString:
2467 * @ctxt: the XPath context
2468 * @val: the char * value
2469 *
2470 * This is the cached version of xmlXPathNewCString().
2471 * Acquire an xmlXPathObjectPtr of type string and of value @val
2472 *
2473 * Returns the created or reused object.
2474 */
2475 static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt,const char * val)2476 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2477 {
2478 if ((ctxt != NULL) && (ctxt->cache)) {
2479 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2480
2481 if ((cache->stringObjs != NULL) &&
2482 (cache->stringObjs->number != 0))
2483 {
2484 xmlXPathObjectPtr ret;
2485
2486 ret = (xmlXPathObjectPtr)
2487 cache->stringObjs->items[--cache->stringObjs->number];
2488
2489 ret->type = XPATH_STRING;
2490 ret->stringval = xmlStrdup(BAD_CAST val);
2491 #ifdef XP_DEBUG_OBJ_USAGE
2492 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2493 #endif
2494 return(ret);
2495 } else if ((cache->miscObjs != NULL) &&
2496 (cache->miscObjs->number != 0))
2497 {
2498 xmlXPathObjectPtr ret;
2499
2500 ret = (xmlXPathObjectPtr)
2501 cache->miscObjs->items[--cache->miscObjs->number];
2502
2503 ret->type = XPATH_STRING;
2504 ret->stringval = xmlStrdup(BAD_CAST val);
2505 #ifdef XP_DEBUG_OBJ_USAGE
2506 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2507 #endif
2508 return(ret);
2509 }
2510 }
2511 return(xmlXPathNewCString(val));
2512 }
2513
2514 /**
2515 * xmlXPathCacheNewString:
2516 * @ctxt: the XPath context
2517 * @val: the xmlChar * value
2518 *
2519 * This is the cached version of xmlXPathNewString().
2520 * Acquire an xmlXPathObjectPtr of type string and of value @val
2521 *
2522 * Returns the created or reused object.
2523 */
2524 static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt,const xmlChar * val)2525 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2526 {
2527 if ((ctxt != NULL) && (ctxt->cache)) {
2528 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2529
2530 if ((cache->stringObjs != NULL) &&
2531 (cache->stringObjs->number != 0))
2532 {
2533 xmlXPathObjectPtr ret;
2534
2535 ret = (xmlXPathObjectPtr)
2536 cache->stringObjs->items[--cache->stringObjs->number];
2537 ret->type = XPATH_STRING;
2538 if (val != NULL)
2539 ret->stringval = xmlStrdup(val);
2540 else
2541 ret->stringval = xmlStrdup((const xmlChar *)"");
2542 #ifdef XP_DEBUG_OBJ_USAGE
2543 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2544 #endif
2545 return(ret);
2546 } else if ((cache->miscObjs != NULL) &&
2547 (cache->miscObjs->number != 0))
2548 {
2549 xmlXPathObjectPtr ret;
2550
2551 ret = (xmlXPathObjectPtr)
2552 cache->miscObjs->items[--cache->miscObjs->number];
2553
2554 ret->type = XPATH_STRING;
2555 if (val != NULL)
2556 ret->stringval = xmlStrdup(val);
2557 else
2558 ret->stringval = xmlStrdup((const xmlChar *)"");
2559 #ifdef XP_DEBUG_OBJ_USAGE
2560 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2561 #endif
2562 return(ret);
2563 }
2564 }
2565 return(xmlXPathNewString(val));
2566 }
2567
2568 /**
2569 * xmlXPathCacheNewBoolean:
2570 * @ctxt: the XPath context
2571 * @val: the boolean value
2572 *
2573 * This is the cached version of xmlXPathNewBoolean().
2574 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2575 *
2576 * Returns the created or reused object.
2577 */
2578 static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt,int val)2579 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2580 {
2581 if ((ctxt != NULL) && (ctxt->cache)) {
2582 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2583
2584 if ((cache->booleanObjs != NULL) &&
2585 (cache->booleanObjs->number != 0))
2586 {
2587 xmlXPathObjectPtr ret;
2588
2589 ret = (xmlXPathObjectPtr)
2590 cache->booleanObjs->items[--cache->booleanObjs->number];
2591 ret->type = XPATH_BOOLEAN;
2592 ret->boolval = (val != 0);
2593 #ifdef XP_DEBUG_OBJ_USAGE
2594 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2595 #endif
2596 return(ret);
2597 } else if ((cache->miscObjs != NULL) &&
2598 (cache->miscObjs->number != 0))
2599 {
2600 xmlXPathObjectPtr ret;
2601
2602 ret = (xmlXPathObjectPtr)
2603 cache->miscObjs->items[--cache->miscObjs->number];
2604
2605 ret->type = XPATH_BOOLEAN;
2606 ret->boolval = (val != 0);
2607 #ifdef XP_DEBUG_OBJ_USAGE
2608 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2609 #endif
2610 return(ret);
2611 }
2612 }
2613 return(xmlXPathNewBoolean(val));
2614 }
2615
2616 /**
2617 * xmlXPathCacheNewFloat:
2618 * @ctxt: the XPath context
2619 * @val: the double value
2620 *
2621 * This is the cached version of xmlXPathNewFloat().
2622 * Acquires an xmlXPathObjectPtr of type double and of value @val
2623 *
2624 * Returns the created or reused object.
2625 */
2626 static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt,double val)2627 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2628 {
2629 if ((ctxt != NULL) && (ctxt->cache)) {
2630 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2631
2632 if ((cache->numberObjs != NULL) &&
2633 (cache->numberObjs->number != 0))
2634 {
2635 xmlXPathObjectPtr ret;
2636
2637 ret = (xmlXPathObjectPtr)
2638 cache->numberObjs->items[--cache->numberObjs->number];
2639 ret->type = XPATH_NUMBER;
2640 ret->floatval = val;
2641 #ifdef XP_DEBUG_OBJ_USAGE
2642 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2643 #endif
2644 return(ret);
2645 } else if ((cache->miscObjs != NULL) &&
2646 (cache->miscObjs->number != 0))
2647 {
2648 xmlXPathObjectPtr ret;
2649
2650 ret = (xmlXPathObjectPtr)
2651 cache->miscObjs->items[--cache->miscObjs->number];
2652
2653 ret->type = XPATH_NUMBER;
2654 ret->floatval = val;
2655 #ifdef XP_DEBUG_OBJ_USAGE
2656 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2657 #endif
2658 return(ret);
2659 }
2660 }
2661 return(xmlXPathNewFloat(val));
2662 }
2663
2664 /**
2665 * xmlXPathCacheConvertString:
2666 * @ctxt: the XPath context
2667 * @val: an XPath object
2668 *
2669 * This is the cached version of xmlXPathConvertString().
2670 * Converts an existing object to its string() equivalent
2671 *
2672 * Returns a created or reused object, the old one is freed (cached)
2673 * (or the operation is done directly on @val)
2674 */
2675
2676 static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2677 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2678 xmlChar *res = NULL;
2679
2680 if (val == NULL)
2681 return(xmlXPathCacheNewCString(ctxt, ""));
2682
2683 switch (val->type) {
2684 case XPATH_UNDEFINED:
2685 #ifdef DEBUG_EXPR
2686 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2687 #endif
2688 break;
2689 case XPATH_NODESET:
2690 case XPATH_XSLT_TREE:
2691 res = xmlXPathCastNodeSetToString(val->nodesetval);
2692 break;
2693 case XPATH_STRING:
2694 return(val);
2695 case XPATH_BOOLEAN:
2696 res = xmlXPathCastBooleanToString(val->boolval);
2697 break;
2698 case XPATH_NUMBER:
2699 res = xmlXPathCastNumberToString(val->floatval);
2700 break;
2701 case XPATH_USERS:
2702 case XPATH_POINT:
2703 case XPATH_RANGE:
2704 case XPATH_LOCATIONSET:
2705 TODO;
2706 break;
2707 }
2708 xmlXPathReleaseObject(ctxt, val);
2709 if (res == NULL)
2710 return(xmlXPathCacheNewCString(ctxt, ""));
2711 return(xmlXPathCacheWrapString(ctxt, res));
2712 }
2713
2714 /**
2715 * xmlXPathCacheObjectCopy:
2716 * @ctxt: the XPath context
2717 * @val: the original object
2718 *
2719 * This is the cached version of xmlXPathObjectCopy().
2720 * Acquire a copy of a given object
2721 *
2722 * Returns a created or reused created object.
2723 */
2724 static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2725 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2726 {
2727 if (val == NULL)
2728 return(NULL);
2729
2730 if (XP_HAS_CACHE(ctxt)) {
2731 switch (val->type) {
2732 case XPATH_NODESET:
2733 return(xmlXPathCacheWrapNodeSet(ctxt,
2734 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2735 case XPATH_STRING:
2736 return(xmlXPathCacheNewString(ctxt, val->stringval));
2737 case XPATH_BOOLEAN:
2738 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2739 case XPATH_NUMBER:
2740 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2741 default:
2742 break;
2743 }
2744 }
2745 return(xmlXPathObjectCopy(val));
2746 }
2747
2748 /**
2749 * xmlXPathCacheConvertBoolean:
2750 * @ctxt: the XPath context
2751 * @val: an XPath object
2752 *
2753 * This is the cached version of xmlXPathConvertBoolean().
2754 * Converts an existing object to its boolean() equivalent
2755 *
2756 * Returns a created or reused object, the old one is freed (or the operation
2757 * is done directly on @val)
2758 */
2759 static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2760 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2761 xmlXPathObjectPtr ret;
2762
2763 if (val == NULL)
2764 return(xmlXPathCacheNewBoolean(ctxt, 0));
2765 if (val->type == XPATH_BOOLEAN)
2766 return(val);
2767 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2768 xmlXPathReleaseObject(ctxt, val);
2769 return(ret);
2770 }
2771
2772 /**
2773 * xmlXPathCacheConvertNumber:
2774 * @ctxt: the XPath context
2775 * @val: an XPath object
2776 *
2777 * This is the cached version of xmlXPathConvertNumber().
2778 * Converts an existing object to its number() equivalent
2779 *
2780 * Returns a created or reused object, the old one is freed (or the operation
2781 * is done directly on @val)
2782 */
2783 static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt,xmlXPathObjectPtr val)2784 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2785 xmlXPathObjectPtr ret;
2786
2787 if (val == NULL)
2788 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2789 if (val->type == XPATH_NUMBER)
2790 return(val);
2791 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2792 xmlXPathReleaseObject(ctxt, val);
2793 return(ret);
2794 }
2795
2796 /************************************************************************
2797 * *
2798 * Parser stacks related functions and macros *
2799 * *
2800 ************************************************************************/
2801
2802 /**
2803 * xmlXPathSetFrame:
2804 * @ctxt: an XPath parser context
2805 *
2806 * Set the callee evaluation frame
2807 *
2808 * Returns the previous frame value to be restored once done
2809 */
2810 static int
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt)2811 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2812 int ret;
2813
2814 if (ctxt == NULL)
2815 return(0);
2816 ret = ctxt->valueFrame;
2817 ctxt->valueFrame = ctxt->valueNr;
2818 return(ret);
2819 }
2820
2821 /**
2822 * xmlXPathPopFrame:
2823 * @ctxt: an XPath parser context
2824 * @frame: the previous frame value
2825 *
2826 * Remove the callee evaluation frame
2827 */
2828 static void
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt,int frame)2829 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2830 if (ctxt == NULL)
2831 return;
2832 if (ctxt->valueNr < ctxt->valueFrame) {
2833 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2834 }
2835 ctxt->valueFrame = frame;
2836 }
2837
2838 /**
2839 * valuePop:
2840 * @ctxt: an XPath evaluation context
2841 *
2842 * Pops the top XPath object from the value stack
2843 *
2844 * Returns the XPath object just removed
2845 */
2846 xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)2847 valuePop(xmlXPathParserContextPtr ctxt)
2848 {
2849 xmlXPathObjectPtr ret;
2850
2851 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2852 return (NULL);
2853
2854 if (ctxt->valueNr <= ctxt->valueFrame) {
2855 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2856 return (NULL);
2857 }
2858
2859 ctxt->valueNr--;
2860 if (ctxt->valueNr > 0)
2861 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2862 else
2863 ctxt->value = NULL;
2864 ret = ctxt->valueTab[ctxt->valueNr];
2865 ctxt->valueTab[ctxt->valueNr] = NULL;
2866 return (ret);
2867 }
2868 /**
2869 * valuePush:
2870 * @ctxt: an XPath evaluation context
2871 * @value: the XPath object
2872 *
2873 * Pushes a new XPath object on top of the value stack
2874 *
2875 * returns the number of items on the value stack
2876 */
2877 int
valuePush(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr value)2878 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2879 {
2880 if ((ctxt == NULL) || (value == NULL)) return(-1);
2881 if (ctxt->valueNr >= ctxt->valueMax) {
2882 xmlXPathObjectPtr *tmp;
2883
2884 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2885 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2886 ctxt->error = XPATH_MEMORY_ERROR;
2887 return (0);
2888 }
2889 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2890 2 * ctxt->valueMax *
2891 sizeof(ctxt->valueTab[0]));
2892 if (tmp == NULL) {
2893 xmlXPathErrMemory(NULL, "pushing value\n");
2894 ctxt->error = XPATH_MEMORY_ERROR;
2895 return (0);
2896 }
2897 ctxt->valueMax *= 2;
2898 ctxt->valueTab = tmp;
2899 }
2900 ctxt->valueTab[ctxt->valueNr] = value;
2901 ctxt->value = value;
2902 return (ctxt->valueNr++);
2903 }
2904
2905 /**
2906 * xmlXPathPopBoolean:
2907 * @ctxt: an XPath parser context
2908 *
2909 * Pops a boolean from the stack, handling conversion if needed.
2910 * Check error with #xmlXPathCheckError.
2911 *
2912 * Returns the boolean
2913 */
2914 int
xmlXPathPopBoolean(xmlXPathParserContextPtr ctxt)2915 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2916 xmlXPathObjectPtr obj;
2917 int ret;
2918
2919 obj = valuePop(ctxt);
2920 if (obj == NULL) {
2921 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2922 return(0);
2923 }
2924 if (obj->type != XPATH_BOOLEAN)
2925 ret = xmlXPathCastToBoolean(obj);
2926 else
2927 ret = obj->boolval;
2928 xmlXPathReleaseObject(ctxt->context, obj);
2929 return(ret);
2930 }
2931
2932 /**
2933 * xmlXPathPopNumber:
2934 * @ctxt: an XPath parser context
2935 *
2936 * Pops a number from the stack, handling conversion if needed.
2937 * Check error with #xmlXPathCheckError.
2938 *
2939 * Returns the number
2940 */
2941 double
xmlXPathPopNumber(xmlXPathParserContextPtr ctxt)2942 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2943 xmlXPathObjectPtr obj;
2944 double ret;
2945
2946 obj = valuePop(ctxt);
2947 if (obj == NULL) {
2948 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2949 return(0);
2950 }
2951 if (obj->type != XPATH_NUMBER)
2952 ret = xmlXPathCastToNumber(obj);
2953 else
2954 ret = obj->floatval;
2955 xmlXPathReleaseObject(ctxt->context, obj);
2956 return(ret);
2957 }
2958
2959 /**
2960 * xmlXPathPopString:
2961 * @ctxt: an XPath parser context
2962 *
2963 * Pops a string from the stack, handling conversion if needed.
2964 * Check error with #xmlXPathCheckError.
2965 *
2966 * Returns the string
2967 */
2968 xmlChar *
xmlXPathPopString(xmlXPathParserContextPtr ctxt)2969 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2970 xmlXPathObjectPtr obj;
2971 xmlChar * ret;
2972
2973 obj = valuePop(ctxt);
2974 if (obj == NULL) {
2975 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2976 return(NULL);
2977 }
2978 ret = xmlXPathCastToString(obj); /* this does required strdup */
2979 /* TODO: needs refactoring somewhere else */
2980 if (obj->stringval == ret)
2981 obj->stringval = NULL;
2982 xmlXPathReleaseObject(ctxt->context, obj);
2983 return(ret);
2984 }
2985
2986 /**
2987 * xmlXPathPopNodeSet:
2988 * @ctxt: an XPath parser context
2989 *
2990 * Pops a node-set from the stack, handling conversion if needed.
2991 * Check error with #xmlXPathCheckError.
2992 *
2993 * Returns the node-set
2994 */
2995 xmlNodeSetPtr
xmlXPathPopNodeSet(xmlXPathParserContextPtr ctxt)2996 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2997 xmlXPathObjectPtr obj;
2998 xmlNodeSetPtr ret;
2999
3000 if (ctxt == NULL) return(NULL);
3001 if (ctxt->value == NULL) {
3002 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3003 return(NULL);
3004 }
3005 if (!xmlXPathStackIsNodeSet(ctxt)) {
3006 xmlXPathSetTypeError(ctxt);
3007 return(NULL);
3008 }
3009 obj = valuePop(ctxt);
3010 ret = obj->nodesetval;
3011 #if 0
3012 /* to fix memory leak of not clearing obj->user */
3013 if (obj->boolval && obj->user != NULL)
3014 xmlFreeNodeList((xmlNodePtr) obj->user);
3015 #endif
3016 obj->nodesetval = NULL;
3017 xmlXPathReleaseObject(ctxt->context, obj);
3018 return(ret);
3019 }
3020
3021 /**
3022 * xmlXPathPopExternal:
3023 * @ctxt: an XPath parser context
3024 *
3025 * Pops an external object from the stack, handling conversion if needed.
3026 * Check error with #xmlXPathCheckError.
3027 *
3028 * Returns the object
3029 */
3030 void *
xmlXPathPopExternal(xmlXPathParserContextPtr ctxt)3031 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3032 xmlXPathObjectPtr obj;
3033 void * ret;
3034
3035 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3036 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3037 return(NULL);
3038 }
3039 if (ctxt->value->type != XPATH_USERS) {
3040 xmlXPathSetTypeError(ctxt);
3041 return(NULL);
3042 }
3043 obj = valuePop(ctxt);
3044 ret = obj->user;
3045 obj->user = NULL;
3046 xmlXPathReleaseObject(ctxt->context, obj);
3047 return(ret);
3048 }
3049
3050 /*
3051 * Macros for accessing the content. Those should be used only by the parser,
3052 * and not exported.
3053 *
3054 * Dirty macros, i.e. one need to make assumption on the context to use them
3055 *
3056 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3057 * CUR returns the current xmlChar value, i.e. a 8 bit value
3058 * in ISO-Latin or UTF-8.
3059 * This should be used internally by the parser
3060 * only to compare to ASCII values otherwise it would break when
3061 * running with UTF-8 encoding.
3062 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3063 * to compare on ASCII based substring.
3064 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3065 * strings within the parser.
3066 * CURRENT Returns the current char value, with the full decoding of
3067 * UTF-8 if we are using this mode. It returns an int.
3068 * NEXT Skip to the next character, this does the proper decoding
3069 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3070 * It returns the pointer to the current xmlChar.
3071 */
3072
3073 #define CUR (*ctxt->cur)
3074 #define SKIP(val) ctxt->cur += (val)
3075 #define NXT(val) ctxt->cur[(val)]
3076 #define CUR_PTR ctxt->cur
3077 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3078
3079 #define COPY_BUF(l,b,i,v) \
3080 if (l == 1) b[i++] = (xmlChar) v; \
3081 else i += xmlCopyChar(l,&b[i],v)
3082
3083 #define NEXTL(l) ctxt->cur += l
3084
3085 #define SKIP_BLANKS \
3086 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3087
3088 #define CURRENT (*ctxt->cur)
3089 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3090
3091
3092 #ifndef DBL_DIG
3093 #define DBL_DIG 16
3094 #endif
3095 #ifndef DBL_EPSILON
3096 #define DBL_EPSILON 1E-9
3097 #endif
3098
3099 #define UPPER_DOUBLE 1E9
3100 #define LOWER_DOUBLE 1E-5
3101 #define LOWER_DOUBLE_EXP 5
3102
3103 #define INTEGER_DIGITS DBL_DIG
3104 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3105 #define EXPONENT_DIGITS (3 + 2)
3106
3107 /**
3108 * xmlXPathFormatNumber:
3109 * @number: number to format
3110 * @buffer: output buffer
3111 * @buffersize: size of output buffer
3112 *
3113 * Convert the number into a string representation.
3114 */
3115 static void
xmlXPathFormatNumber(double number,char buffer[],int buffersize)3116 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3117 {
3118 switch (xmlXPathIsInf(number)) {
3119 case 1:
3120 if (buffersize > (int)sizeof("Infinity"))
3121 snprintf(buffer, buffersize, "Infinity");
3122 break;
3123 case -1:
3124 if (buffersize > (int)sizeof("-Infinity"))
3125 snprintf(buffer, buffersize, "-Infinity");
3126 break;
3127 default:
3128 if (xmlXPathIsNaN(number)) {
3129 if (buffersize > (int)sizeof("NaN"))
3130 snprintf(buffer, buffersize, "NaN");
3131 } else if (number == 0) {
3132 /* Omit sign for negative zero. */
3133 snprintf(buffer, buffersize, "0");
3134 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3135 (number == (int) number)) {
3136 char work[30];
3137 char *ptr, *cur;
3138 int value = (int) number;
3139
3140 ptr = &buffer[0];
3141 if (value == 0) {
3142 *ptr++ = '0';
3143 } else {
3144 snprintf(work, 29, "%d", value);
3145 cur = &work[0];
3146 while ((*cur) && (ptr - buffer < buffersize)) {
3147 *ptr++ = *cur++;
3148 }
3149 }
3150 if (ptr - buffer < buffersize) {
3151 *ptr = 0;
3152 } else if (buffersize > 0) {
3153 ptr--;
3154 *ptr = 0;
3155 }
3156 } else {
3157 /*
3158 For the dimension of work,
3159 DBL_DIG is number of significant digits
3160 EXPONENT is only needed for "scientific notation"
3161 3 is sign, decimal point, and terminating zero
3162 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3163 Note that this dimension is slightly (a few characters)
3164 larger than actually necessary.
3165 */
3166 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3167 int integer_place, fraction_place;
3168 char *ptr;
3169 char *after_fraction;
3170 double absolute_value;
3171 int size;
3172
3173 absolute_value = fabs(number);
3174
3175 /*
3176 * First choose format - scientific or regular floating point.
3177 * In either case, result is in work, and after_fraction points
3178 * just past the fractional part.
3179 */
3180 if ( ((absolute_value > UPPER_DOUBLE) ||
3181 (absolute_value < LOWER_DOUBLE)) &&
3182 (absolute_value != 0.0) ) {
3183 /* Use scientific notation */
3184 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3185 fraction_place = DBL_DIG - 1;
3186 size = snprintf(work, sizeof(work),"%*.*e",
3187 integer_place, fraction_place, number);
3188 while ((size > 0) && (work[size] != 'e')) size--;
3189
3190 }
3191 else {
3192 /* Use regular notation */
3193 if (absolute_value > 0.0) {
3194 integer_place = (int)log10(absolute_value);
3195 if (integer_place > 0)
3196 fraction_place = DBL_DIG - integer_place - 1;
3197 else
3198 fraction_place = DBL_DIG - integer_place;
3199 } else {
3200 fraction_place = 1;
3201 }
3202 size = snprintf(work, sizeof(work), "%0.*f",
3203 fraction_place, number);
3204 }
3205
3206 /* Remove leading spaces sometimes inserted by snprintf */
3207 while (work[0] == ' ') {
3208 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3209 size--;
3210 }
3211
3212 /* Remove fractional trailing zeroes */
3213 after_fraction = work + size;
3214 ptr = after_fraction;
3215 while (*(--ptr) == '0')
3216 ;
3217 if (*ptr != '.')
3218 ptr++;
3219 while ((*ptr++ = *after_fraction++) != 0);
3220
3221 /* Finally copy result back to caller */
3222 size = strlen(work) + 1;
3223 if (size > buffersize) {
3224 work[buffersize - 1] = 0;
3225 size = buffersize;
3226 }
3227 memmove(buffer, work, size);
3228 }
3229 break;
3230 }
3231 }
3232
3233
3234 /************************************************************************
3235 * *
3236 * Routines to handle NodeSets *
3237 * *
3238 ************************************************************************/
3239
3240 /**
3241 * xmlXPathOrderDocElems:
3242 * @doc: an input document
3243 *
3244 * Call this routine to speed up XPath computation on static documents.
3245 * This stamps all the element nodes with the document order
3246 * Like for line information, the order is kept in the element->content
3247 * field, the value stored is actually - the node number (starting at -1)
3248 * to be able to differentiate from line numbers.
3249 *
3250 * Returns the number of elements found in the document or -1 in case
3251 * of error.
3252 */
3253 long
xmlXPathOrderDocElems(xmlDocPtr doc)3254 xmlXPathOrderDocElems(xmlDocPtr doc) {
3255 ptrdiff_t count = 0;
3256 xmlNodePtr cur;
3257
3258 if (doc == NULL)
3259 return(-1);
3260 cur = doc->children;
3261 while (cur != NULL) {
3262 if (cur->type == XML_ELEMENT_NODE) {
3263 cur->content = (void *) (-(++count));
3264 if (cur->children != NULL) {
3265 cur = cur->children;
3266 continue;
3267 }
3268 }
3269 if (cur->next != NULL) {
3270 cur = cur->next;
3271 continue;
3272 }
3273 do {
3274 cur = cur->parent;
3275 if (cur == NULL)
3276 break;
3277 if (cur == (xmlNodePtr) doc) {
3278 cur = NULL;
3279 break;
3280 }
3281 if (cur->next != NULL) {
3282 cur = cur->next;
3283 break;
3284 }
3285 } while (cur != NULL);
3286 }
3287 return((long) count);
3288 }
3289
3290 /**
3291 * xmlXPathCmpNodes:
3292 * @node1: the first node
3293 * @node2: the second node
3294 *
3295 * Compare two nodes w.r.t document order
3296 *
3297 * Returns -2 in case of error 1 if first point < second point, 0 if
3298 * it's the same node, -1 otherwise
3299 */
3300 int
xmlXPathCmpNodes(xmlNodePtr node1,xmlNodePtr node2)3301 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3302 int depth1, depth2;
3303 int attr1 = 0, attr2 = 0;
3304 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3305 xmlNodePtr cur, root;
3306
3307 if ((node1 == NULL) || (node2 == NULL))
3308 return(-2);
3309 /*
3310 * a couple of optimizations which will avoid computations in most cases
3311 */
3312 if (node1 == node2) /* trivial case */
3313 return(0);
3314 if (node1->type == XML_ATTRIBUTE_NODE) {
3315 attr1 = 1;
3316 attrNode1 = node1;
3317 node1 = node1->parent;
3318 }
3319 if (node2->type == XML_ATTRIBUTE_NODE) {
3320 attr2 = 1;
3321 attrNode2 = node2;
3322 node2 = node2->parent;
3323 }
3324 if (node1 == node2) {
3325 if (attr1 == attr2) {
3326 /* not required, but we keep attributes in order */
3327 if (attr1 != 0) {
3328 cur = attrNode2->prev;
3329 while (cur != NULL) {
3330 if (cur == attrNode1)
3331 return (1);
3332 cur = cur->prev;
3333 }
3334 return (-1);
3335 }
3336 return(0);
3337 }
3338 if (attr2 == 1)
3339 return(1);
3340 return(-1);
3341 }
3342 if ((node1->type == XML_NAMESPACE_DECL) ||
3343 (node2->type == XML_NAMESPACE_DECL))
3344 return(1);
3345 if (node1 == node2->prev)
3346 return(1);
3347 if (node1 == node2->next)
3348 return(-1);
3349
3350 /*
3351 * Speedup using document order if availble.
3352 */
3353 if ((node1->type == XML_ELEMENT_NODE) &&
3354 (node2->type == XML_ELEMENT_NODE) &&
3355 (0 > (ptrdiff_t) node1->content) &&
3356 (0 > (ptrdiff_t) node2->content) &&
3357 (node1->doc == node2->doc)) {
3358 ptrdiff_t l1, l2;
3359
3360 l1 = -((ptrdiff_t) node1->content);
3361 l2 = -((ptrdiff_t) node2->content);
3362 if (l1 < l2)
3363 return(1);
3364 if (l1 > l2)
3365 return(-1);
3366 }
3367
3368 /*
3369 * compute depth to root
3370 */
3371 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3372 if (cur->parent == node1)
3373 return(1);
3374 depth2++;
3375 }
3376 root = cur;
3377 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3378 if (cur->parent == node2)
3379 return(-1);
3380 depth1++;
3381 }
3382 /*
3383 * Distinct document (or distinct entities :-( ) case.
3384 */
3385 if (root != cur) {
3386 return(-2);
3387 }
3388 /*
3389 * get the nearest common ancestor.
3390 */
3391 while (depth1 > depth2) {
3392 depth1--;
3393 node1 = node1->parent;
3394 }
3395 while (depth2 > depth1) {
3396 depth2--;
3397 node2 = node2->parent;
3398 }
3399 while (node1->parent != node2->parent) {
3400 node1 = node1->parent;
3401 node2 = node2->parent;
3402 /* should not happen but just in case ... */
3403 if ((node1 == NULL) || (node2 == NULL))
3404 return(-2);
3405 }
3406 /*
3407 * Find who's first.
3408 */
3409 if (node1 == node2->prev)
3410 return(1);
3411 if (node1 == node2->next)
3412 return(-1);
3413 /*
3414 * Speedup using document order if availble.
3415 */
3416 if ((node1->type == XML_ELEMENT_NODE) &&
3417 (node2->type == XML_ELEMENT_NODE) &&
3418 (0 > (ptrdiff_t) node1->content) &&
3419 (0 > (ptrdiff_t) node2->content) &&
3420 (node1->doc == node2->doc)) {
3421 ptrdiff_t l1, l2;
3422
3423 l1 = -((ptrdiff_t) node1->content);
3424 l2 = -((ptrdiff_t) node2->content);
3425 if (l1 < l2)
3426 return(1);
3427 if (l1 > l2)
3428 return(-1);
3429 }
3430
3431 for (cur = node1->next;cur != NULL;cur = cur->next)
3432 if (cur == node2)
3433 return(1);
3434 return(-1); /* assume there is no sibling list corruption */
3435 }
3436
3437 /**
3438 * xmlXPathNodeSetSort:
3439 * @set: the node set
3440 *
3441 * Sort the node set in document order
3442 */
3443 void
xmlXPathNodeSetSort(xmlNodeSetPtr set)3444 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3445 #ifndef WITH_TIM_SORT
3446 int i, j, incr, len;
3447 xmlNodePtr tmp;
3448 #endif
3449
3450 if (set == NULL)
3451 return;
3452
3453 #ifndef WITH_TIM_SORT
3454 /*
3455 * Use the old Shell's sort implementation to sort the node-set
3456 * Timsort ought to be quite faster
3457 */
3458 len = set->nodeNr;
3459 for (incr = len / 2; incr > 0; incr /= 2) {
3460 for (i = incr; i < len; i++) {
3461 j = i - incr;
3462 while (j >= 0) {
3463 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3464 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3465 set->nodeTab[j + incr]) == -1)
3466 #else
3467 if (xmlXPathCmpNodes(set->nodeTab[j],
3468 set->nodeTab[j + incr]) == -1)
3469 #endif
3470 {
3471 tmp = set->nodeTab[j];
3472 set->nodeTab[j] = set->nodeTab[j + incr];
3473 set->nodeTab[j + incr] = tmp;
3474 j -= incr;
3475 } else
3476 break;
3477 }
3478 }
3479 }
3480 #else /* WITH_TIM_SORT */
3481 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3482 #endif /* WITH_TIM_SORT */
3483 }
3484
3485 #define XML_NODESET_DEFAULT 10
3486 /**
3487 * xmlXPathNodeSetDupNs:
3488 * @node: the parent node of the namespace XPath node
3489 * @ns: the libxml namespace declaration node.
3490 *
3491 * Namespace node in libxml don't match the XPath semantic. In a node set
3492 * the namespace nodes are duplicated and the next pointer is set to the
3493 * parent node in the XPath semantic.
3494 *
3495 * Returns the newly created object.
3496 */
3497 static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node,xmlNsPtr ns)3498 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3499 xmlNsPtr cur;
3500
3501 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3502 return(NULL);
3503 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3504 return((xmlNodePtr) ns);
3505
3506 /*
3507 * Allocate a new Namespace and fill the fields.
3508 */
3509 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3510 if (cur == NULL) {
3511 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3512 return(NULL);
3513 }
3514 memset(cur, 0, sizeof(xmlNs));
3515 cur->type = XML_NAMESPACE_DECL;
3516 if (ns->href != NULL)
3517 cur->href = xmlStrdup(ns->href);
3518 if (ns->prefix != NULL)
3519 cur->prefix = xmlStrdup(ns->prefix);
3520 cur->next = (xmlNsPtr) node;
3521 return((xmlNodePtr) cur);
3522 }
3523
3524 /**
3525 * xmlXPathNodeSetFreeNs:
3526 * @ns: the XPath namespace node found in a nodeset.
3527 *
3528 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3529 * the namespace nodes are duplicated and the next pointer is set to the
3530 * parent node in the XPath semantic. Check if such a node needs to be freed
3531 */
3532 void
xmlXPathNodeSetFreeNs(xmlNsPtr ns)3533 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3534 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3535 return;
3536
3537 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3538 if (ns->href != NULL)
3539 xmlFree((xmlChar *)ns->href);
3540 if (ns->prefix != NULL)
3541 xmlFree((xmlChar *)ns->prefix);
3542 xmlFree(ns);
3543 }
3544 }
3545
3546 /**
3547 * xmlXPathNodeSetCreate:
3548 * @val: an initial xmlNodePtr, or NULL
3549 *
3550 * Create a new xmlNodeSetPtr of type double and of value @val
3551 *
3552 * Returns the newly created object.
3553 */
3554 xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val)3555 xmlXPathNodeSetCreate(xmlNodePtr val) {
3556 xmlNodeSetPtr ret;
3557
3558 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3559 if (ret == NULL) {
3560 xmlXPathErrMemory(NULL, "creating nodeset\n");
3561 return(NULL);
3562 }
3563 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3564 if (val != NULL) {
3565 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3566 sizeof(xmlNodePtr));
3567 if (ret->nodeTab == NULL) {
3568 xmlXPathErrMemory(NULL, "creating nodeset\n");
3569 xmlFree(ret);
3570 return(NULL);
3571 }
3572 memset(ret->nodeTab, 0 ,
3573 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574 ret->nodeMax = XML_NODESET_DEFAULT;
3575 if (val->type == XML_NAMESPACE_DECL) {
3576 xmlNsPtr ns = (xmlNsPtr) val;
3577
3578 ret->nodeTab[ret->nodeNr++] =
3579 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3580 } else
3581 ret->nodeTab[ret->nodeNr++] = val;
3582 }
3583 return(ret);
3584 }
3585
3586 /**
3587 * xmlXPathNodeSetCreateSize:
3588 * @size: the initial size of the set
3589 *
3590 * Create a new xmlNodeSetPtr of type double and of value @val
3591 *
3592 * Returns the newly created object.
3593 */
3594 static xmlNodeSetPtr
xmlXPathNodeSetCreateSize(int size)3595 xmlXPathNodeSetCreateSize(int size) {
3596 xmlNodeSetPtr ret;
3597
3598 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3599 if (ret == NULL) {
3600 xmlXPathErrMemory(NULL, "creating nodeset\n");
3601 return(NULL);
3602 }
3603 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3604 if (size < XML_NODESET_DEFAULT)
3605 size = XML_NODESET_DEFAULT;
3606 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3607 if (ret->nodeTab == NULL) {
3608 xmlXPathErrMemory(NULL, "creating nodeset\n");
3609 xmlFree(ret);
3610 return(NULL);
3611 }
3612 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3613 ret->nodeMax = size;
3614 return(ret);
3615 }
3616
3617 /**
3618 * xmlXPathNodeSetContains:
3619 * @cur: the node-set
3620 * @val: the node
3621 *
3622 * checks whether @cur contains @val
3623 *
3624 * Returns true (1) if @cur contains @val, false (0) otherwise
3625 */
3626 int
xmlXPathNodeSetContains(xmlNodeSetPtr cur,xmlNodePtr val)3627 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3628 int i;
3629
3630 if ((cur == NULL) || (val == NULL)) return(0);
3631 if (val->type == XML_NAMESPACE_DECL) {
3632 for (i = 0; i < cur->nodeNr; i++) {
3633 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3634 xmlNsPtr ns1, ns2;
3635
3636 ns1 = (xmlNsPtr) val;
3637 ns2 = (xmlNsPtr) cur->nodeTab[i];
3638 if (ns1 == ns2)
3639 return(1);
3640 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3641 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3642 return(1);
3643 }
3644 }
3645 } else {
3646 for (i = 0; i < cur->nodeNr; i++) {
3647 if (cur->nodeTab[i] == val)
3648 return(1);
3649 }
3650 }
3651 return(0);
3652 }
3653
3654 /**
3655 * xmlXPathNodeSetAddNs:
3656 * @cur: the initial node set
3657 * @node: the hosting node
3658 * @ns: a the namespace node
3659 *
3660 * add a new namespace node to an existing NodeSet
3661 *
3662 * Returns 0 in case of success and -1 in case of error
3663 */
3664 int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur,xmlNodePtr node,xmlNsPtr ns)3665 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3666 int i;
3667
3668
3669 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3670 (ns->type != XML_NAMESPACE_DECL) ||
3671 (node->type != XML_ELEMENT_NODE))
3672 return(-1);
3673
3674 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3675 /*
3676 * prevent duplicates
3677 */
3678 for (i = 0;i < cur->nodeNr;i++) {
3679 if ((cur->nodeTab[i] != NULL) &&
3680 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3681 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3682 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3683 return(0);
3684 }
3685
3686 /*
3687 * grow the nodeTab if needed
3688 */
3689 if (cur->nodeMax == 0) {
3690 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3691 sizeof(xmlNodePtr));
3692 if (cur->nodeTab == NULL) {
3693 xmlXPathErrMemory(NULL, "growing nodeset\n");
3694 return(-1);
3695 }
3696 memset(cur->nodeTab, 0 ,
3697 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3698 cur->nodeMax = XML_NODESET_DEFAULT;
3699 } else if (cur->nodeNr == cur->nodeMax) {
3700 xmlNodePtr *temp;
3701
3702 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3703 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3704 return(-1);
3705 }
3706 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3707 sizeof(xmlNodePtr));
3708 if (temp == NULL) {
3709 xmlXPathErrMemory(NULL, "growing nodeset\n");
3710 return(-1);
3711 }
3712 cur->nodeMax *= 2;
3713 cur->nodeTab = temp;
3714 }
3715 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3716 return(0);
3717 }
3718
3719 /**
3720 * xmlXPathNodeSetAdd:
3721 * @cur: the initial node set
3722 * @val: a new xmlNodePtr
3723 *
3724 * add a new xmlNodePtr to an existing NodeSet
3725 *
3726 * Returns 0 in case of success, and -1 in case of error
3727 */
3728 int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur,xmlNodePtr val)3729 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3730 int i;
3731
3732 if ((cur == NULL) || (val == NULL)) return(-1);
3733
3734 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3735 /*
3736 * prevent duplicates
3737 */
3738 for (i = 0;i < cur->nodeNr;i++)
3739 if (cur->nodeTab[i] == val) return(0);
3740
3741 /*
3742 * grow the nodeTab if needed
3743 */
3744 if (cur->nodeMax == 0) {
3745 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3746 sizeof(xmlNodePtr));
3747 if (cur->nodeTab == NULL) {
3748 xmlXPathErrMemory(NULL, "growing nodeset\n");
3749 return(-1);
3750 }
3751 memset(cur->nodeTab, 0 ,
3752 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3753 cur->nodeMax = XML_NODESET_DEFAULT;
3754 } else if (cur->nodeNr == cur->nodeMax) {
3755 xmlNodePtr *temp;
3756
3757 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3758 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3759 return(-1);
3760 }
3761 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3762 sizeof(xmlNodePtr));
3763 if (temp == NULL) {
3764 xmlXPathErrMemory(NULL, "growing nodeset\n");
3765 return(-1);
3766 }
3767 cur->nodeMax *= 2;
3768 cur->nodeTab = temp;
3769 }
3770 if (val->type == XML_NAMESPACE_DECL) {
3771 xmlNsPtr ns = (xmlNsPtr) val;
3772
3773 cur->nodeTab[cur->nodeNr++] =
3774 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3775 } else
3776 cur->nodeTab[cur->nodeNr++] = val;
3777 return(0);
3778 }
3779
3780 /**
3781 * xmlXPathNodeSetAddUnique:
3782 * @cur: the initial node set
3783 * @val: a new xmlNodePtr
3784 *
3785 * add a new xmlNodePtr to an existing NodeSet, optimized version
3786 * when we are sure the node is not already in the set.
3787 *
3788 * Returns 0 in case of success and -1 in case of failure
3789 */
3790 int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur,xmlNodePtr val)3791 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3792 if ((cur == NULL) || (val == NULL)) return(-1);
3793
3794 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3795 /*
3796 * grow the nodeTab if needed
3797 */
3798 if (cur->nodeMax == 0) {
3799 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3800 sizeof(xmlNodePtr));
3801 if (cur->nodeTab == NULL) {
3802 xmlXPathErrMemory(NULL, "growing nodeset\n");
3803 return(-1);
3804 }
3805 memset(cur->nodeTab, 0 ,
3806 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3807 cur->nodeMax = XML_NODESET_DEFAULT;
3808 } else if (cur->nodeNr == cur->nodeMax) {
3809 xmlNodePtr *temp;
3810
3811 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3812 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3813 return(-1);
3814 }
3815 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3816 sizeof(xmlNodePtr));
3817 if (temp == NULL) {
3818 xmlXPathErrMemory(NULL, "growing nodeset\n");
3819 return(-1);
3820 }
3821 cur->nodeTab = temp;
3822 cur->nodeMax *= 2;
3823 }
3824 if (val->type == XML_NAMESPACE_DECL) {
3825 xmlNsPtr ns = (xmlNsPtr) val;
3826
3827 cur->nodeTab[cur->nodeNr++] =
3828 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3829 } else
3830 cur->nodeTab[cur->nodeNr++] = val;
3831 return(0);
3832 }
3833
3834 /**
3835 * xmlXPathNodeSetMerge:
3836 * @val1: the first NodeSet or NULL
3837 * @val2: the second NodeSet
3838 *
3839 * Merges two nodesets, all nodes from @val2 are added to @val1
3840 * if @val1 is NULL, a new set is created and copied from @val2
3841 *
3842 * Returns @val1 once extended or NULL in case of error.
3843 */
3844 xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1,xmlNodeSetPtr val2)3845 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3846 int i, j, initNr, skip;
3847 xmlNodePtr n1, n2;
3848
3849 if (val2 == NULL) return(val1);
3850 if (val1 == NULL) {
3851 val1 = xmlXPathNodeSetCreate(NULL);
3852 if (val1 == NULL)
3853 return (NULL);
3854 #if 0
3855 /*
3856 * TODO: The optimization won't work in every case, since
3857 * those nasty namespace nodes need to be added with
3858 * xmlXPathNodeSetDupNs() to the set; thus a pure
3859 * memcpy is not possible.
3860 * If there was a flag on the nodesetval, indicating that
3861 * some temporary nodes are in, that would be helpfull.
3862 */
3863 /*
3864 * Optimization: Create an equally sized node-set
3865 * and memcpy the content.
3866 */
3867 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3868 if (val1 == NULL)
3869 return(NULL);
3870 if (val2->nodeNr != 0) {
3871 if (val2->nodeNr == 1)
3872 *(val1->nodeTab) = *(val2->nodeTab);
3873 else {
3874 memcpy(val1->nodeTab, val2->nodeTab,
3875 val2->nodeNr * sizeof(xmlNodePtr));
3876 }
3877 val1->nodeNr = val2->nodeNr;
3878 }
3879 return(val1);
3880 #endif
3881 }
3882
3883 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3884 initNr = val1->nodeNr;
3885
3886 for (i = 0;i < val2->nodeNr;i++) {
3887 n2 = val2->nodeTab[i];
3888 /*
3889 * check against duplicates
3890 */
3891 skip = 0;
3892 for (j = 0; j < initNr; j++) {
3893 n1 = val1->nodeTab[j];
3894 if (n1 == n2) {
3895 skip = 1;
3896 break;
3897 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3898 (n2->type == XML_NAMESPACE_DECL)) {
3899 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3900 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3901 ((xmlNsPtr) n2)->prefix)))
3902 {
3903 skip = 1;
3904 break;
3905 }
3906 }
3907 }
3908 if (skip)
3909 continue;
3910
3911 /*
3912 * grow the nodeTab if needed
3913 */
3914 if (val1->nodeMax == 0) {
3915 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3916 sizeof(xmlNodePtr));
3917 if (val1->nodeTab == NULL) {
3918 xmlXPathErrMemory(NULL, "merging nodeset\n");
3919 return(NULL);
3920 }
3921 memset(val1->nodeTab, 0 ,
3922 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3923 val1->nodeMax = XML_NODESET_DEFAULT;
3924 } else if (val1->nodeNr == val1->nodeMax) {
3925 xmlNodePtr *temp;
3926
3927 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3928 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3929 return(NULL);
3930 }
3931 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3932 sizeof(xmlNodePtr));
3933 if (temp == NULL) {
3934 xmlXPathErrMemory(NULL, "merging nodeset\n");
3935 return(NULL);
3936 }
3937 val1->nodeTab = temp;
3938 val1->nodeMax *= 2;
3939 }
3940 if (n2->type == XML_NAMESPACE_DECL) {
3941 xmlNsPtr ns = (xmlNsPtr) n2;
3942
3943 val1->nodeTab[val1->nodeNr++] =
3944 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3945 } else
3946 val1->nodeTab[val1->nodeNr++] = n2;
3947 }
3948
3949 return(val1);
3950 }
3951
3952
3953 /**
3954 * xmlXPathNodeSetMergeAndClear:
3955 * @set1: the first NodeSet or NULL
3956 * @set2: the second NodeSet
3957 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3958 *
3959 * Merges two nodesets, all nodes from @set2 are added to @set1
3960 * if @set1 is NULL, a new set is created and copied from @set2.
3961 * Checks for duplicate nodes. Clears set2.
3962 *
3963 * Returns @set1 once extended or NULL in case of error.
3964 */
3965 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)3966 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3967 int hasNullEntries)
3968 {
3969 if ((set1 == NULL) && (hasNullEntries == 0)) {
3970 /*
3971 * Note that doing a memcpy of the list, namespace nodes are
3972 * just assigned to set1, since set2 is cleared anyway.
3973 */
3974 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3975 if (set1 == NULL)
3976 return(NULL);
3977 if (set2->nodeNr != 0) {
3978 memcpy(set1->nodeTab, set2->nodeTab,
3979 set2->nodeNr * sizeof(xmlNodePtr));
3980 set1->nodeNr = set2->nodeNr;
3981 }
3982 } else {
3983 int i, j, initNbSet1;
3984 xmlNodePtr n1, n2;
3985
3986 if (set1 == NULL)
3987 set1 = xmlXPathNodeSetCreate(NULL);
3988 if (set1 == NULL)
3989 return (NULL);
3990
3991 initNbSet1 = set1->nodeNr;
3992 for (i = 0;i < set2->nodeNr;i++) {
3993 n2 = set2->nodeTab[i];
3994 /*
3995 * Skip NULLed entries.
3996 */
3997 if (n2 == NULL)
3998 continue;
3999 /*
4000 * Skip duplicates.
4001 */
4002 for (j = 0; j < initNbSet1; j++) {
4003 n1 = set1->nodeTab[j];
4004 if (n1 == n2) {
4005 goto skip_node;
4006 } else if ((n1->type == XML_NAMESPACE_DECL) &&
4007 (n2->type == XML_NAMESPACE_DECL))
4008 {
4009 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
4010 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
4011 ((xmlNsPtr) n2)->prefix)))
4012 {
4013 /*
4014 * Free the namespace node.
4015 */
4016 set2->nodeTab[i] = NULL;
4017 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4018 goto skip_node;
4019 }
4020 }
4021 }
4022 /*
4023 * grow the nodeTab if needed
4024 */
4025 if (set1->nodeMax == 0) {
4026 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4027 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4028 if (set1->nodeTab == NULL) {
4029 xmlXPathErrMemory(NULL, "merging nodeset\n");
4030 return(NULL);
4031 }
4032 memset(set1->nodeTab, 0,
4033 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4034 set1->nodeMax = XML_NODESET_DEFAULT;
4035 } else if (set1->nodeNr >= set1->nodeMax) {
4036 xmlNodePtr *temp;
4037
4038 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4039 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4040 return(NULL);
4041 }
4042 temp = (xmlNodePtr *) xmlRealloc(
4043 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4044 if (temp == NULL) {
4045 xmlXPathErrMemory(NULL, "merging nodeset\n");
4046 return(NULL);
4047 }
4048 set1->nodeTab = temp;
4049 set1->nodeMax *= 2;
4050 }
4051 set1->nodeTab[set1->nodeNr++] = n2;
4052 skip_node:
4053 {}
4054 }
4055 }
4056 set2->nodeNr = 0;
4057 return(set1);
4058 }
4059
4060 /**
4061 * xmlXPathNodeSetMergeAndClearNoDupls:
4062 * @set1: the first NodeSet or NULL
4063 * @set2: the second NodeSet
4064 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4065 *
4066 * Merges two nodesets, all nodes from @set2 are added to @set1
4067 * if @set1 is NULL, a new set is created and copied from @set2.
4068 * Doesn't chack for duplicate nodes. Clears set2.
4069 *
4070 * Returns @set1 once extended or NULL in case of error.
4071 */
4072 static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1,xmlNodeSetPtr set2,int hasNullEntries)4073 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4074 int hasNullEntries)
4075 {
4076 if (set2 == NULL)
4077 return(set1);
4078 if ((set1 == NULL) && (hasNullEntries == 0)) {
4079 /*
4080 * Note that doing a memcpy of the list, namespace nodes are
4081 * just assigned to set1, since set2 is cleared anyway.
4082 */
4083 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4084 if (set1 == NULL)
4085 return(NULL);
4086 if (set2->nodeNr != 0) {
4087 memcpy(set1->nodeTab, set2->nodeTab,
4088 set2->nodeNr * sizeof(xmlNodePtr));
4089 set1->nodeNr = set2->nodeNr;
4090 }
4091 } else {
4092 int i;
4093 xmlNodePtr n2;
4094
4095 if (set1 == NULL)
4096 set1 = xmlXPathNodeSetCreate(NULL);
4097 if (set1 == NULL)
4098 return (NULL);
4099
4100 for (i = 0;i < set2->nodeNr;i++) {
4101 n2 = set2->nodeTab[i];
4102 /*
4103 * Skip NULLed entries.
4104 */
4105 if (n2 == NULL)
4106 continue;
4107 if (set1->nodeMax == 0) {
4108 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4109 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4110 if (set1->nodeTab == NULL) {
4111 xmlXPathErrMemory(NULL, "merging nodeset\n");
4112 return(NULL);
4113 }
4114 memset(set1->nodeTab, 0,
4115 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4116 set1->nodeMax = XML_NODESET_DEFAULT;
4117 } else if (set1->nodeNr >= set1->nodeMax) {
4118 xmlNodePtr *temp;
4119
4120 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4121 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4122 return(NULL);
4123 }
4124 temp = (xmlNodePtr *) xmlRealloc(
4125 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4126 if (temp == NULL) {
4127 xmlXPathErrMemory(NULL, "merging nodeset\n");
4128 return(NULL);
4129 }
4130 set1->nodeTab = temp;
4131 set1->nodeMax *= 2;
4132 }
4133 set1->nodeTab[set1->nodeNr++] = n2;
4134 }
4135 }
4136 set2->nodeNr = 0;
4137 return(set1);
4138 }
4139
4140 /**
4141 * xmlXPathNodeSetDel:
4142 * @cur: the initial node set
4143 * @val: an xmlNodePtr
4144 *
4145 * Removes an xmlNodePtr from an existing NodeSet
4146 */
4147 void
xmlXPathNodeSetDel(xmlNodeSetPtr cur,xmlNodePtr val)4148 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4149 int i;
4150
4151 if (cur == NULL) return;
4152 if (val == NULL) return;
4153
4154 /*
4155 * find node in nodeTab
4156 */
4157 for (i = 0;i < cur->nodeNr;i++)
4158 if (cur->nodeTab[i] == val) break;
4159
4160 if (i >= cur->nodeNr) { /* not found */
4161 #ifdef DEBUG
4162 xmlGenericError(xmlGenericErrorContext,
4163 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4164 val->name);
4165 #endif
4166 return;
4167 }
4168 if ((cur->nodeTab[i] != NULL) &&
4169 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4170 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4171 cur->nodeNr--;
4172 for (;i < cur->nodeNr;i++)
4173 cur->nodeTab[i] = cur->nodeTab[i + 1];
4174 cur->nodeTab[cur->nodeNr] = NULL;
4175 }
4176
4177 /**
4178 * xmlXPathNodeSetRemove:
4179 * @cur: the initial node set
4180 * @val: the index to remove
4181 *
4182 * Removes an entry from an existing NodeSet list.
4183 */
4184 void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur,int val)4185 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4186 if (cur == NULL) return;
4187 if (val >= cur->nodeNr) return;
4188 if ((cur->nodeTab[val] != NULL) &&
4189 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4190 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4191 cur->nodeNr--;
4192 for (;val < cur->nodeNr;val++)
4193 cur->nodeTab[val] = cur->nodeTab[val + 1];
4194 cur->nodeTab[cur->nodeNr] = NULL;
4195 }
4196
4197 /**
4198 * xmlXPathFreeNodeSet:
4199 * @obj: the xmlNodeSetPtr to free
4200 *
4201 * Free the NodeSet compound (not the actual nodes !).
4202 */
4203 void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj)4204 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4205 if (obj == NULL) return;
4206 if (obj->nodeTab != NULL) {
4207 int i;
4208
4209 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4210 for (i = 0;i < obj->nodeNr;i++)
4211 if ((obj->nodeTab[i] != NULL) &&
4212 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4213 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4214 xmlFree(obj->nodeTab);
4215 }
4216 xmlFree(obj);
4217 }
4218
4219 /**
4220 * xmlXPathNodeSetClearFromPos:
4221 * @set: the node set to be cleared
4222 * @pos: the start position to clear from
4223 *
4224 * Clears the list from temporary XPath objects (e.g. namespace nodes
4225 * are feed) starting with the entry at @pos, but does *not* free the list
4226 * itself. Sets the length of the list to @pos.
4227 */
4228 static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set,int pos,int hasNsNodes)4229 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4230 {
4231 if ((set == NULL) || (pos >= set->nodeNr))
4232 return;
4233 else if ((hasNsNodes)) {
4234 int i;
4235 xmlNodePtr node;
4236
4237 for (i = pos; i < set->nodeNr; i++) {
4238 node = set->nodeTab[i];
4239 if ((node != NULL) &&
4240 (node->type == XML_NAMESPACE_DECL))
4241 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4242 }
4243 }
4244 set->nodeNr = pos;
4245 }
4246
4247 /**
4248 * xmlXPathNodeSetClear:
4249 * @set: the node set to clear
4250 *
4251 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4252 * are feed), but does *not* free the list itself. Sets the length of the
4253 * list to 0.
4254 */
4255 static void
xmlXPathNodeSetClear(xmlNodeSetPtr set,int hasNsNodes)4256 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4257 {
4258 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4259 }
4260
4261 /**
4262 * xmlXPathNodeSetKeepLast:
4263 * @set: the node set to be cleared
4264 *
4265 * Move the last node to the first position and clear temporary XPath objects
4266 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4267 * to 1.
4268 */
4269 static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)4270 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4271 {
4272 int i;
4273 xmlNodePtr node;
4274
4275 if ((set == NULL) || (set->nodeNr <= 1))
4276 return;
4277 for (i = 0; i < set->nodeNr - 1; i++) {
4278 node = set->nodeTab[i];
4279 if ((node != NULL) &&
4280 (node->type == XML_NAMESPACE_DECL))
4281 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4282 }
4283 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4284 set->nodeNr = 1;
4285 }
4286
4287 /**
4288 * xmlXPathFreeValueTree:
4289 * @obj: the xmlNodeSetPtr to free
4290 *
4291 * Free the NodeSet compound and the actual tree, this is different
4292 * from xmlXPathFreeNodeSet()
4293 */
4294 static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj)4295 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4296 int i;
4297
4298 if (obj == NULL) return;
4299
4300 if (obj->nodeTab != NULL) {
4301 for (i = 0;i < obj->nodeNr;i++) {
4302 if (obj->nodeTab[i] != NULL) {
4303 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4304 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4305 } else {
4306 xmlFreeNodeList(obj->nodeTab[i]);
4307 }
4308 }
4309 }
4310 xmlFree(obj->nodeTab);
4311 }
4312 xmlFree(obj);
4313 }
4314
4315 #if defined(DEBUG) || defined(DEBUG_STEP)
4316 /**
4317 * xmlGenericErrorContextNodeSet:
4318 * @output: a FILE * for the output
4319 * @obj: the xmlNodeSetPtr to display
4320 *
4321 * Quick display of a NodeSet
4322 */
4323 void
xmlGenericErrorContextNodeSet(FILE * output,xmlNodeSetPtr obj)4324 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4325 int i;
4326
4327 if (output == NULL) output = xmlGenericErrorContext;
4328 if (obj == NULL) {
4329 fprintf(output, "NodeSet == NULL !\n");
4330 return;
4331 }
4332 if (obj->nodeNr == 0) {
4333 fprintf(output, "NodeSet is empty\n");
4334 return;
4335 }
4336 if (obj->nodeTab == NULL) {
4337 fprintf(output, " nodeTab == NULL !\n");
4338 return;
4339 }
4340 for (i = 0; i < obj->nodeNr; i++) {
4341 if (obj->nodeTab[i] == NULL) {
4342 fprintf(output, " NULL !\n");
4343 return;
4344 }
4345 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4346 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4347 fprintf(output, " /");
4348 else if (obj->nodeTab[i]->name == NULL)
4349 fprintf(output, " noname!");
4350 else fprintf(output, " %s", obj->nodeTab[i]->name);
4351 }
4352 fprintf(output, "\n");
4353 }
4354 #endif
4355
4356 /**
4357 * xmlXPathNewNodeSet:
4358 * @val: the NodePtr value
4359 *
4360 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4361 * it with the single Node @val
4362 *
4363 * Returns the newly created object.
4364 */
4365 xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val)4366 xmlXPathNewNodeSet(xmlNodePtr val) {
4367 xmlXPathObjectPtr ret;
4368
4369 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4370 if (ret == NULL) {
4371 xmlXPathErrMemory(NULL, "creating nodeset\n");
4372 return(NULL);
4373 }
4374 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4375 ret->type = XPATH_NODESET;
4376 ret->boolval = 0;
4377 ret->nodesetval = xmlXPathNodeSetCreate(val);
4378 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4379 #ifdef XP_DEBUG_OBJ_USAGE
4380 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4381 #endif
4382 return(ret);
4383 }
4384
4385 /**
4386 * xmlXPathNewValueTree:
4387 * @val: the NodePtr value
4388 *
4389 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4390 * it with the tree root @val
4391 *
4392 * Returns the newly created object.
4393 */
4394 xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val)4395 xmlXPathNewValueTree(xmlNodePtr val) {
4396 xmlXPathObjectPtr ret;
4397
4398 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4399 if (ret == NULL) {
4400 xmlXPathErrMemory(NULL, "creating result value tree\n");
4401 return(NULL);
4402 }
4403 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4404 ret->type = XPATH_XSLT_TREE;
4405 ret->boolval = 1;
4406 ret->user = (void *) val;
4407 ret->nodesetval = xmlXPathNodeSetCreate(val);
4408 #ifdef XP_DEBUG_OBJ_USAGE
4409 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4410 #endif
4411 return(ret);
4412 }
4413
4414 /**
4415 * xmlXPathNewNodeSetList:
4416 * @val: an existing NodeSet
4417 *
4418 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4419 * it with the Nodeset @val
4420 *
4421 * Returns the newly created object.
4422 */
4423 xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)4424 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4425 {
4426 xmlXPathObjectPtr ret;
4427 int i;
4428
4429 if (val == NULL)
4430 ret = NULL;
4431 else if (val->nodeTab == NULL)
4432 ret = xmlXPathNewNodeSet(NULL);
4433 else {
4434 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4435 if (ret) {
4436 for (i = 1; i < val->nodeNr; ++i) {
4437 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4438 < 0) break;
4439 }
4440 }
4441 }
4442
4443 return (ret);
4444 }
4445
4446 /**
4447 * xmlXPathWrapNodeSet:
4448 * @val: the NodePtr value
4449 *
4450 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4451 *
4452 * Returns the newly created object.
4453 */
4454 xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val)4455 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4456 xmlXPathObjectPtr ret;
4457
4458 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4459 if (ret == NULL) {
4460 xmlXPathErrMemory(NULL, "creating node set object\n");
4461 return(NULL);
4462 }
4463 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4464 ret->type = XPATH_NODESET;
4465 ret->nodesetval = val;
4466 #ifdef XP_DEBUG_OBJ_USAGE
4467 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4468 #endif
4469 return(ret);
4470 }
4471
4472 /**
4473 * xmlXPathFreeNodeSetList:
4474 * @obj: an existing NodeSetList object
4475 *
4476 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4477 * the list contrary to xmlXPathFreeObject().
4478 */
4479 void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj)4480 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4481 if (obj == NULL) return;
4482 #ifdef XP_DEBUG_OBJ_USAGE
4483 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4484 #endif
4485 xmlFree(obj);
4486 }
4487
4488 /**
4489 * xmlXPathDifference:
4490 * @nodes1: a node-set
4491 * @nodes2: a node-set
4492 *
4493 * Implements the EXSLT - Sets difference() function:
4494 * node-set set:difference (node-set, node-set)
4495 *
4496 * Returns the difference between the two node sets, or nodes1 if
4497 * nodes2 is empty
4498 */
4499 xmlNodeSetPtr
xmlXPathDifference(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4500 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4501 xmlNodeSetPtr ret;
4502 int i, l1;
4503 xmlNodePtr cur;
4504
4505 if (xmlXPathNodeSetIsEmpty(nodes2))
4506 return(nodes1);
4507
4508 ret = xmlXPathNodeSetCreate(NULL);
4509 if (xmlXPathNodeSetIsEmpty(nodes1))
4510 return(ret);
4511
4512 l1 = xmlXPathNodeSetGetLength(nodes1);
4513
4514 for (i = 0; i < l1; i++) {
4515 cur = xmlXPathNodeSetItem(nodes1, i);
4516 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4517 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4518 break;
4519 }
4520 }
4521 return(ret);
4522 }
4523
4524 /**
4525 * xmlXPathIntersection:
4526 * @nodes1: a node-set
4527 * @nodes2: a node-set
4528 *
4529 * Implements the EXSLT - Sets intersection() function:
4530 * node-set set:intersection (node-set, node-set)
4531 *
4532 * Returns a node set comprising the nodes that are within both the
4533 * node sets passed as arguments
4534 */
4535 xmlNodeSetPtr
xmlXPathIntersection(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4536 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4537 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4538 int i, l1;
4539 xmlNodePtr cur;
4540
4541 if (ret == NULL)
4542 return(ret);
4543 if (xmlXPathNodeSetIsEmpty(nodes1))
4544 return(ret);
4545 if (xmlXPathNodeSetIsEmpty(nodes2))
4546 return(ret);
4547
4548 l1 = xmlXPathNodeSetGetLength(nodes1);
4549
4550 for (i = 0; i < l1; i++) {
4551 cur = xmlXPathNodeSetItem(nodes1, i);
4552 if (xmlXPathNodeSetContains(nodes2, cur)) {
4553 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4554 break;
4555 }
4556 }
4557 return(ret);
4558 }
4559
4560 /**
4561 * xmlXPathDistinctSorted:
4562 * @nodes: a node-set, sorted by document order
4563 *
4564 * Implements the EXSLT - Sets distinct() function:
4565 * node-set set:distinct (node-set)
4566 *
4567 * Returns a subset of the nodes contained in @nodes, or @nodes if
4568 * it is empty
4569 */
4570 xmlNodeSetPtr
xmlXPathDistinctSorted(xmlNodeSetPtr nodes)4571 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4572 xmlNodeSetPtr ret;
4573 xmlHashTablePtr hash;
4574 int i, l;
4575 xmlChar * strval;
4576 xmlNodePtr cur;
4577
4578 if (xmlXPathNodeSetIsEmpty(nodes))
4579 return(nodes);
4580
4581 ret = xmlXPathNodeSetCreate(NULL);
4582 if (ret == NULL)
4583 return(ret);
4584 l = xmlXPathNodeSetGetLength(nodes);
4585 hash = xmlHashCreate (l);
4586 for (i = 0; i < l; i++) {
4587 cur = xmlXPathNodeSetItem(nodes, i);
4588 strval = xmlXPathCastNodeToString(cur);
4589 if (xmlHashLookup(hash, strval) == NULL) {
4590 xmlHashAddEntry(hash, strval, strval);
4591 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4592 break;
4593 } else {
4594 xmlFree(strval);
4595 }
4596 }
4597 xmlHashFree(hash, xmlHashDefaultDeallocator);
4598 return(ret);
4599 }
4600
4601 /**
4602 * xmlXPathDistinct:
4603 * @nodes: a node-set
4604 *
4605 * Implements the EXSLT - Sets distinct() function:
4606 * node-set set:distinct (node-set)
4607 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4608 * is called with the sorted node-set
4609 *
4610 * Returns a subset of the nodes contained in @nodes, or @nodes if
4611 * it is empty
4612 */
4613 xmlNodeSetPtr
xmlXPathDistinct(xmlNodeSetPtr nodes)4614 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4615 if (xmlXPathNodeSetIsEmpty(nodes))
4616 return(nodes);
4617
4618 xmlXPathNodeSetSort(nodes);
4619 return(xmlXPathDistinctSorted(nodes));
4620 }
4621
4622 /**
4623 * xmlXPathHasSameNodes:
4624 * @nodes1: a node-set
4625 * @nodes2: a node-set
4626 *
4627 * Implements the EXSLT - Sets has-same-nodes function:
4628 * boolean set:has-same-node(node-set, node-set)
4629 *
4630 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4631 * otherwise
4632 */
4633 int
xmlXPathHasSameNodes(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4634 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4635 int i, l;
4636 xmlNodePtr cur;
4637
4638 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4639 xmlXPathNodeSetIsEmpty(nodes2))
4640 return(0);
4641
4642 l = xmlXPathNodeSetGetLength(nodes1);
4643 for (i = 0; i < l; i++) {
4644 cur = xmlXPathNodeSetItem(nodes1, i);
4645 if (xmlXPathNodeSetContains(nodes2, cur))
4646 return(1);
4647 }
4648 return(0);
4649 }
4650
4651 /**
4652 * xmlXPathNodeLeadingSorted:
4653 * @nodes: a node-set, sorted by document order
4654 * @node: a node
4655 *
4656 * Implements the EXSLT - Sets leading() function:
4657 * node-set set:leading (node-set, node-set)
4658 *
4659 * Returns the nodes in @nodes that precede @node in document order,
4660 * @nodes if @node is NULL or an empty node-set if @nodes
4661 * doesn't contain @node
4662 */
4663 xmlNodeSetPtr
xmlXPathNodeLeadingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4664 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4665 int i, l;
4666 xmlNodePtr cur;
4667 xmlNodeSetPtr ret;
4668
4669 if (node == NULL)
4670 return(nodes);
4671
4672 ret = xmlXPathNodeSetCreate(NULL);
4673 if (ret == NULL)
4674 return(ret);
4675 if (xmlXPathNodeSetIsEmpty(nodes) ||
4676 (!xmlXPathNodeSetContains(nodes, node)))
4677 return(ret);
4678
4679 l = xmlXPathNodeSetGetLength(nodes);
4680 for (i = 0; i < l; i++) {
4681 cur = xmlXPathNodeSetItem(nodes, i);
4682 if (cur == node)
4683 break;
4684 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4685 break;
4686 }
4687 return(ret);
4688 }
4689
4690 /**
4691 * xmlXPathNodeLeading:
4692 * @nodes: a node-set
4693 * @node: a node
4694 *
4695 * Implements the EXSLT - Sets leading() function:
4696 * node-set set:leading (node-set, node-set)
4697 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4698 * is called.
4699 *
4700 * Returns the nodes in @nodes that precede @node in document order,
4701 * @nodes if @node is NULL or an empty node-set if @nodes
4702 * doesn't contain @node
4703 */
4704 xmlNodeSetPtr
xmlXPathNodeLeading(xmlNodeSetPtr nodes,xmlNodePtr node)4705 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4706 xmlXPathNodeSetSort(nodes);
4707 return(xmlXPathNodeLeadingSorted(nodes, node));
4708 }
4709
4710 /**
4711 * xmlXPathLeadingSorted:
4712 * @nodes1: a node-set, sorted by document order
4713 * @nodes2: a node-set, sorted by document order
4714 *
4715 * Implements the EXSLT - Sets leading() function:
4716 * node-set set:leading (node-set, node-set)
4717 *
4718 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4719 * in document order, @nodes1 if @nodes2 is NULL or empty or
4720 * an empty node-set if @nodes1 doesn't contain @nodes2
4721 */
4722 xmlNodeSetPtr
xmlXPathLeadingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4723 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4724 if (xmlXPathNodeSetIsEmpty(nodes2))
4725 return(nodes1);
4726 return(xmlXPathNodeLeadingSorted(nodes1,
4727 xmlXPathNodeSetItem(nodes2, 1)));
4728 }
4729
4730 /**
4731 * xmlXPathLeading:
4732 * @nodes1: a node-set
4733 * @nodes2: a node-set
4734 *
4735 * Implements the EXSLT - Sets leading() function:
4736 * node-set set:leading (node-set, node-set)
4737 * @nodes1 and @nodes2 are sorted by document order, then
4738 * #exslSetsLeadingSorted is called.
4739 *
4740 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4741 * in document order, @nodes1 if @nodes2 is NULL or empty or
4742 * an empty node-set if @nodes1 doesn't contain @nodes2
4743 */
4744 xmlNodeSetPtr
xmlXPathLeading(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4745 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4746 if (xmlXPathNodeSetIsEmpty(nodes2))
4747 return(nodes1);
4748 if (xmlXPathNodeSetIsEmpty(nodes1))
4749 return(xmlXPathNodeSetCreate(NULL));
4750 xmlXPathNodeSetSort(nodes1);
4751 xmlXPathNodeSetSort(nodes2);
4752 return(xmlXPathNodeLeadingSorted(nodes1,
4753 xmlXPathNodeSetItem(nodes2, 1)));
4754 }
4755
4756 /**
4757 * xmlXPathNodeTrailingSorted:
4758 * @nodes: a node-set, sorted by document order
4759 * @node: a node
4760 *
4761 * Implements the EXSLT - Sets trailing() function:
4762 * node-set set:trailing (node-set, node-set)
4763 *
4764 * Returns the nodes in @nodes that follow @node in document order,
4765 * @nodes if @node is NULL or an empty node-set if @nodes
4766 * doesn't contain @node
4767 */
4768 xmlNodeSetPtr
xmlXPathNodeTrailingSorted(xmlNodeSetPtr nodes,xmlNodePtr node)4769 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4770 int i, l;
4771 xmlNodePtr cur;
4772 xmlNodeSetPtr ret;
4773
4774 if (node == NULL)
4775 return(nodes);
4776
4777 ret = xmlXPathNodeSetCreate(NULL);
4778 if (ret == NULL)
4779 return(ret);
4780 if (xmlXPathNodeSetIsEmpty(nodes) ||
4781 (!xmlXPathNodeSetContains(nodes, node)))
4782 return(ret);
4783
4784 l = xmlXPathNodeSetGetLength(nodes);
4785 for (i = l - 1; i >= 0; i--) {
4786 cur = xmlXPathNodeSetItem(nodes, i);
4787 if (cur == node)
4788 break;
4789 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4790 break;
4791 }
4792 xmlXPathNodeSetSort(ret); /* bug 413451 */
4793 return(ret);
4794 }
4795
4796 /**
4797 * xmlXPathNodeTrailing:
4798 * @nodes: a node-set
4799 * @node: a node
4800 *
4801 * Implements the EXSLT - Sets trailing() function:
4802 * node-set set:trailing (node-set, node-set)
4803 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4804 * is called.
4805 *
4806 * Returns the nodes in @nodes that follow @node in document order,
4807 * @nodes if @node is NULL or an empty node-set if @nodes
4808 * doesn't contain @node
4809 */
4810 xmlNodeSetPtr
xmlXPathNodeTrailing(xmlNodeSetPtr nodes,xmlNodePtr node)4811 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4812 xmlXPathNodeSetSort(nodes);
4813 return(xmlXPathNodeTrailingSorted(nodes, node));
4814 }
4815
4816 /**
4817 * xmlXPathTrailingSorted:
4818 * @nodes1: a node-set, sorted by document order
4819 * @nodes2: a node-set, sorted by document order
4820 *
4821 * Implements the EXSLT - Sets trailing() function:
4822 * node-set set:trailing (node-set, node-set)
4823 *
4824 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4825 * in document order, @nodes1 if @nodes2 is NULL or empty or
4826 * an empty node-set if @nodes1 doesn't contain @nodes2
4827 */
4828 xmlNodeSetPtr
xmlXPathTrailingSorted(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4829 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4830 if (xmlXPathNodeSetIsEmpty(nodes2))
4831 return(nodes1);
4832 return(xmlXPathNodeTrailingSorted(nodes1,
4833 xmlXPathNodeSetItem(nodes2, 0)));
4834 }
4835
4836 /**
4837 * xmlXPathTrailing:
4838 * @nodes1: a node-set
4839 * @nodes2: a node-set
4840 *
4841 * Implements the EXSLT - Sets trailing() function:
4842 * node-set set:trailing (node-set, node-set)
4843 * @nodes1 and @nodes2 are sorted by document order, then
4844 * #xmlXPathTrailingSorted is called.
4845 *
4846 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4847 * in document order, @nodes1 if @nodes2 is NULL or empty or
4848 * an empty node-set if @nodes1 doesn't contain @nodes2
4849 */
4850 xmlNodeSetPtr
xmlXPathTrailing(xmlNodeSetPtr nodes1,xmlNodeSetPtr nodes2)4851 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4852 if (xmlXPathNodeSetIsEmpty(nodes2))
4853 return(nodes1);
4854 if (xmlXPathNodeSetIsEmpty(nodes1))
4855 return(xmlXPathNodeSetCreate(NULL));
4856 xmlXPathNodeSetSort(nodes1);
4857 xmlXPathNodeSetSort(nodes2);
4858 return(xmlXPathNodeTrailingSorted(nodes1,
4859 xmlXPathNodeSetItem(nodes2, 0)));
4860 }
4861
4862 /************************************************************************
4863 * *
4864 * Routines to handle extra functions *
4865 * *
4866 ************************************************************************/
4867
4868 /**
4869 * xmlXPathRegisterFunc:
4870 * @ctxt: the XPath context
4871 * @name: the function name
4872 * @f: the function implementation or NULL
4873 *
4874 * Register a new function. If @f is NULL it unregisters the function
4875 *
4876 * Returns 0 in case of success, -1 in case of error
4877 */
4878 int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathFunction f)4879 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4880 xmlXPathFunction f) {
4881 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4882 }
4883
4884 /**
4885 * xmlXPathRegisterFuncNS:
4886 * @ctxt: the XPath context
4887 * @name: the function name
4888 * @ns_uri: the function namespace URI
4889 * @f: the function implementation or NULL
4890 *
4891 * Register a new function. If @f is NULL it unregisters the function
4892 *
4893 * Returns 0 in case of success, -1 in case of error
4894 */
4895 int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathFunction f)4896 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4897 const xmlChar *ns_uri, xmlXPathFunction f) {
4898 if (ctxt == NULL)
4899 return(-1);
4900 if (name == NULL)
4901 return(-1);
4902
4903 if (ctxt->funcHash == NULL)
4904 ctxt->funcHash = xmlHashCreate(0);
4905 if (ctxt->funcHash == NULL)
4906 return(-1);
4907 if (f == NULL)
4908 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4909 XML_IGNORE_PEDANTIC_WARNINGS
4910 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4911 XML_POP_WARNINGS
4912 }
4913
4914 /**
4915 * xmlXPathRegisterFuncLookup:
4916 * @ctxt: the XPath context
4917 * @f: the lookup function
4918 * @funcCtxt: the lookup data
4919 *
4920 * Registers an external mechanism to do function lookup.
4921 */
4922 void
xmlXPathRegisterFuncLookup(xmlXPathContextPtr ctxt,xmlXPathFuncLookupFunc f,void * funcCtxt)4923 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4924 xmlXPathFuncLookupFunc f,
4925 void *funcCtxt) {
4926 if (ctxt == NULL)
4927 return;
4928 ctxt->funcLookupFunc = f;
4929 ctxt->funcLookupData = funcCtxt;
4930 }
4931
4932 /**
4933 * xmlXPathFunctionLookup:
4934 * @ctxt: the XPath context
4935 * @name: the function name
4936 *
4937 * Search in the Function array of the context for the given
4938 * function.
4939 *
4940 * Returns the xmlXPathFunction or NULL if not found
4941 */
4942 xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt,const xmlChar * name)4943 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4944 if (ctxt == NULL)
4945 return (NULL);
4946
4947 if (ctxt->funcLookupFunc != NULL) {
4948 xmlXPathFunction ret;
4949 xmlXPathFuncLookupFunc f;
4950
4951 f = ctxt->funcLookupFunc;
4952 ret = f(ctxt->funcLookupData, name, NULL);
4953 if (ret != NULL)
4954 return(ret);
4955 }
4956 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4957 }
4958
4959 /**
4960 * xmlXPathFunctionLookupNS:
4961 * @ctxt: the XPath context
4962 * @name: the function name
4963 * @ns_uri: the function namespace URI
4964 *
4965 * Search in the Function array of the context for the given
4966 * function.
4967 *
4968 * Returns the xmlXPathFunction or NULL if not found
4969 */
4970 xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)4971 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4972 const xmlChar *ns_uri) {
4973 xmlXPathFunction ret;
4974
4975 if (ctxt == NULL)
4976 return(NULL);
4977 if (name == NULL)
4978 return(NULL);
4979
4980 if (ctxt->funcLookupFunc != NULL) {
4981 xmlXPathFuncLookupFunc f;
4982
4983 f = ctxt->funcLookupFunc;
4984 ret = f(ctxt->funcLookupData, name, ns_uri);
4985 if (ret != NULL)
4986 return(ret);
4987 }
4988
4989 if (ctxt->funcHash == NULL)
4990 return(NULL);
4991
4992 XML_IGNORE_PEDANTIC_WARNINGS
4993 ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4994 XML_POP_WARNINGS
4995 return(ret);
4996 }
4997
4998 /**
4999 * xmlXPathRegisteredFuncsCleanup:
5000 * @ctxt: the XPath context
5001 *
5002 * Cleanup the XPath context data associated to registered functions
5003 */
5004 void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt)5005 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
5006 if (ctxt == NULL)
5007 return;
5008
5009 xmlHashFree(ctxt->funcHash, NULL);
5010 ctxt->funcHash = NULL;
5011 }
5012
5013 /************************************************************************
5014 * *
5015 * Routines to handle Variables *
5016 * *
5017 ************************************************************************/
5018
5019 /**
5020 * xmlXPathRegisterVariable:
5021 * @ctxt: the XPath context
5022 * @name: the variable name
5023 * @value: the variable value or NULL
5024 *
5025 * Register a new variable value. If @value is NULL it unregisters
5026 * the variable
5027 *
5028 * Returns 0 in case of success, -1 in case of error
5029 */
5030 int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt,const xmlChar * name,xmlXPathObjectPtr value)5031 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5032 xmlXPathObjectPtr value) {
5033 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5034 }
5035
5036 /**
5037 * xmlXPathRegisterVariableNS:
5038 * @ctxt: the XPath context
5039 * @name: the variable name
5040 * @ns_uri: the variable namespace URI
5041 * @value: the variable value or NULL
5042 *
5043 * Register a new variable value. If @value is NULL it unregisters
5044 * the variable
5045 *
5046 * Returns 0 in case of success, -1 in case of error
5047 */
5048 int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri,xmlXPathObjectPtr value)5049 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5050 const xmlChar *ns_uri,
5051 xmlXPathObjectPtr value) {
5052 if (ctxt == NULL)
5053 return(-1);
5054 if (name == NULL)
5055 return(-1);
5056
5057 if (ctxt->varHash == NULL)
5058 ctxt->varHash = xmlHashCreate(0);
5059 if (ctxt->varHash == NULL)
5060 return(-1);
5061 if (value == NULL)
5062 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5063 xmlXPathFreeObjectEntry));
5064 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5065 (void *) value, xmlXPathFreeObjectEntry));
5066 }
5067
5068 /**
5069 * xmlXPathRegisterVariableLookup:
5070 * @ctxt: the XPath context
5071 * @f: the lookup function
5072 * @data: the lookup data
5073 *
5074 * register an external mechanism to do variable lookup
5075 */
5076 void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,xmlXPathVariableLookupFunc f,void * data)5077 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5078 xmlXPathVariableLookupFunc f, void *data) {
5079 if (ctxt == NULL)
5080 return;
5081 ctxt->varLookupFunc = f;
5082 ctxt->varLookupData = data;
5083 }
5084
5085 /**
5086 * xmlXPathVariableLookup:
5087 * @ctxt: the XPath context
5088 * @name: the variable name
5089 *
5090 * Search in the Variable array of the context for the given
5091 * variable value.
5092 *
5093 * Returns a copy of the value or NULL if not found
5094 */
5095 xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt,const xmlChar * name)5096 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5097 if (ctxt == NULL)
5098 return(NULL);
5099
5100 if (ctxt->varLookupFunc != NULL) {
5101 xmlXPathObjectPtr ret;
5102
5103 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5104 (ctxt->varLookupData, name, NULL);
5105 return(ret);
5106 }
5107 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5108 }
5109
5110 /**
5111 * xmlXPathVariableLookupNS:
5112 * @ctxt: the XPath context
5113 * @name: the variable name
5114 * @ns_uri: the variable namespace URI
5115 *
5116 * Search in the Variable array of the context for the given
5117 * variable value.
5118 *
5119 * Returns the a copy of the value or NULL if not found
5120 */
5121 xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt,const xmlChar * name,const xmlChar * ns_uri)5122 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5123 const xmlChar *ns_uri) {
5124 if (ctxt == NULL)
5125 return(NULL);
5126
5127 if (ctxt->varLookupFunc != NULL) {
5128 xmlXPathObjectPtr ret;
5129
5130 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5131 (ctxt->varLookupData, name, ns_uri);
5132 if (ret != NULL) return(ret);
5133 }
5134
5135 if (ctxt->varHash == NULL)
5136 return(NULL);
5137 if (name == NULL)
5138 return(NULL);
5139
5140 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5141 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5142 }
5143
5144 /**
5145 * xmlXPathRegisteredVariablesCleanup:
5146 * @ctxt: the XPath context
5147 *
5148 * Cleanup the XPath context data associated to registered variables
5149 */
5150 void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt)5151 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5152 if (ctxt == NULL)
5153 return;
5154
5155 xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5156 ctxt->varHash = NULL;
5157 }
5158
5159 /**
5160 * xmlXPathRegisterNs:
5161 * @ctxt: the XPath context
5162 * @prefix: the namespace prefix cannot be NULL or empty string
5163 * @ns_uri: the namespace name
5164 *
5165 * Register a new namespace. If @ns_uri is NULL it unregisters
5166 * the namespace
5167 *
5168 * Returns 0 in case of success, -1 in case of error
5169 */
5170 int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt,const xmlChar * prefix,const xmlChar * ns_uri)5171 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5172 const xmlChar *ns_uri) {
5173 if (ctxt == NULL)
5174 return(-1);
5175 if (prefix == NULL)
5176 return(-1);
5177 if (prefix[0] == 0)
5178 return(-1);
5179
5180 if (ctxt->nsHash == NULL)
5181 ctxt->nsHash = xmlHashCreate(10);
5182 if (ctxt->nsHash == NULL)
5183 return(-1);
5184 if (ns_uri == NULL)
5185 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5186 xmlHashDefaultDeallocator));
5187 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5188 xmlHashDefaultDeallocator));
5189 }
5190
5191 /**
5192 * xmlXPathNsLookup:
5193 * @ctxt: the XPath context
5194 * @prefix: the namespace prefix value
5195 *
5196 * Search in the namespace declaration array of the context for the given
5197 * namespace name associated to the given prefix
5198 *
5199 * Returns the value or NULL if not found
5200 */
5201 const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt,const xmlChar * prefix)5202 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5203 if (ctxt == NULL)
5204 return(NULL);
5205 if (prefix == NULL)
5206 return(NULL);
5207
5208 #ifdef XML_XML_NAMESPACE
5209 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5210 return(XML_XML_NAMESPACE);
5211 #endif
5212
5213 if (ctxt->namespaces != NULL) {
5214 int i;
5215
5216 for (i = 0;i < ctxt->nsNr;i++) {
5217 if ((ctxt->namespaces[i] != NULL) &&
5218 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5219 return(ctxt->namespaces[i]->href);
5220 }
5221 }
5222
5223 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5224 }
5225
5226 /**
5227 * xmlXPathRegisteredNsCleanup:
5228 * @ctxt: the XPath context
5229 *
5230 * Cleanup the XPath context data associated to registered variables
5231 */
5232 void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt)5233 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5234 if (ctxt == NULL)
5235 return;
5236
5237 xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5238 ctxt->nsHash = NULL;
5239 }
5240
5241 /************************************************************************
5242 * *
5243 * Routines to handle Values *
5244 * *
5245 ************************************************************************/
5246
5247 /* Allocations are terrible, one needs to optimize all this !!! */
5248
5249 /**
5250 * xmlXPathNewFloat:
5251 * @val: the double value
5252 *
5253 * Create a new xmlXPathObjectPtr of type double and of value @val
5254 *
5255 * Returns the newly created object.
5256 */
5257 xmlXPathObjectPtr
xmlXPathNewFloat(double val)5258 xmlXPathNewFloat(double val) {
5259 xmlXPathObjectPtr ret;
5260
5261 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262 if (ret == NULL) {
5263 xmlXPathErrMemory(NULL, "creating float object\n");
5264 return(NULL);
5265 }
5266 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5267 ret->type = XPATH_NUMBER;
5268 ret->floatval = val;
5269 #ifdef XP_DEBUG_OBJ_USAGE
5270 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5271 #endif
5272 return(ret);
5273 }
5274
5275 /**
5276 * xmlXPathNewBoolean:
5277 * @val: the boolean value
5278 *
5279 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5280 *
5281 * Returns the newly created object.
5282 */
5283 xmlXPathObjectPtr
xmlXPathNewBoolean(int val)5284 xmlXPathNewBoolean(int val) {
5285 xmlXPathObjectPtr ret;
5286
5287 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5288 if (ret == NULL) {
5289 xmlXPathErrMemory(NULL, "creating boolean object\n");
5290 return(NULL);
5291 }
5292 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5293 ret->type = XPATH_BOOLEAN;
5294 ret->boolval = (val != 0);
5295 #ifdef XP_DEBUG_OBJ_USAGE
5296 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5297 #endif
5298 return(ret);
5299 }
5300
5301 /**
5302 * xmlXPathNewString:
5303 * @val: the xmlChar * value
5304 *
5305 * Create a new xmlXPathObjectPtr of type string and of value @val
5306 *
5307 * Returns the newly created object.
5308 */
5309 xmlXPathObjectPtr
xmlXPathNewString(const xmlChar * val)5310 xmlXPathNewString(const xmlChar *val) {
5311 xmlXPathObjectPtr ret;
5312
5313 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5314 if (ret == NULL) {
5315 xmlXPathErrMemory(NULL, "creating string object\n");
5316 return(NULL);
5317 }
5318 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5319 ret->type = XPATH_STRING;
5320 if (val != NULL)
5321 ret->stringval = xmlStrdup(val);
5322 else
5323 ret->stringval = xmlStrdup((const xmlChar *)"");
5324 #ifdef XP_DEBUG_OBJ_USAGE
5325 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5326 #endif
5327 return(ret);
5328 }
5329
5330 /**
5331 * xmlXPathWrapString:
5332 * @val: the xmlChar * value
5333 *
5334 * Wraps the @val string into an XPath object.
5335 *
5336 * Returns the newly created object.
5337 */
5338 xmlXPathObjectPtr
xmlXPathWrapString(xmlChar * val)5339 xmlXPathWrapString (xmlChar *val) {
5340 xmlXPathObjectPtr ret;
5341
5342 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5343 if (ret == NULL) {
5344 xmlXPathErrMemory(NULL, "creating string object\n");
5345 return(NULL);
5346 }
5347 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5348 ret->type = XPATH_STRING;
5349 ret->stringval = val;
5350 #ifdef XP_DEBUG_OBJ_USAGE
5351 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5352 #endif
5353 return(ret);
5354 }
5355
5356 /**
5357 * xmlXPathNewCString:
5358 * @val: the char * value
5359 *
5360 * Create a new xmlXPathObjectPtr of type string and of value @val
5361 *
5362 * Returns the newly created object.
5363 */
5364 xmlXPathObjectPtr
xmlXPathNewCString(const char * val)5365 xmlXPathNewCString(const char *val) {
5366 xmlXPathObjectPtr ret;
5367
5368 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5369 if (ret == NULL) {
5370 xmlXPathErrMemory(NULL, "creating string object\n");
5371 return(NULL);
5372 }
5373 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5374 ret->type = XPATH_STRING;
5375 ret->stringval = xmlStrdup(BAD_CAST val);
5376 #ifdef XP_DEBUG_OBJ_USAGE
5377 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5378 #endif
5379 return(ret);
5380 }
5381
5382 /**
5383 * xmlXPathWrapCString:
5384 * @val: the char * value
5385 *
5386 * Wraps a string into an XPath object.
5387 *
5388 * Returns the newly created object.
5389 */
5390 xmlXPathObjectPtr
xmlXPathWrapCString(char * val)5391 xmlXPathWrapCString (char * val) {
5392 return(xmlXPathWrapString((xmlChar *)(val)));
5393 }
5394
5395 /**
5396 * xmlXPathWrapExternal:
5397 * @val: the user data
5398 *
5399 * Wraps the @val data into an XPath object.
5400 *
5401 * Returns the newly created object.
5402 */
5403 xmlXPathObjectPtr
xmlXPathWrapExternal(void * val)5404 xmlXPathWrapExternal (void *val) {
5405 xmlXPathObjectPtr ret;
5406
5407 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5408 if (ret == NULL) {
5409 xmlXPathErrMemory(NULL, "creating user object\n");
5410 return(NULL);
5411 }
5412 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5413 ret->type = XPATH_USERS;
5414 ret->user = val;
5415 #ifdef XP_DEBUG_OBJ_USAGE
5416 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5417 #endif
5418 return(ret);
5419 }
5420
5421 /**
5422 * xmlXPathObjectCopy:
5423 * @val: the original object
5424 *
5425 * allocate a new copy of a given object
5426 *
5427 * Returns the newly created object.
5428 */
5429 xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val)5430 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5431 xmlXPathObjectPtr ret;
5432
5433 if (val == NULL)
5434 return(NULL);
5435
5436 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5437 if (ret == NULL) {
5438 xmlXPathErrMemory(NULL, "copying object\n");
5439 return(NULL);
5440 }
5441 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5442 #ifdef XP_DEBUG_OBJ_USAGE
5443 xmlXPathDebugObjUsageRequested(NULL, val->type);
5444 #endif
5445 switch (val->type) {
5446 case XPATH_BOOLEAN:
5447 case XPATH_NUMBER:
5448 case XPATH_POINT:
5449 case XPATH_RANGE:
5450 break;
5451 case XPATH_STRING:
5452 ret->stringval = xmlStrdup(val->stringval);
5453 break;
5454 case XPATH_XSLT_TREE:
5455 #if 0
5456 /*
5457 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5458 this previous handling is no longer correct, and can cause some serious
5459 problems (ref. bug 145547)
5460 */
5461 if ((val->nodesetval != NULL) &&
5462 (val->nodesetval->nodeTab != NULL)) {
5463 xmlNodePtr cur, tmp;
5464 xmlDocPtr top;
5465
5466 ret->boolval = 1;
5467 top = xmlNewDoc(NULL);
5468 top->name = (char *)
5469 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5470 ret->user = top;
5471 if (top != NULL) {
5472 top->doc = top;
5473 cur = val->nodesetval->nodeTab[0]->children;
5474 while (cur != NULL) {
5475 tmp = xmlDocCopyNode(cur, top, 1);
5476 xmlAddChild((xmlNodePtr) top, tmp);
5477 cur = cur->next;
5478 }
5479 }
5480
5481 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5482 } else
5483 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5484 /* Deallocate the copied tree value */
5485 break;
5486 #endif
5487 case XPATH_NODESET:
5488 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5489 /* Do not deallocate the copied tree value */
5490 ret->boolval = 0;
5491 break;
5492 case XPATH_LOCATIONSET:
5493 #ifdef LIBXML_XPTR_ENABLED
5494 {
5495 xmlLocationSetPtr loc = val->user;
5496 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5497 break;
5498 }
5499 #endif
5500 case XPATH_USERS:
5501 ret->user = val->user;
5502 break;
5503 case XPATH_UNDEFINED:
5504 xmlGenericError(xmlGenericErrorContext,
5505 "xmlXPathObjectCopy: unsupported type %d\n",
5506 val->type);
5507 break;
5508 }
5509 return(ret);
5510 }
5511
5512 /**
5513 * xmlXPathFreeObject:
5514 * @obj: the object to free
5515 *
5516 * Free up an xmlXPathObjectPtr object.
5517 */
5518 void
xmlXPathFreeObject(xmlXPathObjectPtr obj)5519 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5520 if (obj == NULL) return;
5521 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5522 if (obj->boolval) {
5523 #if 0
5524 if (obj->user != NULL) {
5525 xmlXPathFreeNodeSet(obj->nodesetval);
5526 xmlFreeNodeList((xmlNodePtr) obj->user);
5527 } else
5528 #endif
5529 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5530 if (obj->nodesetval != NULL)
5531 xmlXPathFreeValueTree(obj->nodesetval);
5532 } else {
5533 if (obj->nodesetval != NULL)
5534 xmlXPathFreeNodeSet(obj->nodesetval);
5535 }
5536 #ifdef LIBXML_XPTR_ENABLED
5537 } else if (obj->type == XPATH_LOCATIONSET) {
5538 if (obj->user != NULL)
5539 xmlXPtrFreeLocationSet(obj->user);
5540 #endif
5541 } else if (obj->type == XPATH_STRING) {
5542 if (obj->stringval != NULL)
5543 xmlFree(obj->stringval);
5544 }
5545 #ifdef XP_DEBUG_OBJ_USAGE
5546 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5547 #endif
5548 xmlFree(obj);
5549 }
5550
5551 static void
xmlXPathFreeObjectEntry(void * obj,const xmlChar * name ATTRIBUTE_UNUSED)5552 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5553 xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5554 }
5555
5556 /**
5557 * xmlXPathReleaseObject:
5558 * @obj: the xmlXPathObjectPtr to free or to cache
5559 *
5560 * Depending on the state of the cache this frees the given
5561 * XPath object or stores it in the cache.
5562 */
5563 static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt,xmlXPathObjectPtr obj)5564 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5565 {
5566 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5567 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5568 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5569
5570 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5571
5572 if (obj == NULL)
5573 return;
5574 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5575 xmlXPathFreeObject(obj);
5576 } else {
5577 xmlXPathContextCachePtr cache =
5578 (xmlXPathContextCachePtr) ctxt->cache;
5579
5580 switch (obj->type) {
5581 case XPATH_NODESET:
5582 case XPATH_XSLT_TREE:
5583 if (obj->nodesetval != NULL) {
5584 if (obj->boolval) {
5585 /*
5586 * It looks like the @boolval is used for
5587 * evaluation if this an XSLT Result Tree Fragment.
5588 * TODO: Check if this assumption is correct.
5589 */
5590 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5591 xmlXPathFreeValueTree(obj->nodesetval);
5592 obj->nodesetval = NULL;
5593 } else if ((obj->nodesetval->nodeMax <= 40) &&
5594 (XP_CACHE_WANTS(cache->nodesetObjs,
5595 cache->maxNodeset)))
5596 {
5597 XP_CACHE_ADD(cache->nodesetObjs, obj);
5598 goto obj_cached;
5599 } else {
5600 xmlXPathFreeNodeSet(obj->nodesetval);
5601 obj->nodesetval = NULL;
5602 }
5603 }
5604 break;
5605 case XPATH_STRING:
5606 if (obj->stringval != NULL)
5607 xmlFree(obj->stringval);
5608
5609 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5610 XP_CACHE_ADD(cache->stringObjs, obj);
5611 goto obj_cached;
5612 }
5613 break;
5614 case XPATH_BOOLEAN:
5615 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5616 XP_CACHE_ADD(cache->booleanObjs, obj);
5617 goto obj_cached;
5618 }
5619 break;
5620 case XPATH_NUMBER:
5621 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5622 XP_CACHE_ADD(cache->numberObjs, obj);
5623 goto obj_cached;
5624 }
5625 break;
5626 #ifdef LIBXML_XPTR_ENABLED
5627 case XPATH_LOCATIONSET:
5628 if (obj->user != NULL) {
5629 xmlXPtrFreeLocationSet(obj->user);
5630 }
5631 goto free_obj;
5632 #endif
5633 default:
5634 goto free_obj;
5635 }
5636
5637 /*
5638 * Fallback to adding to the misc-objects slot.
5639 */
5640 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5641 XP_CACHE_ADD(cache->miscObjs, obj);
5642 } else
5643 goto free_obj;
5644
5645 obj_cached:
5646
5647 #ifdef XP_DEBUG_OBJ_USAGE
5648 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5649 #endif
5650
5651 if (obj->nodesetval != NULL) {
5652 xmlNodeSetPtr tmpset = obj->nodesetval;
5653
5654 /*
5655 * TODO: Due to those nasty ns-nodes, we need to traverse
5656 * the list and free the ns-nodes.
5657 * URGENT TODO: Check if it's actually slowing things down.
5658 * Maybe we shouldn't try to preserve the list.
5659 */
5660 if (tmpset->nodeNr > 1) {
5661 int i;
5662 xmlNodePtr node;
5663
5664 for (i = 0; i < tmpset->nodeNr; i++) {
5665 node = tmpset->nodeTab[i];
5666 if ((node != NULL) &&
5667 (node->type == XML_NAMESPACE_DECL))
5668 {
5669 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5670 }
5671 }
5672 } else if (tmpset->nodeNr == 1) {
5673 if ((tmpset->nodeTab[0] != NULL) &&
5674 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5675 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5676 }
5677 tmpset->nodeNr = 0;
5678 memset(obj, 0, sizeof(xmlXPathObject));
5679 obj->nodesetval = tmpset;
5680 } else
5681 memset(obj, 0, sizeof(xmlXPathObject));
5682
5683 return;
5684
5685 free_obj:
5686 /*
5687 * Cache is full; free the object.
5688 */
5689 if (obj->nodesetval != NULL)
5690 xmlXPathFreeNodeSet(obj->nodesetval);
5691 #ifdef XP_DEBUG_OBJ_USAGE
5692 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5693 #endif
5694 xmlFree(obj);
5695 }
5696 return;
5697 }
5698
5699
5700 /************************************************************************
5701 * *
5702 * Type Casting Routines *
5703 * *
5704 ************************************************************************/
5705
5706 /**
5707 * xmlXPathCastBooleanToString:
5708 * @val: a boolean
5709 *
5710 * Converts a boolean to its string value.
5711 *
5712 * Returns a newly allocated string.
5713 */
5714 xmlChar *
xmlXPathCastBooleanToString(int val)5715 xmlXPathCastBooleanToString (int val) {
5716 xmlChar *ret;
5717 if (val)
5718 ret = xmlStrdup((const xmlChar *) "true");
5719 else
5720 ret = xmlStrdup((const xmlChar *) "false");
5721 return(ret);
5722 }
5723
5724 /**
5725 * xmlXPathCastNumberToString:
5726 * @val: a number
5727 *
5728 * Converts a number to its string value.
5729 *
5730 * Returns a newly allocated string.
5731 */
5732 xmlChar *
xmlXPathCastNumberToString(double val)5733 xmlXPathCastNumberToString (double val) {
5734 xmlChar *ret;
5735 switch (xmlXPathIsInf(val)) {
5736 case 1:
5737 ret = xmlStrdup((const xmlChar *) "Infinity");
5738 break;
5739 case -1:
5740 ret = xmlStrdup((const xmlChar *) "-Infinity");
5741 break;
5742 default:
5743 if (xmlXPathIsNaN(val)) {
5744 ret = xmlStrdup((const xmlChar *) "NaN");
5745 } else if (val == 0) {
5746 /* Omit sign for negative zero. */
5747 ret = xmlStrdup((const xmlChar *) "0");
5748 } else {
5749 /* could be improved */
5750 char buf[100];
5751 xmlXPathFormatNumber(val, buf, 99);
5752 buf[99] = 0;
5753 ret = xmlStrdup((const xmlChar *) buf);
5754 }
5755 }
5756 return(ret);
5757 }
5758
5759 /**
5760 * xmlXPathCastNodeToString:
5761 * @node: a node
5762 *
5763 * Converts a node to its string value.
5764 *
5765 * Returns a newly allocated string.
5766 */
5767 xmlChar *
xmlXPathCastNodeToString(xmlNodePtr node)5768 xmlXPathCastNodeToString (xmlNodePtr node) {
5769 xmlChar *ret;
5770 if ((ret = xmlNodeGetContent(node)) == NULL)
5771 ret = xmlStrdup((const xmlChar *) "");
5772 return(ret);
5773 }
5774
5775 /**
5776 * xmlXPathCastNodeSetToString:
5777 * @ns: a node-set
5778 *
5779 * Converts a node-set to its string value.
5780 *
5781 * Returns a newly allocated string.
5782 */
5783 xmlChar *
xmlXPathCastNodeSetToString(xmlNodeSetPtr ns)5784 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5785 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5786 return(xmlStrdup((const xmlChar *) ""));
5787
5788 if (ns->nodeNr > 1)
5789 xmlXPathNodeSetSort(ns);
5790 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5791 }
5792
5793 /**
5794 * xmlXPathCastToString:
5795 * @val: an XPath object
5796 *
5797 * Converts an existing object to its string() equivalent
5798 *
5799 * Returns the allocated string value of the object, NULL in case of error.
5800 * It's up to the caller to free the string memory with xmlFree().
5801 */
5802 xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val)5803 xmlXPathCastToString(xmlXPathObjectPtr val) {
5804 xmlChar *ret = NULL;
5805
5806 if (val == NULL)
5807 return(xmlStrdup((const xmlChar *) ""));
5808 switch (val->type) {
5809 case XPATH_UNDEFINED:
5810 #ifdef DEBUG_EXPR
5811 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5812 #endif
5813 ret = xmlStrdup((const xmlChar *) "");
5814 break;
5815 case XPATH_NODESET:
5816 case XPATH_XSLT_TREE:
5817 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5818 break;
5819 case XPATH_STRING:
5820 return(xmlStrdup(val->stringval));
5821 case XPATH_BOOLEAN:
5822 ret = xmlXPathCastBooleanToString(val->boolval);
5823 break;
5824 case XPATH_NUMBER: {
5825 ret = xmlXPathCastNumberToString(val->floatval);
5826 break;
5827 }
5828 case XPATH_USERS:
5829 case XPATH_POINT:
5830 case XPATH_RANGE:
5831 case XPATH_LOCATIONSET:
5832 TODO
5833 ret = xmlStrdup((const xmlChar *) "");
5834 break;
5835 }
5836 return(ret);
5837 }
5838
5839 /**
5840 * xmlXPathConvertString:
5841 * @val: an XPath object
5842 *
5843 * Converts an existing object to its string() equivalent
5844 *
5845 * Returns the new object, the old one is freed (or the operation
5846 * is done directly on @val)
5847 */
5848 xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val)5849 xmlXPathConvertString(xmlXPathObjectPtr val) {
5850 xmlChar *res = NULL;
5851
5852 if (val == NULL)
5853 return(xmlXPathNewCString(""));
5854
5855 switch (val->type) {
5856 case XPATH_UNDEFINED:
5857 #ifdef DEBUG_EXPR
5858 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5859 #endif
5860 break;
5861 case XPATH_NODESET:
5862 case XPATH_XSLT_TREE:
5863 res = xmlXPathCastNodeSetToString(val->nodesetval);
5864 break;
5865 case XPATH_STRING:
5866 return(val);
5867 case XPATH_BOOLEAN:
5868 res = xmlXPathCastBooleanToString(val->boolval);
5869 break;
5870 case XPATH_NUMBER:
5871 res = xmlXPathCastNumberToString(val->floatval);
5872 break;
5873 case XPATH_USERS:
5874 case XPATH_POINT:
5875 case XPATH_RANGE:
5876 case XPATH_LOCATIONSET:
5877 TODO;
5878 break;
5879 }
5880 xmlXPathFreeObject(val);
5881 if (res == NULL)
5882 return(xmlXPathNewCString(""));
5883 return(xmlXPathWrapString(res));
5884 }
5885
5886 /**
5887 * xmlXPathCastBooleanToNumber:
5888 * @val: a boolean
5889 *
5890 * Converts a boolean to its number value
5891 *
5892 * Returns the number value
5893 */
5894 double
xmlXPathCastBooleanToNumber(int val)5895 xmlXPathCastBooleanToNumber(int val) {
5896 if (val)
5897 return(1.0);
5898 return(0.0);
5899 }
5900
5901 /**
5902 * xmlXPathCastStringToNumber:
5903 * @val: a string
5904 *
5905 * Converts a string to its number value
5906 *
5907 * Returns the number value
5908 */
5909 double
xmlXPathCastStringToNumber(const xmlChar * val)5910 xmlXPathCastStringToNumber(const xmlChar * val) {
5911 return(xmlXPathStringEvalNumber(val));
5912 }
5913
5914 /**
5915 * xmlXPathCastNodeToNumber:
5916 * @node: a node
5917 *
5918 * Converts a node to its number value
5919 *
5920 * Returns the number value
5921 */
5922 double
xmlXPathCastNodeToNumber(xmlNodePtr node)5923 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5924 xmlChar *strval;
5925 double ret;
5926
5927 if (node == NULL)
5928 return(NAN);
5929 strval = xmlXPathCastNodeToString(node);
5930 if (strval == NULL)
5931 return(NAN);
5932 ret = xmlXPathCastStringToNumber(strval);
5933 xmlFree(strval);
5934
5935 return(ret);
5936 }
5937
5938 /**
5939 * xmlXPathCastNodeSetToNumber:
5940 * @ns: a node-set
5941 *
5942 * Converts a node-set to its number value
5943 *
5944 * Returns the number value
5945 */
5946 double
xmlXPathCastNodeSetToNumber(xmlNodeSetPtr ns)5947 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5948 xmlChar *str;
5949 double ret;
5950
5951 if (ns == NULL)
5952 return(NAN);
5953 str = xmlXPathCastNodeSetToString(ns);
5954 ret = xmlXPathCastStringToNumber(str);
5955 xmlFree(str);
5956 return(ret);
5957 }
5958
5959 /**
5960 * xmlXPathCastToNumber:
5961 * @val: an XPath object
5962 *
5963 * Converts an XPath object to its number value
5964 *
5965 * Returns the number value
5966 */
5967 double
xmlXPathCastToNumber(xmlXPathObjectPtr val)5968 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5969 double ret = 0.0;
5970
5971 if (val == NULL)
5972 return(NAN);
5973 switch (val->type) {
5974 case XPATH_UNDEFINED:
5975 #ifdef DEGUB_EXPR
5976 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5977 #endif
5978 ret = NAN;
5979 break;
5980 case XPATH_NODESET:
5981 case XPATH_XSLT_TREE:
5982 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5983 break;
5984 case XPATH_STRING:
5985 ret = xmlXPathCastStringToNumber(val->stringval);
5986 break;
5987 case XPATH_NUMBER:
5988 ret = val->floatval;
5989 break;
5990 case XPATH_BOOLEAN:
5991 ret = xmlXPathCastBooleanToNumber(val->boolval);
5992 break;
5993 case XPATH_USERS:
5994 case XPATH_POINT:
5995 case XPATH_RANGE:
5996 case XPATH_LOCATIONSET:
5997 TODO;
5998 ret = NAN;
5999 break;
6000 }
6001 return(ret);
6002 }
6003
6004 /**
6005 * xmlXPathConvertNumber:
6006 * @val: an XPath object
6007 *
6008 * Converts an existing object to its number() equivalent
6009 *
6010 * Returns the new object, the old one is freed (or the operation
6011 * is done directly on @val)
6012 */
6013 xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val)6014 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
6015 xmlXPathObjectPtr ret;
6016
6017 if (val == NULL)
6018 return(xmlXPathNewFloat(0.0));
6019 if (val->type == XPATH_NUMBER)
6020 return(val);
6021 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6022 xmlXPathFreeObject(val);
6023 return(ret);
6024 }
6025
6026 /**
6027 * xmlXPathCastNumberToBoolean:
6028 * @val: a number
6029 *
6030 * Converts a number to its boolean value
6031 *
6032 * Returns the boolean value
6033 */
6034 int
xmlXPathCastNumberToBoolean(double val)6035 xmlXPathCastNumberToBoolean (double val) {
6036 if (xmlXPathIsNaN(val) || (val == 0.0))
6037 return(0);
6038 return(1);
6039 }
6040
6041 /**
6042 * xmlXPathCastStringToBoolean:
6043 * @val: a string
6044 *
6045 * Converts a string to its boolean value
6046 *
6047 * Returns the boolean value
6048 */
6049 int
xmlXPathCastStringToBoolean(const xmlChar * val)6050 xmlXPathCastStringToBoolean (const xmlChar *val) {
6051 if ((val == NULL) || (xmlStrlen(val) == 0))
6052 return(0);
6053 return(1);
6054 }
6055
6056 /**
6057 * xmlXPathCastNodeSetToBoolean:
6058 * @ns: a node-set
6059 *
6060 * Converts a node-set to its boolean value
6061 *
6062 * Returns the boolean value
6063 */
6064 int
xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns)6065 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6066 if ((ns == NULL) || (ns->nodeNr == 0))
6067 return(0);
6068 return(1);
6069 }
6070
6071 /**
6072 * xmlXPathCastToBoolean:
6073 * @val: an XPath object
6074 *
6075 * Converts an XPath object to its boolean value
6076 *
6077 * Returns the boolean value
6078 */
6079 int
xmlXPathCastToBoolean(xmlXPathObjectPtr val)6080 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6081 int ret = 0;
6082
6083 if (val == NULL)
6084 return(0);
6085 switch (val->type) {
6086 case XPATH_UNDEFINED:
6087 #ifdef DEBUG_EXPR
6088 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6089 #endif
6090 ret = 0;
6091 break;
6092 case XPATH_NODESET:
6093 case XPATH_XSLT_TREE:
6094 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6095 break;
6096 case XPATH_STRING:
6097 ret = xmlXPathCastStringToBoolean(val->stringval);
6098 break;
6099 case XPATH_NUMBER:
6100 ret = xmlXPathCastNumberToBoolean(val->floatval);
6101 break;
6102 case XPATH_BOOLEAN:
6103 ret = val->boolval;
6104 break;
6105 case XPATH_USERS:
6106 case XPATH_POINT:
6107 case XPATH_RANGE:
6108 case XPATH_LOCATIONSET:
6109 TODO;
6110 ret = 0;
6111 break;
6112 }
6113 return(ret);
6114 }
6115
6116
6117 /**
6118 * xmlXPathConvertBoolean:
6119 * @val: an XPath object
6120 *
6121 * Converts an existing object to its boolean() equivalent
6122 *
6123 * Returns the new object, the old one is freed (or the operation
6124 * is done directly on @val)
6125 */
6126 xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val)6127 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6128 xmlXPathObjectPtr ret;
6129
6130 if (val == NULL)
6131 return(xmlXPathNewBoolean(0));
6132 if (val->type == XPATH_BOOLEAN)
6133 return(val);
6134 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6135 xmlXPathFreeObject(val);
6136 return(ret);
6137 }
6138
6139 /************************************************************************
6140 * *
6141 * Routines to handle XPath contexts *
6142 * *
6143 ************************************************************************/
6144
6145 /**
6146 * xmlXPathNewContext:
6147 * @doc: the XML document
6148 *
6149 * Create a new xmlXPathContext
6150 *
6151 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6152 */
6153 xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc)6154 xmlXPathNewContext(xmlDocPtr doc) {
6155 xmlXPathContextPtr ret;
6156
6157 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6158 if (ret == NULL) {
6159 xmlXPathErrMemory(NULL, "creating context\n");
6160 return(NULL);
6161 }
6162 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6163 ret->doc = doc;
6164 ret->node = NULL;
6165
6166 ret->varHash = NULL;
6167
6168 ret->nb_types = 0;
6169 ret->max_types = 0;
6170 ret->types = NULL;
6171
6172 ret->funcHash = xmlHashCreate(0);
6173
6174 ret->nb_axis = 0;
6175 ret->max_axis = 0;
6176 ret->axis = NULL;
6177
6178 ret->nsHash = NULL;
6179 ret->user = NULL;
6180
6181 ret->contextSize = -1;
6182 ret->proximityPosition = -1;
6183
6184 #ifdef XP_DEFAULT_CACHE_ON
6185 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6186 xmlXPathFreeContext(ret);
6187 return(NULL);
6188 }
6189 #endif
6190
6191 xmlXPathRegisterAllFunctions(ret);
6192
6193 return(ret);
6194 }
6195
6196 /**
6197 * xmlXPathFreeContext:
6198 * @ctxt: the context to free
6199 *
6200 * Free up an xmlXPathContext
6201 */
6202 void
xmlXPathFreeContext(xmlXPathContextPtr ctxt)6203 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6204 if (ctxt == NULL) return;
6205
6206 if (ctxt->cache != NULL)
6207 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6208 xmlXPathRegisteredNsCleanup(ctxt);
6209 xmlXPathRegisteredFuncsCleanup(ctxt);
6210 xmlXPathRegisteredVariablesCleanup(ctxt);
6211 xmlResetError(&ctxt->lastError);
6212 xmlFree(ctxt);
6213 }
6214
6215 /************************************************************************
6216 * *
6217 * Routines to handle XPath parser contexts *
6218 * *
6219 ************************************************************************/
6220
6221 #define CHECK_CTXT(ctxt) \
6222 if (ctxt == NULL) { \
6223 __xmlRaiseError(NULL, NULL, NULL, \
6224 NULL, NULL, XML_FROM_XPATH, \
6225 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6226 __FILE__, __LINE__, \
6227 NULL, NULL, NULL, 0, 0, \
6228 "NULL context pointer\n"); \
6229 return(NULL); \
6230 } \
6231
6232 #define CHECK_CTXT_NEG(ctxt) \
6233 if (ctxt == NULL) { \
6234 __xmlRaiseError(NULL, NULL, NULL, \
6235 NULL, NULL, XML_FROM_XPATH, \
6236 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6237 __FILE__, __LINE__, \
6238 NULL, NULL, NULL, 0, 0, \
6239 "NULL context pointer\n"); \
6240 return(-1); \
6241 } \
6242
6243
6244 #define CHECK_CONTEXT(ctxt) \
6245 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6246 (ctxt->doc->children == NULL)) { \
6247 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6248 return(NULL); \
6249 }
6250
6251
6252 /**
6253 * xmlXPathNewParserContext:
6254 * @str: the XPath expression
6255 * @ctxt: the XPath context
6256 *
6257 * Create a new xmlXPathParserContext
6258 *
6259 * Returns the xmlXPathParserContext just allocated.
6260 */
6261 xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar * str,xmlXPathContextPtr ctxt)6262 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6263 xmlXPathParserContextPtr ret;
6264
6265 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6266 if (ret == NULL) {
6267 xmlXPathErrMemory(ctxt, "creating parser context\n");
6268 return(NULL);
6269 }
6270 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6271 ret->cur = ret->base = str;
6272 ret->context = ctxt;
6273
6274 ret->comp = xmlXPathNewCompExpr();
6275 if (ret->comp == NULL) {
6276 xmlFree(ret->valueTab);
6277 xmlFree(ret);
6278 return(NULL);
6279 }
6280 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6281 ret->comp->dict = ctxt->dict;
6282 xmlDictReference(ret->comp->dict);
6283 }
6284
6285 return(ret);
6286 }
6287
6288 /**
6289 * xmlXPathCompParserContext:
6290 * @comp: the XPath compiled expression
6291 * @ctxt: the XPath context
6292 *
6293 * Create a new xmlXPathParserContext when processing a compiled expression
6294 *
6295 * Returns the xmlXPathParserContext just allocated.
6296 */
6297 static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)6298 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6299 xmlXPathParserContextPtr ret;
6300
6301 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6302 if (ret == NULL) {
6303 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6304 return(NULL);
6305 }
6306 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6307
6308 /* Allocate the value stack */
6309 ret->valueTab = (xmlXPathObjectPtr *)
6310 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6311 if (ret->valueTab == NULL) {
6312 xmlFree(ret);
6313 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6314 return(NULL);
6315 }
6316 ret->valueNr = 0;
6317 ret->valueMax = 10;
6318 ret->value = NULL;
6319 ret->valueFrame = 0;
6320
6321 ret->context = ctxt;
6322 ret->comp = comp;
6323
6324 return(ret);
6325 }
6326
6327 /**
6328 * xmlXPathFreeParserContext:
6329 * @ctxt: the context to free
6330 *
6331 * Free up an xmlXPathParserContext
6332 */
6333 void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt)6334 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6335 int i;
6336
6337 if (ctxt->valueTab != NULL) {
6338 for (i = 0; i < ctxt->valueNr; i++) {
6339 if (ctxt->context)
6340 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6341 else
6342 xmlXPathFreeObject(ctxt->valueTab[i]);
6343 }
6344 xmlFree(ctxt->valueTab);
6345 }
6346 if (ctxt->comp != NULL) {
6347 #ifdef XPATH_STREAMING
6348 if (ctxt->comp->stream != NULL) {
6349 xmlFreePatternList(ctxt->comp->stream);
6350 ctxt->comp->stream = NULL;
6351 }
6352 #endif
6353 xmlXPathFreeCompExpr(ctxt->comp);
6354 }
6355 xmlFree(ctxt);
6356 }
6357
6358 /************************************************************************
6359 * *
6360 * The implicit core function library *
6361 * *
6362 ************************************************************************/
6363
6364 /**
6365 * xmlXPathNodeValHash:
6366 * @node: a node pointer
6367 *
6368 * Function computing the beginning of the string value of the node,
6369 * used to speed up comparisons
6370 *
6371 * Returns an int usable as a hash
6372 */
6373 static unsigned int
xmlXPathNodeValHash(xmlNodePtr node)6374 xmlXPathNodeValHash(xmlNodePtr node) {
6375 int len = 2;
6376 const xmlChar * string = NULL;
6377 xmlNodePtr tmp = NULL;
6378 unsigned int ret = 0;
6379
6380 if (node == NULL)
6381 return(0);
6382
6383 if (node->type == XML_DOCUMENT_NODE) {
6384 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6385 if (tmp == NULL)
6386 node = node->children;
6387 else
6388 node = tmp;
6389
6390 if (node == NULL)
6391 return(0);
6392 }
6393
6394 switch (node->type) {
6395 case XML_COMMENT_NODE:
6396 case XML_PI_NODE:
6397 case XML_CDATA_SECTION_NODE:
6398 case XML_TEXT_NODE:
6399 string = node->content;
6400 if (string == NULL)
6401 return(0);
6402 if (string[0] == 0)
6403 return(0);
6404 return(((unsigned int) string[0]) +
6405 (((unsigned int) string[1]) << 8));
6406 case XML_NAMESPACE_DECL:
6407 string = ((xmlNsPtr)node)->href;
6408 if (string == NULL)
6409 return(0);
6410 if (string[0] == 0)
6411 return(0);
6412 return(((unsigned int) string[0]) +
6413 (((unsigned int) string[1]) << 8));
6414 case XML_ATTRIBUTE_NODE:
6415 tmp = ((xmlAttrPtr) node)->children;
6416 break;
6417 case XML_ELEMENT_NODE:
6418 tmp = node->children;
6419 break;
6420 default:
6421 return(0);
6422 }
6423 while (tmp != NULL) {
6424 switch (tmp->type) {
6425 case XML_CDATA_SECTION_NODE:
6426 case XML_TEXT_NODE:
6427 string = tmp->content;
6428 break;
6429 default:
6430 string = NULL;
6431 break;
6432 }
6433 if ((string != NULL) && (string[0] != 0)) {
6434 if (len == 1) {
6435 return(ret + (((unsigned int) string[0]) << 8));
6436 }
6437 if (string[1] == 0) {
6438 len = 1;
6439 ret = (unsigned int) string[0];
6440 } else {
6441 return(((unsigned int) string[0]) +
6442 (((unsigned int) string[1]) << 8));
6443 }
6444 }
6445 /*
6446 * Skip to next node
6447 */
6448 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6449 if (tmp->children->type != XML_ENTITY_DECL) {
6450 tmp = tmp->children;
6451 continue;
6452 }
6453 }
6454 if (tmp == node)
6455 break;
6456
6457 if (tmp->next != NULL) {
6458 tmp = tmp->next;
6459 continue;
6460 }
6461
6462 do {
6463 tmp = tmp->parent;
6464 if (tmp == NULL)
6465 break;
6466 if (tmp == node) {
6467 tmp = NULL;
6468 break;
6469 }
6470 if (tmp->next != NULL) {
6471 tmp = tmp->next;
6472 break;
6473 }
6474 } while (tmp != NULL);
6475 }
6476 return(ret);
6477 }
6478
6479 /**
6480 * xmlXPathStringHash:
6481 * @string: a string
6482 *
6483 * Function computing the beginning of the string value of the node,
6484 * used to speed up comparisons
6485 *
6486 * Returns an int usable as a hash
6487 */
6488 static unsigned int
xmlXPathStringHash(const xmlChar * string)6489 xmlXPathStringHash(const xmlChar * string) {
6490 if (string == NULL)
6491 return((unsigned int) 0);
6492 if (string[0] == 0)
6493 return(0);
6494 return(((unsigned int) string[0]) +
6495 (((unsigned int) string[1]) << 8));
6496 }
6497
6498 /**
6499 * xmlXPathCompareNodeSetFloat:
6500 * @ctxt: the XPath Parser context
6501 * @inf: less than (1) or greater than (0)
6502 * @strict: is the comparison strict
6503 * @arg: the node set
6504 * @f: the value
6505 *
6506 * Implement the compare operation between a nodeset and a number
6507 * @ns < @val (1, 1, ...
6508 * @ns <= @val (1, 0, ...
6509 * @ns > @val (0, 1, ...
6510 * @ns >= @val (0, 0, ...
6511 *
6512 * If one object to be compared is a node-set and the other is a number,
6513 * then the comparison will be true if and only if there is a node in the
6514 * node-set such that the result of performing the comparison on the number
6515 * to be compared and on the result of converting the string-value of that
6516 * node to a number using the number function is true.
6517 *
6518 * Returns 0 or 1 depending on the results of the test.
6519 */
6520 static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr f)6521 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6522 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6523 int i, ret = 0;
6524 xmlNodeSetPtr ns;
6525 xmlChar *str2;
6526
6527 if ((f == NULL) || (arg == NULL) ||
6528 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6529 xmlXPathReleaseObject(ctxt->context, arg);
6530 xmlXPathReleaseObject(ctxt->context, f);
6531 return(0);
6532 }
6533 ns = arg->nodesetval;
6534 if (ns != NULL) {
6535 for (i = 0;i < ns->nodeNr;i++) {
6536 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6537 if (str2 != NULL) {
6538 valuePush(ctxt,
6539 xmlXPathCacheNewString(ctxt->context, str2));
6540 xmlFree(str2);
6541 xmlXPathNumberFunction(ctxt, 1);
6542 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6543 ret = xmlXPathCompareValues(ctxt, inf, strict);
6544 if (ret)
6545 break;
6546 }
6547 }
6548 }
6549 xmlXPathReleaseObject(ctxt->context, arg);
6550 xmlXPathReleaseObject(ctxt->context, f);
6551 return(ret);
6552 }
6553
6554 /**
6555 * xmlXPathCompareNodeSetString:
6556 * @ctxt: the XPath Parser context
6557 * @inf: less than (1) or greater than (0)
6558 * @strict: is the comparison strict
6559 * @arg: the node set
6560 * @s: the value
6561 *
6562 * Implement the compare operation between a nodeset and a string
6563 * @ns < @val (1, 1, ...
6564 * @ns <= @val (1, 0, ...
6565 * @ns > @val (0, 1, ...
6566 * @ns >= @val (0, 0, ...
6567 *
6568 * If one object to be compared is a node-set and the other is a string,
6569 * then the comparison will be true if and only if there is a node in
6570 * the node-set such that the result of performing the comparison on the
6571 * string-value of the node and the other string is true.
6572 *
6573 * Returns 0 or 1 depending on the results of the test.
6574 */
6575 static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr s)6576 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6577 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6578 int i, ret = 0;
6579 xmlNodeSetPtr ns;
6580 xmlChar *str2;
6581
6582 if ((s == NULL) || (arg == NULL) ||
6583 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6584 xmlXPathReleaseObject(ctxt->context, arg);
6585 xmlXPathReleaseObject(ctxt->context, s);
6586 return(0);
6587 }
6588 ns = arg->nodesetval;
6589 if (ns != NULL) {
6590 for (i = 0;i < ns->nodeNr;i++) {
6591 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6592 if (str2 != NULL) {
6593 valuePush(ctxt,
6594 xmlXPathCacheNewString(ctxt->context, str2));
6595 xmlFree(str2);
6596 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6597 ret = xmlXPathCompareValues(ctxt, inf, strict);
6598 if (ret)
6599 break;
6600 }
6601 }
6602 }
6603 xmlXPathReleaseObject(ctxt->context, arg);
6604 xmlXPathReleaseObject(ctxt->context, s);
6605 return(ret);
6606 }
6607
6608 /**
6609 * xmlXPathCompareNodeSets:
6610 * @inf: less than (1) or greater than (0)
6611 * @strict: is the comparison strict
6612 * @arg1: the first node set object
6613 * @arg2: the second node set object
6614 *
6615 * Implement the compare operation on nodesets:
6616 *
6617 * If both objects to be compared are node-sets, then the comparison
6618 * will be true if and only if there is a node in the first node-set
6619 * and a node in the second node-set such that the result of performing
6620 * the comparison on the string-values of the two nodes is true.
6621 * ....
6622 * When neither object to be compared is a node-set and the operator
6623 * is <=, <, >= or >, then the objects are compared by converting both
6624 * objects to numbers and comparing the numbers according to IEEE 754.
6625 * ....
6626 * The number function converts its argument to a number as follows:
6627 * - a string that consists of optional whitespace followed by an
6628 * optional minus sign followed by a Number followed by whitespace
6629 * is converted to the IEEE 754 number that is nearest (according
6630 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6631 * represented by the string; any other string is converted to NaN
6632 *
6633 * Conclusion all nodes need to be converted first to their string value
6634 * and then the comparison must be done when possible
6635 */
6636 static int
xmlXPathCompareNodeSets(int inf,int strict,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6637 xmlXPathCompareNodeSets(int inf, int strict,
6638 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6639 int i, j, init = 0;
6640 double val1;
6641 double *values2;
6642 int ret = 0;
6643 xmlNodeSetPtr ns1;
6644 xmlNodeSetPtr ns2;
6645
6646 if ((arg1 == NULL) ||
6647 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6648 xmlXPathFreeObject(arg2);
6649 return(0);
6650 }
6651 if ((arg2 == NULL) ||
6652 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6653 xmlXPathFreeObject(arg1);
6654 xmlXPathFreeObject(arg2);
6655 return(0);
6656 }
6657
6658 ns1 = arg1->nodesetval;
6659 ns2 = arg2->nodesetval;
6660
6661 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6662 xmlXPathFreeObject(arg1);
6663 xmlXPathFreeObject(arg2);
6664 return(0);
6665 }
6666 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6667 xmlXPathFreeObject(arg1);
6668 xmlXPathFreeObject(arg2);
6669 return(0);
6670 }
6671
6672 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6673 if (values2 == NULL) {
6674 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6675 xmlXPathFreeObject(arg1);
6676 xmlXPathFreeObject(arg2);
6677 return(0);
6678 }
6679 for (i = 0;i < ns1->nodeNr;i++) {
6680 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6681 if (xmlXPathIsNaN(val1))
6682 continue;
6683 for (j = 0;j < ns2->nodeNr;j++) {
6684 if (init == 0) {
6685 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6686 }
6687 if (xmlXPathIsNaN(values2[j]))
6688 continue;
6689 if (inf && strict)
6690 ret = (val1 < values2[j]);
6691 else if (inf && !strict)
6692 ret = (val1 <= values2[j]);
6693 else if (!inf && strict)
6694 ret = (val1 > values2[j]);
6695 else if (!inf && !strict)
6696 ret = (val1 >= values2[j]);
6697 if (ret)
6698 break;
6699 }
6700 if (ret)
6701 break;
6702 init = 1;
6703 }
6704 xmlFree(values2);
6705 xmlXPathFreeObject(arg1);
6706 xmlXPathFreeObject(arg2);
6707 return(ret);
6708 }
6709
6710 /**
6711 * xmlXPathCompareNodeSetValue:
6712 * @ctxt: the XPath Parser context
6713 * @inf: less than (1) or greater than (0)
6714 * @strict: is the comparison strict
6715 * @arg: the node set
6716 * @val: the value
6717 *
6718 * Implement the compare operation between a nodeset and a value
6719 * @ns < @val (1, 1, ...
6720 * @ns <= @val (1, 0, ...
6721 * @ns > @val (0, 1, ...
6722 * @ns >= @val (0, 0, ...
6723 *
6724 * If one object to be compared is a node-set and the other is a boolean,
6725 * then the comparison will be true if and only if the result of performing
6726 * the comparison on the boolean and on the result of converting
6727 * the node-set to a boolean using the boolean function is true.
6728 *
6729 * Returns 0 or 1 depending on the results of the test.
6730 */
6731 static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt,int inf,int strict,xmlXPathObjectPtr arg,xmlXPathObjectPtr val)6732 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6733 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6734 if ((val == NULL) || (arg == NULL) ||
6735 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6736 return(0);
6737
6738 switch(val->type) {
6739 case XPATH_NUMBER:
6740 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6741 case XPATH_NODESET:
6742 case XPATH_XSLT_TREE:
6743 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6744 case XPATH_STRING:
6745 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6746 case XPATH_BOOLEAN:
6747 valuePush(ctxt, arg);
6748 xmlXPathBooleanFunction(ctxt, 1);
6749 valuePush(ctxt, val);
6750 return(xmlXPathCompareValues(ctxt, inf, strict));
6751 default:
6752 xmlGenericError(xmlGenericErrorContext,
6753 "xmlXPathCompareNodeSetValue: Can't compare node set "
6754 "and object of type %d\n",
6755 val->type);
6756 xmlXPathReleaseObject(ctxt->context, arg);
6757 xmlXPathReleaseObject(ctxt->context, val);
6758 XP_ERROR0(XPATH_INVALID_TYPE);
6759 }
6760 return(0);
6761 }
6762
6763 /**
6764 * xmlXPathEqualNodeSetString:
6765 * @arg: the nodeset object argument
6766 * @str: the string to compare to.
6767 * @neq: flag to show whether for '=' (0) or '!=' (1)
6768 *
6769 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6770 * If one object to be compared is a node-set and the other is a string,
6771 * then the comparison will be true if and only if there is a node in
6772 * the node-set such that the result of performing the comparison on the
6773 * string-value of the node and the other string is true.
6774 *
6775 * Returns 0 or 1 depending on the results of the test.
6776 */
6777 static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg,const xmlChar * str,int neq)6778 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6779 {
6780 int i;
6781 xmlNodeSetPtr ns;
6782 xmlChar *str2;
6783 unsigned int hash;
6784
6785 if ((str == NULL) || (arg == NULL) ||
6786 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6787 return (0);
6788 ns = arg->nodesetval;
6789 /*
6790 * A NULL nodeset compared with a string is always false
6791 * (since there is no node equal, and no node not equal)
6792 */
6793 if ((ns == NULL) || (ns->nodeNr <= 0) )
6794 return (0);
6795 hash = xmlXPathStringHash(str);
6796 for (i = 0; i < ns->nodeNr; i++) {
6797 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6798 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6799 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6800 xmlFree(str2);
6801 if (neq)
6802 continue;
6803 return (1);
6804 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6805 if (neq)
6806 continue;
6807 return (1);
6808 } else if (neq) {
6809 if (str2 != NULL)
6810 xmlFree(str2);
6811 return (1);
6812 }
6813 if (str2 != NULL)
6814 xmlFree(str2);
6815 } else if (neq)
6816 return (1);
6817 }
6818 return (0);
6819 }
6820
6821 /**
6822 * xmlXPathEqualNodeSetFloat:
6823 * @arg: the nodeset object argument
6824 * @f: the float to compare to
6825 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6826 *
6827 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6828 * If one object to be compared is a node-set and the other is a number,
6829 * then the comparison will be true if and only if there is a node in
6830 * the node-set such that the result of performing the comparison on the
6831 * number to be compared and on the result of converting the string-value
6832 * of that node to a number using the number function is true.
6833 *
6834 * Returns 0 or 1 depending on the results of the test.
6835 */
6836 static int
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg,double f,int neq)6837 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6838 xmlXPathObjectPtr arg, double f, int neq) {
6839 int i, ret=0;
6840 xmlNodeSetPtr ns;
6841 xmlChar *str2;
6842 xmlXPathObjectPtr val;
6843 double v;
6844
6845 if ((arg == NULL) ||
6846 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6847 return(0);
6848
6849 ns = arg->nodesetval;
6850 if (ns != NULL) {
6851 for (i=0;i<ns->nodeNr;i++) {
6852 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6853 if (str2 != NULL) {
6854 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6855 xmlFree(str2);
6856 xmlXPathNumberFunction(ctxt, 1);
6857 val = valuePop(ctxt);
6858 v = val->floatval;
6859 xmlXPathReleaseObject(ctxt->context, val);
6860 if (!xmlXPathIsNaN(v)) {
6861 if ((!neq) && (v==f)) {
6862 ret = 1;
6863 break;
6864 } else if ((neq) && (v!=f)) {
6865 ret = 1;
6866 break;
6867 }
6868 } else { /* NaN is unequal to any value */
6869 if (neq)
6870 ret = 1;
6871 }
6872 }
6873 }
6874 }
6875
6876 return(ret);
6877 }
6878
6879
6880 /**
6881 * xmlXPathEqualNodeSets:
6882 * @arg1: first nodeset object argument
6883 * @arg2: second nodeset object argument
6884 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6885 *
6886 * Implement the equal / not equal operation on XPath nodesets:
6887 * @arg1 == @arg2 or @arg1 != @arg2
6888 * If both objects to be compared are node-sets, then the comparison
6889 * will be true if and only if there is a node in the first node-set and
6890 * a node in the second node-set such that the result of performing the
6891 * comparison on the string-values of the two nodes is true.
6892 *
6893 * (needless to say, this is a costly operation)
6894 *
6895 * Returns 0 or 1 depending on the results of the test.
6896 */
6897 static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2,int neq)6898 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6899 int i, j;
6900 unsigned int *hashs1;
6901 unsigned int *hashs2;
6902 xmlChar **values1;
6903 xmlChar **values2;
6904 int ret = 0;
6905 xmlNodeSetPtr ns1;
6906 xmlNodeSetPtr ns2;
6907
6908 if ((arg1 == NULL) ||
6909 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6910 return(0);
6911 if ((arg2 == NULL) ||
6912 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6913 return(0);
6914
6915 ns1 = arg1->nodesetval;
6916 ns2 = arg2->nodesetval;
6917
6918 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6919 return(0);
6920 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6921 return(0);
6922
6923 /*
6924 * for equal, check if there is a node pertaining to both sets
6925 */
6926 if (neq == 0)
6927 for (i = 0;i < ns1->nodeNr;i++)
6928 for (j = 0;j < ns2->nodeNr;j++)
6929 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6930 return(1);
6931
6932 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6933 if (values1 == NULL) {
6934 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6935 return(0);
6936 }
6937 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6938 if (hashs1 == NULL) {
6939 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6940 xmlFree(values1);
6941 return(0);
6942 }
6943 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6944 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6945 if (values2 == NULL) {
6946 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6947 xmlFree(hashs1);
6948 xmlFree(values1);
6949 return(0);
6950 }
6951 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6952 if (hashs2 == NULL) {
6953 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6954 xmlFree(hashs1);
6955 xmlFree(values1);
6956 xmlFree(values2);
6957 return(0);
6958 }
6959 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6960 for (i = 0;i < ns1->nodeNr;i++) {
6961 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6962 for (j = 0;j < ns2->nodeNr;j++) {
6963 if (i == 0)
6964 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6965 if (hashs1[i] != hashs2[j]) {
6966 if (neq) {
6967 ret = 1;
6968 break;
6969 }
6970 }
6971 else {
6972 if (values1[i] == NULL)
6973 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6974 if (values2[j] == NULL)
6975 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6976 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6977 if (ret)
6978 break;
6979 }
6980 }
6981 if (ret)
6982 break;
6983 }
6984 for (i = 0;i < ns1->nodeNr;i++)
6985 if (values1[i] != NULL)
6986 xmlFree(values1[i]);
6987 for (j = 0;j < ns2->nodeNr;j++)
6988 if (values2[j] != NULL)
6989 xmlFree(values2[j]);
6990 xmlFree(values1);
6991 xmlFree(values2);
6992 xmlFree(hashs1);
6993 xmlFree(hashs2);
6994 return(ret);
6995 }
6996
6997 static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr arg1,xmlXPathObjectPtr arg2)6998 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6999 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
7000 int ret = 0;
7001 /*
7002 *At this point we are assured neither arg1 nor arg2
7003 *is a nodeset, so we can just pick the appropriate routine.
7004 */
7005 switch (arg1->type) {
7006 case XPATH_UNDEFINED:
7007 #ifdef DEBUG_EXPR
7008 xmlGenericError(xmlGenericErrorContext,
7009 "Equal: undefined\n");
7010 #endif
7011 break;
7012 case XPATH_BOOLEAN:
7013 switch (arg2->type) {
7014 case XPATH_UNDEFINED:
7015 #ifdef DEBUG_EXPR
7016 xmlGenericError(xmlGenericErrorContext,
7017 "Equal: undefined\n");
7018 #endif
7019 break;
7020 case XPATH_BOOLEAN:
7021 #ifdef DEBUG_EXPR
7022 xmlGenericError(xmlGenericErrorContext,
7023 "Equal: %d boolean %d \n",
7024 arg1->boolval, arg2->boolval);
7025 #endif
7026 ret = (arg1->boolval == arg2->boolval);
7027 break;
7028 case XPATH_NUMBER:
7029 ret = (arg1->boolval ==
7030 xmlXPathCastNumberToBoolean(arg2->floatval));
7031 break;
7032 case XPATH_STRING:
7033 if ((arg2->stringval == NULL) ||
7034 (arg2->stringval[0] == 0)) ret = 0;
7035 else
7036 ret = 1;
7037 ret = (arg1->boolval == ret);
7038 break;
7039 case XPATH_USERS:
7040 case XPATH_POINT:
7041 case XPATH_RANGE:
7042 case XPATH_LOCATIONSET:
7043 TODO
7044 break;
7045 case XPATH_NODESET:
7046 case XPATH_XSLT_TREE:
7047 break;
7048 }
7049 break;
7050 case XPATH_NUMBER:
7051 switch (arg2->type) {
7052 case XPATH_UNDEFINED:
7053 #ifdef DEBUG_EXPR
7054 xmlGenericError(xmlGenericErrorContext,
7055 "Equal: undefined\n");
7056 #endif
7057 break;
7058 case XPATH_BOOLEAN:
7059 ret = (arg2->boolval==
7060 xmlXPathCastNumberToBoolean(arg1->floatval));
7061 break;
7062 case XPATH_STRING:
7063 valuePush(ctxt, arg2);
7064 xmlXPathNumberFunction(ctxt, 1);
7065 arg2 = valuePop(ctxt);
7066 /* Falls through. */
7067 case XPATH_NUMBER:
7068 /* Hand check NaN and Infinity equalities */
7069 if (xmlXPathIsNaN(arg1->floatval) ||
7070 xmlXPathIsNaN(arg2->floatval)) {
7071 ret = 0;
7072 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7073 if (xmlXPathIsInf(arg2->floatval) == 1)
7074 ret = 1;
7075 else
7076 ret = 0;
7077 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7078 if (xmlXPathIsInf(arg2->floatval) == -1)
7079 ret = 1;
7080 else
7081 ret = 0;
7082 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7083 if (xmlXPathIsInf(arg1->floatval) == 1)
7084 ret = 1;
7085 else
7086 ret = 0;
7087 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7088 if (xmlXPathIsInf(arg1->floatval) == -1)
7089 ret = 1;
7090 else
7091 ret = 0;
7092 } else {
7093 ret = (arg1->floatval == arg2->floatval);
7094 }
7095 break;
7096 case XPATH_USERS:
7097 case XPATH_POINT:
7098 case XPATH_RANGE:
7099 case XPATH_LOCATIONSET:
7100 TODO
7101 break;
7102 case XPATH_NODESET:
7103 case XPATH_XSLT_TREE:
7104 break;
7105 }
7106 break;
7107 case XPATH_STRING:
7108 switch (arg2->type) {
7109 case XPATH_UNDEFINED:
7110 #ifdef DEBUG_EXPR
7111 xmlGenericError(xmlGenericErrorContext,
7112 "Equal: undefined\n");
7113 #endif
7114 break;
7115 case XPATH_BOOLEAN:
7116 if ((arg1->stringval == NULL) ||
7117 (arg1->stringval[0] == 0)) ret = 0;
7118 else
7119 ret = 1;
7120 ret = (arg2->boolval == ret);
7121 break;
7122 case XPATH_STRING:
7123 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7124 break;
7125 case XPATH_NUMBER:
7126 valuePush(ctxt, arg1);
7127 xmlXPathNumberFunction(ctxt, 1);
7128 arg1 = valuePop(ctxt);
7129 /* Hand check NaN and Infinity equalities */
7130 if (xmlXPathIsNaN(arg1->floatval) ||
7131 xmlXPathIsNaN(arg2->floatval)) {
7132 ret = 0;
7133 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7134 if (xmlXPathIsInf(arg2->floatval) == 1)
7135 ret = 1;
7136 else
7137 ret = 0;
7138 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7139 if (xmlXPathIsInf(arg2->floatval) == -1)
7140 ret = 1;
7141 else
7142 ret = 0;
7143 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7144 if (xmlXPathIsInf(arg1->floatval) == 1)
7145 ret = 1;
7146 else
7147 ret = 0;
7148 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7149 if (xmlXPathIsInf(arg1->floatval) == -1)
7150 ret = 1;
7151 else
7152 ret = 0;
7153 } else {
7154 ret = (arg1->floatval == arg2->floatval);
7155 }
7156 break;
7157 case XPATH_USERS:
7158 case XPATH_POINT:
7159 case XPATH_RANGE:
7160 case XPATH_LOCATIONSET:
7161 TODO
7162 break;
7163 case XPATH_NODESET:
7164 case XPATH_XSLT_TREE:
7165 break;
7166 }
7167 break;
7168 case XPATH_USERS:
7169 case XPATH_POINT:
7170 case XPATH_RANGE:
7171 case XPATH_LOCATIONSET:
7172 TODO
7173 break;
7174 case XPATH_NODESET:
7175 case XPATH_XSLT_TREE:
7176 break;
7177 }
7178 xmlXPathReleaseObject(ctxt->context, arg1);
7179 xmlXPathReleaseObject(ctxt->context, arg2);
7180 return(ret);
7181 }
7182
7183 /**
7184 * xmlXPathEqualValues:
7185 * @ctxt: the XPath Parser context
7186 *
7187 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7188 *
7189 * Returns 0 or 1 depending on the results of the test.
7190 */
7191 int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt)7192 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7193 xmlXPathObjectPtr arg1, arg2, argtmp;
7194 int ret = 0;
7195
7196 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7197 arg2 = valuePop(ctxt);
7198 arg1 = valuePop(ctxt);
7199 if ((arg1 == NULL) || (arg2 == NULL)) {
7200 if (arg1 != NULL)
7201 xmlXPathReleaseObject(ctxt->context, arg1);
7202 else
7203 xmlXPathReleaseObject(ctxt->context, arg2);
7204 XP_ERROR0(XPATH_INVALID_OPERAND);
7205 }
7206
7207 if (arg1 == arg2) {
7208 #ifdef DEBUG_EXPR
7209 xmlGenericError(xmlGenericErrorContext,
7210 "Equal: by pointer\n");
7211 #endif
7212 xmlXPathFreeObject(arg1);
7213 return(1);
7214 }
7215
7216 /*
7217 *If either argument is a nodeset, it's a 'special case'
7218 */
7219 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7220 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7221 /*
7222 *Hack it to assure arg1 is the nodeset
7223 */
7224 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7225 argtmp = arg2;
7226 arg2 = arg1;
7227 arg1 = argtmp;
7228 }
7229 switch (arg2->type) {
7230 case XPATH_UNDEFINED:
7231 #ifdef DEBUG_EXPR
7232 xmlGenericError(xmlGenericErrorContext,
7233 "Equal: undefined\n");
7234 #endif
7235 break;
7236 case XPATH_NODESET:
7237 case XPATH_XSLT_TREE:
7238 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7239 break;
7240 case XPATH_BOOLEAN:
7241 if ((arg1->nodesetval == NULL) ||
7242 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7243 else
7244 ret = 1;
7245 ret = (ret == arg2->boolval);
7246 break;
7247 case XPATH_NUMBER:
7248 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7249 break;
7250 case XPATH_STRING:
7251 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7252 break;
7253 case XPATH_USERS:
7254 case XPATH_POINT:
7255 case XPATH_RANGE:
7256 case XPATH_LOCATIONSET:
7257 TODO
7258 break;
7259 }
7260 xmlXPathReleaseObject(ctxt->context, arg1);
7261 xmlXPathReleaseObject(ctxt->context, arg2);
7262 return(ret);
7263 }
7264
7265 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7266 }
7267
7268 /**
7269 * xmlXPathNotEqualValues:
7270 * @ctxt: the XPath Parser context
7271 *
7272 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7273 *
7274 * Returns 0 or 1 depending on the results of the test.
7275 */
7276 int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt)7277 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7278 xmlXPathObjectPtr arg1, arg2, argtmp;
7279 int ret = 0;
7280
7281 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7282 arg2 = valuePop(ctxt);
7283 arg1 = valuePop(ctxt);
7284 if ((arg1 == NULL) || (arg2 == NULL)) {
7285 if (arg1 != NULL)
7286 xmlXPathReleaseObject(ctxt->context, arg1);
7287 else
7288 xmlXPathReleaseObject(ctxt->context, arg2);
7289 XP_ERROR0(XPATH_INVALID_OPERAND);
7290 }
7291
7292 if (arg1 == arg2) {
7293 #ifdef DEBUG_EXPR
7294 xmlGenericError(xmlGenericErrorContext,
7295 "NotEqual: by pointer\n");
7296 #endif
7297 xmlXPathReleaseObject(ctxt->context, arg1);
7298 return(0);
7299 }
7300
7301 /*
7302 *If either argument is a nodeset, it's a 'special case'
7303 */
7304 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7305 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7306 /*
7307 *Hack it to assure arg1 is the nodeset
7308 */
7309 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7310 argtmp = arg2;
7311 arg2 = arg1;
7312 arg1 = argtmp;
7313 }
7314 switch (arg2->type) {
7315 case XPATH_UNDEFINED:
7316 #ifdef DEBUG_EXPR
7317 xmlGenericError(xmlGenericErrorContext,
7318 "NotEqual: undefined\n");
7319 #endif
7320 break;
7321 case XPATH_NODESET:
7322 case XPATH_XSLT_TREE:
7323 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7324 break;
7325 case XPATH_BOOLEAN:
7326 if ((arg1->nodesetval == NULL) ||
7327 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7328 else
7329 ret = 1;
7330 ret = (ret != arg2->boolval);
7331 break;
7332 case XPATH_NUMBER:
7333 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7334 break;
7335 case XPATH_STRING:
7336 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7337 break;
7338 case XPATH_USERS:
7339 case XPATH_POINT:
7340 case XPATH_RANGE:
7341 case XPATH_LOCATIONSET:
7342 TODO
7343 break;
7344 }
7345 xmlXPathReleaseObject(ctxt->context, arg1);
7346 xmlXPathReleaseObject(ctxt->context, arg2);
7347 return(ret);
7348 }
7349
7350 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7351 }
7352
7353 /**
7354 * xmlXPathCompareValues:
7355 * @ctxt: the XPath Parser context
7356 * @inf: less than (1) or greater than (0)
7357 * @strict: is the comparison strict
7358 *
7359 * Implement the compare operation on XPath objects:
7360 * @arg1 < @arg2 (1, 1, ...
7361 * @arg1 <= @arg2 (1, 0, ...
7362 * @arg1 > @arg2 (0, 1, ...
7363 * @arg1 >= @arg2 (0, 0, ...
7364 *
7365 * When neither object to be compared is a node-set and the operator is
7366 * <=, <, >=, >, then the objects are compared by converted both objects
7367 * to numbers and comparing the numbers according to IEEE 754. The <
7368 * comparison will be true if and only if the first number is less than the
7369 * second number. The <= comparison will be true if and only if the first
7370 * number is less than or equal to the second number. The > comparison
7371 * will be true if and only if the first number is greater than the second
7372 * number. The >= comparison will be true if and only if the first number
7373 * is greater than or equal to the second number.
7374 *
7375 * Returns 1 if the comparison succeeded, 0 if it failed
7376 */
7377 int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt,int inf,int strict)7378 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7379 int ret = 0, arg1i = 0, arg2i = 0;
7380 xmlXPathObjectPtr arg1, arg2;
7381
7382 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7383 arg2 = valuePop(ctxt);
7384 arg1 = valuePop(ctxt);
7385 if ((arg1 == NULL) || (arg2 == NULL)) {
7386 if (arg1 != NULL)
7387 xmlXPathReleaseObject(ctxt->context, arg1);
7388 else
7389 xmlXPathReleaseObject(ctxt->context, arg2);
7390 XP_ERROR0(XPATH_INVALID_OPERAND);
7391 }
7392
7393 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7394 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7395 /*
7396 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7397 * are not freed from within this routine; they will be freed from the
7398 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7399 */
7400 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7401 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7402 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7403 } else {
7404 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7405 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7406 arg1, arg2);
7407 } else {
7408 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7409 arg2, arg1);
7410 }
7411 }
7412 return(ret);
7413 }
7414
7415 if (arg1->type != XPATH_NUMBER) {
7416 valuePush(ctxt, arg1);
7417 xmlXPathNumberFunction(ctxt, 1);
7418 arg1 = valuePop(ctxt);
7419 }
7420 if (arg1->type != XPATH_NUMBER) {
7421 xmlXPathFreeObject(arg1);
7422 xmlXPathFreeObject(arg2);
7423 XP_ERROR0(XPATH_INVALID_OPERAND);
7424 }
7425 if (arg2->type != XPATH_NUMBER) {
7426 valuePush(ctxt, arg2);
7427 xmlXPathNumberFunction(ctxt, 1);
7428 arg2 = valuePop(ctxt);
7429 }
7430 if (arg2->type != XPATH_NUMBER) {
7431 xmlXPathReleaseObject(ctxt->context, arg1);
7432 xmlXPathReleaseObject(ctxt->context, arg2);
7433 XP_ERROR0(XPATH_INVALID_OPERAND);
7434 }
7435 /*
7436 * Add tests for infinity and nan
7437 * => feedback on 3.4 for Inf and NaN
7438 */
7439 /* Hand check NaN and Infinity comparisons */
7440 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7441 ret=0;
7442 } else {
7443 arg1i=xmlXPathIsInf(arg1->floatval);
7444 arg2i=xmlXPathIsInf(arg2->floatval);
7445 if (inf && strict) {
7446 if ((arg1i == -1 && arg2i != -1) ||
7447 (arg2i == 1 && arg1i != 1)) {
7448 ret = 1;
7449 } else if (arg1i == 0 && arg2i == 0) {
7450 ret = (arg1->floatval < arg2->floatval);
7451 } else {
7452 ret = 0;
7453 }
7454 }
7455 else if (inf && !strict) {
7456 if (arg1i == -1 || arg2i == 1) {
7457 ret = 1;
7458 } else if (arg1i == 0 && arg2i == 0) {
7459 ret = (arg1->floatval <= arg2->floatval);
7460 } else {
7461 ret = 0;
7462 }
7463 }
7464 else if (!inf && strict) {
7465 if ((arg1i == 1 && arg2i != 1) ||
7466 (arg2i == -1 && arg1i != -1)) {
7467 ret = 1;
7468 } else if (arg1i == 0 && arg2i == 0) {
7469 ret = (arg1->floatval > arg2->floatval);
7470 } else {
7471 ret = 0;
7472 }
7473 }
7474 else if (!inf && !strict) {
7475 if (arg1i == 1 || arg2i == -1) {
7476 ret = 1;
7477 } else if (arg1i == 0 && arg2i == 0) {
7478 ret = (arg1->floatval >= arg2->floatval);
7479 } else {
7480 ret = 0;
7481 }
7482 }
7483 }
7484 xmlXPathReleaseObject(ctxt->context, arg1);
7485 xmlXPathReleaseObject(ctxt->context, arg2);
7486 return(ret);
7487 }
7488
7489 /**
7490 * xmlXPathValueFlipSign:
7491 * @ctxt: the XPath Parser context
7492 *
7493 * Implement the unary - operation on an XPath object
7494 * The numeric operators convert their operands to numbers as if
7495 * by calling the number function.
7496 */
7497 void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt)7498 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7499 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7500 CAST_TO_NUMBER;
7501 CHECK_TYPE(XPATH_NUMBER);
7502 ctxt->value->floatval = -ctxt->value->floatval;
7503 }
7504
7505 /**
7506 * xmlXPathAddValues:
7507 * @ctxt: the XPath Parser context
7508 *
7509 * Implement the add operation on XPath objects:
7510 * The numeric operators convert their operands to numbers as if
7511 * by calling the number function.
7512 */
7513 void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt)7514 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7515 xmlXPathObjectPtr arg;
7516 double val;
7517
7518 arg = valuePop(ctxt);
7519 if (arg == NULL)
7520 XP_ERROR(XPATH_INVALID_OPERAND);
7521 val = xmlXPathCastToNumber(arg);
7522 xmlXPathReleaseObject(ctxt->context, arg);
7523 CAST_TO_NUMBER;
7524 CHECK_TYPE(XPATH_NUMBER);
7525 ctxt->value->floatval += val;
7526 }
7527
7528 /**
7529 * xmlXPathSubValues:
7530 * @ctxt: the XPath Parser context
7531 *
7532 * Implement the subtraction operation on XPath objects:
7533 * The numeric operators convert their operands to numbers as if
7534 * by calling the number function.
7535 */
7536 void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt)7537 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7538 xmlXPathObjectPtr arg;
7539 double val;
7540
7541 arg = valuePop(ctxt);
7542 if (arg == NULL)
7543 XP_ERROR(XPATH_INVALID_OPERAND);
7544 val = xmlXPathCastToNumber(arg);
7545 xmlXPathReleaseObject(ctxt->context, arg);
7546 CAST_TO_NUMBER;
7547 CHECK_TYPE(XPATH_NUMBER);
7548 ctxt->value->floatval -= val;
7549 }
7550
7551 /**
7552 * xmlXPathMultValues:
7553 * @ctxt: the XPath Parser context
7554 *
7555 * Implement the multiply operation on XPath objects:
7556 * The numeric operators convert their operands to numbers as if
7557 * by calling the number function.
7558 */
7559 void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt)7560 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7561 xmlXPathObjectPtr arg;
7562 double val;
7563
7564 arg = valuePop(ctxt);
7565 if (arg == NULL)
7566 XP_ERROR(XPATH_INVALID_OPERAND);
7567 val = xmlXPathCastToNumber(arg);
7568 xmlXPathReleaseObject(ctxt->context, arg);
7569 CAST_TO_NUMBER;
7570 CHECK_TYPE(XPATH_NUMBER);
7571 ctxt->value->floatval *= val;
7572 }
7573
7574 /**
7575 * xmlXPathDivValues:
7576 * @ctxt: the XPath Parser context
7577 *
7578 * Implement the div operation on XPath objects @arg1 / @arg2:
7579 * The numeric operators convert their operands to numbers as if
7580 * by calling the number function.
7581 */
7582 void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt)7583 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7584 xmlXPathObjectPtr arg;
7585 double val;
7586
7587 arg = valuePop(ctxt);
7588 if (arg == NULL)
7589 XP_ERROR(XPATH_INVALID_OPERAND);
7590 val = xmlXPathCastToNumber(arg);
7591 xmlXPathReleaseObject(ctxt->context, arg);
7592 CAST_TO_NUMBER;
7593 CHECK_TYPE(XPATH_NUMBER);
7594 ctxt->value->floatval /= val;
7595 }
7596
7597 /**
7598 * xmlXPathModValues:
7599 * @ctxt: the XPath Parser context
7600 *
7601 * Implement the mod operation on XPath objects: @arg1 / @arg2
7602 * The numeric operators convert their operands to numbers as if
7603 * by calling the number function.
7604 */
7605 void
xmlXPathModValues(xmlXPathParserContextPtr ctxt)7606 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7607 xmlXPathObjectPtr arg;
7608 double arg1, arg2;
7609
7610 arg = valuePop(ctxt);
7611 if (arg == NULL)
7612 XP_ERROR(XPATH_INVALID_OPERAND);
7613 arg2 = xmlXPathCastToNumber(arg);
7614 xmlXPathReleaseObject(ctxt->context, arg);
7615 CAST_TO_NUMBER;
7616 CHECK_TYPE(XPATH_NUMBER);
7617 arg1 = ctxt->value->floatval;
7618 if (arg2 == 0)
7619 ctxt->value->floatval = NAN;
7620 else {
7621 ctxt->value->floatval = fmod(arg1, arg2);
7622 }
7623 }
7624
7625 /************************************************************************
7626 * *
7627 * The traversal functions *
7628 * *
7629 ************************************************************************/
7630
7631 /*
7632 * A traversal function enumerates nodes along an axis.
7633 * Initially it must be called with NULL, and it indicates
7634 * termination on the axis by returning NULL.
7635 */
7636 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7637 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7638
7639 /*
7640 * xmlXPathTraversalFunctionExt:
7641 * A traversal function enumerates nodes along an axis.
7642 * Initially it must be called with NULL, and it indicates
7643 * termination on the axis by returning NULL.
7644 * The context node of the traversal is specified via @contextNode.
7645 */
7646 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7647 (xmlNodePtr cur, xmlNodePtr contextNode);
7648
7649 /*
7650 * xmlXPathNodeSetMergeFunction:
7651 * Used for merging node sets in xmlXPathCollectAndTest().
7652 */
7653 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7654 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7655
7656
7657 /**
7658 * xmlXPathNextSelf:
7659 * @ctxt: the XPath Parser context
7660 * @cur: the current node in the traversal
7661 *
7662 * Traversal function for the "self" direction
7663 * The self axis contains just the context node itself
7664 *
7665 * Returns the next element following that axis
7666 */
7667 xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7668 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7669 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7670 if (cur == NULL)
7671 return(ctxt->context->node);
7672 return(NULL);
7673 }
7674
7675 /**
7676 * xmlXPathNextChild:
7677 * @ctxt: the XPath Parser context
7678 * @cur: the current node in the traversal
7679 *
7680 * Traversal function for the "child" direction
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 xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7686 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688 if (cur == NULL) {
7689 if (ctxt->context->node == NULL) return(NULL);
7690 switch (ctxt->context->node->type) {
7691 case XML_ELEMENT_NODE:
7692 case XML_TEXT_NODE:
7693 case XML_CDATA_SECTION_NODE:
7694 case XML_ENTITY_REF_NODE:
7695 case XML_ENTITY_NODE:
7696 case XML_PI_NODE:
7697 case XML_COMMENT_NODE:
7698 case XML_NOTATION_NODE:
7699 case XML_DTD_NODE:
7700 return(ctxt->context->node->children);
7701 case XML_DOCUMENT_NODE:
7702 case XML_DOCUMENT_TYPE_NODE:
7703 case XML_DOCUMENT_FRAG_NODE:
7704 case XML_HTML_DOCUMENT_NODE:
7705 #ifdef LIBXML_DOCB_ENABLED
7706 case XML_DOCB_DOCUMENT_NODE:
7707 #endif
7708 return(((xmlDocPtr) ctxt->context->node)->children);
7709 case XML_ELEMENT_DECL:
7710 case XML_ATTRIBUTE_DECL:
7711 case XML_ENTITY_DECL:
7712 case XML_ATTRIBUTE_NODE:
7713 case XML_NAMESPACE_DECL:
7714 case XML_XINCLUDE_START:
7715 case XML_XINCLUDE_END:
7716 return(NULL);
7717 }
7718 return(NULL);
7719 }
7720 if ((cur->type == XML_DOCUMENT_NODE) ||
7721 (cur->type == XML_HTML_DOCUMENT_NODE))
7722 return(NULL);
7723 return(cur->next);
7724 }
7725
7726 /**
7727 * xmlXPathNextChildElement:
7728 * @ctxt: the XPath Parser context
7729 * @cur: the current node in the traversal
7730 *
7731 * Traversal function for the "child" direction and nodes of type element.
7732 * The child axis contains the children of the context node in document order.
7733 *
7734 * Returns the next element following that axis
7735 */
7736 static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7737 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7738 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7739 if (cur == NULL) {
7740 cur = ctxt->context->node;
7741 if (cur == NULL) return(NULL);
7742 /*
7743 * Get the first element child.
7744 */
7745 switch (cur->type) {
7746 case XML_ELEMENT_NODE:
7747 case XML_DOCUMENT_FRAG_NODE:
7748 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7749 case XML_ENTITY_NODE:
7750 cur = cur->children;
7751 if (cur != NULL) {
7752 if (cur->type == XML_ELEMENT_NODE)
7753 return(cur);
7754 do {
7755 cur = cur->next;
7756 } while ((cur != NULL) &&
7757 (cur->type != XML_ELEMENT_NODE));
7758 return(cur);
7759 }
7760 return(NULL);
7761 case XML_DOCUMENT_NODE:
7762 case XML_HTML_DOCUMENT_NODE:
7763 #ifdef LIBXML_DOCB_ENABLED
7764 case XML_DOCB_DOCUMENT_NODE:
7765 #endif
7766 return(xmlDocGetRootElement((xmlDocPtr) cur));
7767 default:
7768 return(NULL);
7769 }
7770 return(NULL);
7771 }
7772 /*
7773 * Get the next sibling element node.
7774 */
7775 switch (cur->type) {
7776 case XML_ELEMENT_NODE:
7777 case XML_TEXT_NODE:
7778 case XML_ENTITY_REF_NODE:
7779 case XML_ENTITY_NODE:
7780 case XML_CDATA_SECTION_NODE:
7781 case XML_PI_NODE:
7782 case XML_COMMENT_NODE:
7783 case XML_XINCLUDE_END:
7784 break;
7785 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7786 default:
7787 return(NULL);
7788 }
7789 if (cur->next != NULL) {
7790 if (cur->next->type == XML_ELEMENT_NODE)
7791 return(cur->next);
7792 cur = cur->next;
7793 do {
7794 cur = cur->next;
7795 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7796 return(cur);
7797 }
7798 return(NULL);
7799 }
7800
7801 #if 0
7802 /**
7803 * xmlXPathNextDescendantOrSelfElemParent:
7804 * @ctxt: the XPath Parser context
7805 * @cur: the current node in the traversal
7806 *
7807 * Traversal function for the "descendant-or-self" axis.
7808 * Additionally it returns only nodes which can be parents of
7809 * element nodes.
7810 *
7811 *
7812 * Returns the next element following that axis
7813 */
7814 static xmlNodePtr
7815 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7816 xmlNodePtr contextNode)
7817 {
7818 if (cur == NULL) {
7819 if (contextNode == NULL)
7820 return(NULL);
7821 switch (contextNode->type) {
7822 case XML_ELEMENT_NODE:
7823 case XML_XINCLUDE_START:
7824 case XML_DOCUMENT_FRAG_NODE:
7825 case XML_DOCUMENT_NODE:
7826 #ifdef LIBXML_DOCB_ENABLED
7827 case XML_DOCB_DOCUMENT_NODE:
7828 #endif
7829 case XML_HTML_DOCUMENT_NODE:
7830 return(contextNode);
7831 default:
7832 return(NULL);
7833 }
7834 return(NULL);
7835 } else {
7836 xmlNodePtr start = cur;
7837
7838 while (cur != NULL) {
7839 switch (cur->type) {
7840 case XML_ELEMENT_NODE:
7841 /* TODO: OK to have XInclude here? */
7842 case XML_XINCLUDE_START:
7843 case XML_DOCUMENT_FRAG_NODE:
7844 if (cur != start)
7845 return(cur);
7846 if (cur->children != NULL) {
7847 cur = cur->children;
7848 continue;
7849 }
7850 break;
7851 /* Not sure if we need those here. */
7852 case XML_DOCUMENT_NODE:
7853 #ifdef LIBXML_DOCB_ENABLED
7854 case XML_DOCB_DOCUMENT_NODE:
7855 #endif
7856 case XML_HTML_DOCUMENT_NODE:
7857 if (cur != start)
7858 return(cur);
7859 return(xmlDocGetRootElement((xmlDocPtr) cur));
7860 default:
7861 break;
7862 }
7863
7864 next_sibling:
7865 if ((cur == NULL) || (cur == contextNode))
7866 return(NULL);
7867 if (cur->next != NULL) {
7868 cur = cur->next;
7869 } else {
7870 cur = cur->parent;
7871 goto next_sibling;
7872 }
7873 }
7874 }
7875 return(NULL);
7876 }
7877 #endif
7878
7879 /**
7880 * xmlXPathNextDescendant:
7881 * @ctxt: the XPath Parser context
7882 * @cur: the current node in the traversal
7883 *
7884 * Traversal function for the "descendant" direction
7885 * the descendant axis contains the descendants of the context node in document
7886 * order; a descendant is a child or a child of a child and so on.
7887 *
7888 * Returns the next element following that axis
7889 */
7890 xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7891 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7892 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7893 if (cur == NULL) {
7894 if (ctxt->context->node == NULL)
7895 return(NULL);
7896 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7897 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7898 return(NULL);
7899
7900 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7901 return(ctxt->context->doc->children);
7902 return(ctxt->context->node->children);
7903 }
7904
7905 if (cur->type == XML_NAMESPACE_DECL)
7906 return(NULL);
7907 if (cur->children != NULL) {
7908 /*
7909 * Do not descend on entities declarations
7910 */
7911 if (cur->children->type != XML_ENTITY_DECL) {
7912 cur = cur->children;
7913 /*
7914 * Skip DTDs
7915 */
7916 if (cur->type != XML_DTD_NODE)
7917 return(cur);
7918 }
7919 }
7920
7921 if (cur == ctxt->context->node) return(NULL);
7922
7923 while (cur->next != NULL) {
7924 cur = cur->next;
7925 if ((cur->type != XML_ENTITY_DECL) &&
7926 (cur->type != XML_DTD_NODE))
7927 return(cur);
7928 }
7929
7930 do {
7931 cur = cur->parent;
7932 if (cur == NULL) break;
7933 if (cur == ctxt->context->node) return(NULL);
7934 if (cur->next != NULL) {
7935 cur = cur->next;
7936 return(cur);
7937 }
7938 } while (cur != NULL);
7939 return(cur);
7940 }
7941
7942 /**
7943 * xmlXPathNextDescendantOrSelf:
7944 * @ctxt: the XPath Parser context
7945 * @cur: the current node in the traversal
7946 *
7947 * Traversal function for the "descendant-or-self" direction
7948 * the descendant-or-self axis contains the context node and the descendants
7949 * of the context node in document order; thus the context node is the first
7950 * node on the axis, and the first child of the context node is the second node
7951 * on the axis
7952 *
7953 * Returns the next element following that axis
7954 */
7955 xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7956 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7957 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7958 if (cur == NULL)
7959 return(ctxt->context->node);
7960
7961 if (ctxt->context->node == NULL)
7962 return(NULL);
7963 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7964 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7965 return(NULL);
7966
7967 return(xmlXPathNextDescendant(ctxt, cur));
7968 }
7969
7970 /**
7971 * xmlXPathNextParent:
7972 * @ctxt: the XPath Parser context
7973 * @cur: the current node in the traversal
7974 *
7975 * Traversal function for the "parent" direction
7976 * The parent axis contains the parent of the context node, if there is one.
7977 *
7978 * Returns the next element following that axis
7979 */
7980 xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)7981 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7982 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7983 /*
7984 * the parent of an attribute or namespace node is the element
7985 * to which the attribute or namespace node is attached
7986 * Namespace handling !!!
7987 */
7988 if (cur == NULL) {
7989 if (ctxt->context->node == NULL) return(NULL);
7990 switch (ctxt->context->node->type) {
7991 case XML_ELEMENT_NODE:
7992 case XML_TEXT_NODE:
7993 case XML_CDATA_SECTION_NODE:
7994 case XML_ENTITY_REF_NODE:
7995 case XML_ENTITY_NODE:
7996 case XML_PI_NODE:
7997 case XML_COMMENT_NODE:
7998 case XML_NOTATION_NODE:
7999 case XML_DTD_NODE:
8000 case XML_ELEMENT_DECL:
8001 case XML_ATTRIBUTE_DECL:
8002 case XML_XINCLUDE_START:
8003 case XML_XINCLUDE_END:
8004 case XML_ENTITY_DECL:
8005 if (ctxt->context->node->parent == NULL)
8006 return((xmlNodePtr) ctxt->context->doc);
8007 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8008 ((ctxt->context->node->parent->name[0] == ' ') ||
8009 (xmlStrEqual(ctxt->context->node->parent->name,
8010 BAD_CAST "fake node libxslt"))))
8011 return(NULL);
8012 return(ctxt->context->node->parent);
8013 case XML_ATTRIBUTE_NODE: {
8014 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8015
8016 return(att->parent);
8017 }
8018 case XML_DOCUMENT_NODE:
8019 case XML_DOCUMENT_TYPE_NODE:
8020 case XML_DOCUMENT_FRAG_NODE:
8021 case XML_HTML_DOCUMENT_NODE:
8022 #ifdef LIBXML_DOCB_ENABLED
8023 case XML_DOCB_DOCUMENT_NODE:
8024 #endif
8025 return(NULL);
8026 case XML_NAMESPACE_DECL: {
8027 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8028
8029 if ((ns->next != NULL) &&
8030 (ns->next->type != XML_NAMESPACE_DECL))
8031 return((xmlNodePtr) ns->next);
8032 return(NULL);
8033 }
8034 }
8035 }
8036 return(NULL);
8037 }
8038
8039 /**
8040 * xmlXPathNextAncestor:
8041 * @ctxt: the XPath Parser context
8042 * @cur: the current node in the traversal
8043 *
8044 * Traversal function for the "ancestor" direction
8045 * the ancestor axis contains the ancestors of the context node; the ancestors
8046 * of the context node consist of the parent of context node and the parent's
8047 * parent and so on; the nodes are ordered in reverse document order; thus the
8048 * parent is the first node on the axis, and the parent's parent is the second
8049 * node on the axis
8050 *
8051 * Returns the next element following that axis
8052 */
8053 xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8054 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8055 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8056 /*
8057 * the parent of an attribute or namespace node is the element
8058 * to which the attribute or namespace node is attached
8059 * !!!!!!!!!!!!!
8060 */
8061 if (cur == NULL) {
8062 if (ctxt->context->node == NULL) return(NULL);
8063 switch (ctxt->context->node->type) {
8064 case XML_ELEMENT_NODE:
8065 case XML_TEXT_NODE:
8066 case XML_CDATA_SECTION_NODE:
8067 case XML_ENTITY_REF_NODE:
8068 case XML_ENTITY_NODE:
8069 case XML_PI_NODE:
8070 case XML_COMMENT_NODE:
8071 case XML_DTD_NODE:
8072 case XML_ELEMENT_DECL:
8073 case XML_ATTRIBUTE_DECL:
8074 case XML_ENTITY_DECL:
8075 case XML_NOTATION_NODE:
8076 case XML_XINCLUDE_START:
8077 case XML_XINCLUDE_END:
8078 if (ctxt->context->node->parent == NULL)
8079 return((xmlNodePtr) ctxt->context->doc);
8080 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8081 ((ctxt->context->node->parent->name[0] == ' ') ||
8082 (xmlStrEqual(ctxt->context->node->parent->name,
8083 BAD_CAST "fake node libxslt"))))
8084 return(NULL);
8085 return(ctxt->context->node->parent);
8086 case XML_ATTRIBUTE_NODE: {
8087 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8088
8089 return(tmp->parent);
8090 }
8091 case XML_DOCUMENT_NODE:
8092 case XML_DOCUMENT_TYPE_NODE:
8093 case XML_DOCUMENT_FRAG_NODE:
8094 case XML_HTML_DOCUMENT_NODE:
8095 #ifdef LIBXML_DOCB_ENABLED
8096 case XML_DOCB_DOCUMENT_NODE:
8097 #endif
8098 return(NULL);
8099 case XML_NAMESPACE_DECL: {
8100 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8101
8102 if ((ns->next != NULL) &&
8103 (ns->next->type != XML_NAMESPACE_DECL))
8104 return((xmlNodePtr) ns->next);
8105 /* Bad, how did that namespace end up here ? */
8106 return(NULL);
8107 }
8108 }
8109 return(NULL);
8110 }
8111 if (cur == ctxt->context->doc->children)
8112 return((xmlNodePtr) ctxt->context->doc);
8113 if (cur == (xmlNodePtr) ctxt->context->doc)
8114 return(NULL);
8115 switch (cur->type) {
8116 case XML_ELEMENT_NODE:
8117 case XML_TEXT_NODE:
8118 case XML_CDATA_SECTION_NODE:
8119 case XML_ENTITY_REF_NODE:
8120 case XML_ENTITY_NODE:
8121 case XML_PI_NODE:
8122 case XML_COMMENT_NODE:
8123 case XML_NOTATION_NODE:
8124 case XML_DTD_NODE:
8125 case XML_ELEMENT_DECL:
8126 case XML_ATTRIBUTE_DECL:
8127 case XML_ENTITY_DECL:
8128 case XML_XINCLUDE_START:
8129 case XML_XINCLUDE_END:
8130 if (cur->parent == NULL)
8131 return(NULL);
8132 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8133 ((cur->parent->name[0] == ' ') ||
8134 (xmlStrEqual(cur->parent->name,
8135 BAD_CAST "fake node libxslt"))))
8136 return(NULL);
8137 return(cur->parent);
8138 case XML_ATTRIBUTE_NODE: {
8139 xmlAttrPtr att = (xmlAttrPtr) cur;
8140
8141 return(att->parent);
8142 }
8143 case XML_NAMESPACE_DECL: {
8144 xmlNsPtr ns = (xmlNsPtr) cur;
8145
8146 if ((ns->next != NULL) &&
8147 (ns->next->type != XML_NAMESPACE_DECL))
8148 return((xmlNodePtr) ns->next);
8149 /* Bad, how did that namespace end up here ? */
8150 return(NULL);
8151 }
8152 case XML_DOCUMENT_NODE:
8153 case XML_DOCUMENT_TYPE_NODE:
8154 case XML_DOCUMENT_FRAG_NODE:
8155 case XML_HTML_DOCUMENT_NODE:
8156 #ifdef LIBXML_DOCB_ENABLED
8157 case XML_DOCB_DOCUMENT_NODE:
8158 #endif
8159 return(NULL);
8160 }
8161 return(NULL);
8162 }
8163
8164 /**
8165 * xmlXPathNextAncestorOrSelf:
8166 * @ctxt: the XPath Parser context
8167 * @cur: the current node in the traversal
8168 *
8169 * Traversal function for the "ancestor-or-self" direction
8170 * he ancestor-or-self axis contains the context node and ancestors of
8171 * the context node in reverse document order; thus the context node is
8172 * the first node on the axis, and the context node's parent the second;
8173 * parent here is defined the same as with the parent axis.
8174 *
8175 * Returns the next element following that axis
8176 */
8177 xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8178 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8179 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8180 if (cur == NULL)
8181 return(ctxt->context->node);
8182 return(xmlXPathNextAncestor(ctxt, cur));
8183 }
8184
8185 /**
8186 * xmlXPathNextFollowingSibling:
8187 * @ctxt: the XPath Parser context
8188 * @cur: the current node in the traversal
8189 *
8190 * Traversal function for the "following-sibling" direction
8191 * The following-sibling axis contains the following siblings of the context
8192 * node in document order.
8193 *
8194 * Returns the next element following that axis
8195 */
8196 xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8197 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8198 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8199 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8200 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8201 return(NULL);
8202 if (cur == (xmlNodePtr) ctxt->context->doc)
8203 return(NULL);
8204 if (cur == NULL)
8205 return(ctxt->context->node->next);
8206 return(cur->next);
8207 }
8208
8209 /**
8210 * xmlXPathNextPrecedingSibling:
8211 * @ctxt: the XPath Parser context
8212 * @cur: the current node in the traversal
8213 *
8214 * Traversal function for the "preceding-sibling" direction
8215 * The preceding-sibling axis contains the preceding siblings of the context
8216 * node in reverse document order; the first preceding sibling is first on the
8217 * axis; the sibling preceding that node is the second on the axis and so on.
8218 *
8219 * Returns the next element following that axis
8220 */
8221 xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8222 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8223 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8224 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8225 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8226 return(NULL);
8227 if (cur == (xmlNodePtr) ctxt->context->doc)
8228 return(NULL);
8229 if (cur == NULL)
8230 return(ctxt->context->node->prev);
8231 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8232 cur = cur->prev;
8233 if (cur == NULL)
8234 return(ctxt->context->node->prev);
8235 }
8236 return(cur->prev);
8237 }
8238
8239 /**
8240 * xmlXPathNextFollowing:
8241 * @ctxt: the XPath Parser context
8242 * @cur: the current node in the traversal
8243 *
8244 * Traversal function for the "following" direction
8245 * The following axis contains all nodes in the same document as the context
8246 * node that are after the context node in document order, excluding any
8247 * descendants and excluding attribute nodes and namespace nodes; the nodes
8248 * are ordered in document order
8249 *
8250 * Returns the next element following that axis
8251 */
8252 xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8253 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8254 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8255 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8256 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8257 return(cur->children);
8258
8259 if (cur == NULL) {
8260 cur = ctxt->context->node;
8261 if (cur->type == XML_ATTRIBUTE_NODE) {
8262 cur = cur->parent;
8263 } else if (cur->type == XML_NAMESPACE_DECL) {
8264 xmlNsPtr ns = (xmlNsPtr) cur;
8265
8266 if ((ns->next == NULL) ||
8267 (ns->next->type == XML_NAMESPACE_DECL))
8268 return (NULL);
8269 cur = (xmlNodePtr) ns->next;
8270 }
8271 }
8272 if (cur == NULL) return(NULL) ; /* ERROR */
8273 if (cur->next != NULL) return(cur->next) ;
8274 do {
8275 cur = cur->parent;
8276 if (cur == NULL) break;
8277 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8278 if (cur->next != NULL) return(cur->next);
8279 } while (cur != NULL);
8280 return(cur);
8281 }
8282
8283 /*
8284 * xmlXPathIsAncestor:
8285 * @ancestor: the ancestor node
8286 * @node: the current node
8287 *
8288 * Check that @ancestor is a @node's ancestor
8289 *
8290 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8291 */
8292 static int
xmlXPathIsAncestor(xmlNodePtr ancestor,xmlNodePtr node)8293 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8294 if ((ancestor == NULL) || (node == NULL)) return(0);
8295 if (node->type == XML_NAMESPACE_DECL)
8296 return(0);
8297 if (ancestor->type == XML_NAMESPACE_DECL)
8298 return(0);
8299 /* nodes need to be in the same document */
8300 if (ancestor->doc != node->doc) return(0);
8301 /* avoid searching if ancestor or node is the root node */
8302 if (ancestor == (xmlNodePtr) node->doc) return(1);
8303 if (node == (xmlNodePtr) ancestor->doc) return(0);
8304 while (node->parent != NULL) {
8305 if (node->parent == ancestor)
8306 return(1);
8307 node = node->parent;
8308 }
8309 return(0);
8310 }
8311
8312 /**
8313 * xmlXPathNextPreceding:
8314 * @ctxt: the XPath Parser context
8315 * @cur: the current node in the traversal
8316 *
8317 * Traversal function for the "preceding" direction
8318 * the preceding axis contains all nodes in the same document as the context
8319 * node that are before the context node in document order, excluding any
8320 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8321 * ordered in reverse document order
8322 *
8323 * Returns the next element following that axis
8324 */
8325 xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8326 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8327 {
8328 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8329 if (cur == NULL) {
8330 cur = ctxt->context->node;
8331 if (cur->type == XML_ATTRIBUTE_NODE) {
8332 cur = cur->parent;
8333 } else if (cur->type == XML_NAMESPACE_DECL) {
8334 xmlNsPtr ns = (xmlNsPtr) cur;
8335
8336 if ((ns->next == NULL) ||
8337 (ns->next->type == XML_NAMESPACE_DECL))
8338 return (NULL);
8339 cur = (xmlNodePtr) ns->next;
8340 }
8341 }
8342 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8343 return (NULL);
8344 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8345 cur = cur->prev;
8346 do {
8347 if (cur->prev != NULL) {
8348 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8349 return (cur);
8350 }
8351
8352 cur = cur->parent;
8353 if (cur == NULL)
8354 return (NULL);
8355 if (cur == ctxt->context->doc->children)
8356 return (NULL);
8357 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8358 return (cur);
8359 }
8360
8361 /**
8362 * xmlXPathNextPrecedingInternal:
8363 * @ctxt: the XPath Parser context
8364 * @cur: the current node in the traversal
8365 *
8366 * Traversal function for the "preceding" direction
8367 * the preceding axis contains all nodes in the same document as the context
8368 * node that are before the context node in document order, excluding any
8369 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8370 * ordered in reverse document order
8371 * This is a faster implementation but internal only since it requires a
8372 * state kept in the parser context: ctxt->ancestor.
8373 *
8374 * Returns the next element following that axis
8375 */
8376 static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8377 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8378 xmlNodePtr cur)
8379 {
8380 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8381 if (cur == NULL) {
8382 cur = ctxt->context->node;
8383 if (cur == NULL)
8384 return (NULL);
8385 if (cur->type == XML_ATTRIBUTE_NODE) {
8386 cur = cur->parent;
8387 } else if (cur->type == XML_NAMESPACE_DECL) {
8388 xmlNsPtr ns = (xmlNsPtr) cur;
8389
8390 if ((ns->next == NULL) ||
8391 (ns->next->type == XML_NAMESPACE_DECL))
8392 return (NULL);
8393 cur = (xmlNodePtr) ns->next;
8394 }
8395 ctxt->ancestor = cur->parent;
8396 }
8397 if (cur->type == XML_NAMESPACE_DECL)
8398 return(NULL);
8399 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8400 cur = cur->prev;
8401 while (cur->prev == NULL) {
8402 cur = cur->parent;
8403 if (cur == NULL)
8404 return (NULL);
8405 if (cur == ctxt->context->doc->children)
8406 return (NULL);
8407 if (cur != ctxt->ancestor)
8408 return (cur);
8409 ctxt->ancestor = cur->parent;
8410 }
8411 cur = cur->prev;
8412 while (cur->last != NULL)
8413 cur = cur->last;
8414 return (cur);
8415 }
8416
8417 /**
8418 * xmlXPathNextNamespace:
8419 * @ctxt: the XPath Parser context
8420 * @cur: the current attribute in the traversal
8421 *
8422 * Traversal function for the "namespace" direction
8423 * the namespace axis contains the namespace nodes of the context node;
8424 * the order of nodes on this axis is implementation-defined; the axis will
8425 * be empty unless the context node is an element
8426 *
8427 * We keep the XML namespace node at the end of the list.
8428 *
8429 * Returns the next element following that axis
8430 */
8431 xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8432 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8433 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8434 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8435 if (cur == NULL) {
8436 if (ctxt->context->tmpNsList != NULL)
8437 xmlFree(ctxt->context->tmpNsList);
8438 ctxt->context->tmpNsList =
8439 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8440 ctxt->context->tmpNsNr = 0;
8441 if (ctxt->context->tmpNsList != NULL) {
8442 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8443 ctxt->context->tmpNsNr++;
8444 }
8445 }
8446 return((xmlNodePtr) xmlXPathXMLNamespace);
8447 }
8448 if (ctxt->context->tmpNsNr > 0) {
8449 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8450 } else {
8451 if (ctxt->context->tmpNsList != NULL)
8452 xmlFree(ctxt->context->tmpNsList);
8453 ctxt->context->tmpNsList = NULL;
8454 return(NULL);
8455 }
8456 }
8457
8458 /**
8459 * xmlXPathNextAttribute:
8460 * @ctxt: the XPath Parser context
8461 * @cur: the current attribute in the traversal
8462 *
8463 * Traversal function for the "attribute" direction
8464 * TODO: support DTD inherited default attributes
8465 *
8466 * Returns the next element following that axis
8467 */
8468 xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt,xmlNodePtr cur)8469 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8470 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8471 if (ctxt->context->node == NULL)
8472 return(NULL);
8473 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8474 return(NULL);
8475 if (cur == NULL) {
8476 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8477 return(NULL);
8478 return((xmlNodePtr)ctxt->context->node->properties);
8479 }
8480 return((xmlNodePtr)cur->next);
8481 }
8482
8483 /************************************************************************
8484 * *
8485 * NodeTest Functions *
8486 * *
8487 ************************************************************************/
8488
8489 #define IS_FUNCTION 200
8490
8491
8492 /************************************************************************
8493 * *
8494 * Implicit tree core function library *
8495 * *
8496 ************************************************************************/
8497
8498 /**
8499 * xmlXPathRoot:
8500 * @ctxt: the XPath Parser context
8501 *
8502 * Initialize the context to the root of the document
8503 */
8504 void
xmlXPathRoot(xmlXPathParserContextPtr ctxt)8505 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8506 if ((ctxt == NULL) || (ctxt->context == NULL))
8507 return;
8508 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8509 (xmlNodePtr) ctxt->context->doc));
8510 }
8511
8512 /************************************************************************
8513 * *
8514 * The explicit core function library *
8515 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8516 * *
8517 ************************************************************************/
8518
8519
8520 /**
8521 * xmlXPathLastFunction:
8522 * @ctxt: the XPath Parser context
8523 * @nargs: the number of arguments
8524 *
8525 * Implement the last() XPath function
8526 * number last()
8527 * The last function returns the number of nodes in the context node list.
8528 */
8529 void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt,int nargs)8530 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8531 CHECK_ARITY(0);
8532 if (ctxt->context->contextSize >= 0) {
8533 valuePush(ctxt,
8534 xmlXPathCacheNewFloat(ctxt->context,
8535 (double) ctxt->context->contextSize));
8536 #ifdef DEBUG_EXPR
8537 xmlGenericError(xmlGenericErrorContext,
8538 "last() : %d\n", ctxt->context->contextSize);
8539 #endif
8540 } else {
8541 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8542 }
8543 }
8544
8545 /**
8546 * xmlXPathPositionFunction:
8547 * @ctxt: the XPath Parser context
8548 * @nargs: the number of arguments
8549 *
8550 * Implement the position() XPath function
8551 * number position()
8552 * The position function returns the position of the context node in the
8553 * context node list. The first position is 1, and so the last position
8554 * will be equal to last().
8555 */
8556 void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt,int nargs)8557 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8558 CHECK_ARITY(0);
8559 if (ctxt->context->proximityPosition >= 0) {
8560 valuePush(ctxt,
8561 xmlXPathCacheNewFloat(ctxt->context,
8562 (double) ctxt->context->proximityPosition));
8563 #ifdef DEBUG_EXPR
8564 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8565 ctxt->context->proximityPosition);
8566 #endif
8567 } else {
8568 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8569 }
8570 }
8571
8572 /**
8573 * xmlXPathCountFunction:
8574 * @ctxt: the XPath Parser context
8575 * @nargs: the number of arguments
8576 *
8577 * Implement the count() XPath function
8578 * number count(node-set)
8579 */
8580 void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt,int nargs)8581 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8582 xmlXPathObjectPtr cur;
8583
8584 CHECK_ARITY(1);
8585 if ((ctxt->value == NULL) ||
8586 ((ctxt->value->type != XPATH_NODESET) &&
8587 (ctxt->value->type != XPATH_XSLT_TREE)))
8588 XP_ERROR(XPATH_INVALID_TYPE);
8589 cur = valuePop(ctxt);
8590
8591 if ((cur == NULL) || (cur->nodesetval == NULL))
8592 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8593 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8594 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8595 (double) cur->nodesetval->nodeNr));
8596 } else {
8597 if ((cur->nodesetval->nodeNr != 1) ||
8598 (cur->nodesetval->nodeTab == NULL)) {
8599 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8600 } else {
8601 xmlNodePtr tmp;
8602 int i = 0;
8603
8604 tmp = cur->nodesetval->nodeTab[0];
8605 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8606 tmp = tmp->children;
8607 while (tmp != NULL) {
8608 tmp = tmp->next;
8609 i++;
8610 }
8611 }
8612 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8613 }
8614 }
8615 xmlXPathReleaseObject(ctxt->context, cur);
8616 }
8617
8618 /**
8619 * xmlXPathGetElementsByIds:
8620 * @doc: the document
8621 * @ids: a whitespace separated list of IDs
8622 *
8623 * Selects elements by their unique ID.
8624 *
8625 * Returns a node-set of selected elements.
8626 */
8627 static xmlNodeSetPtr
xmlXPathGetElementsByIds(xmlDocPtr doc,const xmlChar * ids)8628 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8629 xmlNodeSetPtr ret;
8630 const xmlChar *cur = ids;
8631 xmlChar *ID;
8632 xmlAttrPtr attr;
8633 xmlNodePtr elem = NULL;
8634
8635 if (ids == NULL) return(NULL);
8636
8637 ret = xmlXPathNodeSetCreate(NULL);
8638 if (ret == NULL)
8639 return(ret);
8640
8641 while (IS_BLANK_CH(*cur)) cur++;
8642 while (*cur != 0) {
8643 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8644 cur++;
8645
8646 ID = xmlStrndup(ids, cur - ids);
8647 if (ID != NULL) {
8648 /*
8649 * We used to check the fact that the value passed
8650 * was an NCName, but this generated much troubles for
8651 * me and Aleksey Sanin, people blatantly violated that
8652 * constaint, like Visa3D spec.
8653 * if (xmlValidateNCName(ID, 1) == 0)
8654 */
8655 attr = xmlGetID(doc, ID);
8656 if (attr != NULL) {
8657 if (attr->type == XML_ATTRIBUTE_NODE)
8658 elem = attr->parent;
8659 else if (attr->type == XML_ELEMENT_NODE)
8660 elem = (xmlNodePtr) attr;
8661 else
8662 elem = NULL;
8663 if (elem != NULL)
8664 xmlXPathNodeSetAdd(ret, elem);
8665 }
8666 xmlFree(ID);
8667 }
8668
8669 while (IS_BLANK_CH(*cur)) cur++;
8670 ids = cur;
8671 }
8672 return(ret);
8673 }
8674
8675 /**
8676 * xmlXPathIdFunction:
8677 * @ctxt: the XPath Parser context
8678 * @nargs: the number of arguments
8679 *
8680 * Implement the id() XPath function
8681 * node-set id(object)
8682 * The id function selects elements by their unique ID
8683 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8684 * then the result is the union of the result of applying id to the
8685 * string value of each of the nodes in the argument node-set. When the
8686 * argument to id is of any other type, the argument is converted to a
8687 * string as if by a call to the string function; the string is split
8688 * into a whitespace-separated list of tokens (whitespace is any sequence
8689 * of characters matching the production S); the result is a node-set
8690 * containing the elements in the same document as the context node that
8691 * have a unique ID equal to any of the tokens in the list.
8692 */
8693 void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt,int nargs)8694 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8695 xmlChar *tokens;
8696 xmlNodeSetPtr ret;
8697 xmlXPathObjectPtr obj;
8698
8699 CHECK_ARITY(1);
8700 obj = valuePop(ctxt);
8701 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8702 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8703 xmlNodeSetPtr ns;
8704 int i;
8705
8706 ret = xmlXPathNodeSetCreate(NULL);
8707 /*
8708 * FIXME -- in an out-of-memory condition this will behave badly.
8709 * The solution is not clear -- we already popped an item from
8710 * ctxt, so the object is in a corrupt state.
8711 */
8712
8713 if (obj->nodesetval != NULL) {
8714 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8715 tokens =
8716 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8717 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8718 ret = xmlXPathNodeSetMerge(ret, ns);
8719 xmlXPathFreeNodeSet(ns);
8720 if (tokens != NULL)
8721 xmlFree(tokens);
8722 }
8723 }
8724 xmlXPathReleaseObject(ctxt->context, obj);
8725 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8726 return;
8727 }
8728 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8729 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8730 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8731 xmlXPathReleaseObject(ctxt->context, obj);
8732 return;
8733 }
8734
8735 /**
8736 * xmlXPathLocalNameFunction:
8737 * @ctxt: the XPath Parser context
8738 * @nargs: the number of arguments
8739 *
8740 * Implement the local-name() XPath function
8741 * string local-name(node-set?)
8742 * The local-name function returns a string containing the local part
8743 * of the name of the node in the argument node-set that is first in
8744 * document order. If the node-set is empty or the first node has no
8745 * name, an empty string is returned. If the argument is omitted it
8746 * defaults to the context node.
8747 */
8748 void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8749 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8750 xmlXPathObjectPtr cur;
8751
8752 if (ctxt == NULL) return;
8753
8754 if (nargs == 0) {
8755 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8756 ctxt->context->node));
8757 nargs = 1;
8758 }
8759
8760 CHECK_ARITY(1);
8761 if ((ctxt->value == NULL) ||
8762 ((ctxt->value->type != XPATH_NODESET) &&
8763 (ctxt->value->type != XPATH_XSLT_TREE)))
8764 XP_ERROR(XPATH_INVALID_TYPE);
8765 cur = valuePop(ctxt);
8766
8767 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8768 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8769 } else {
8770 int i = 0; /* Should be first in document order !!!!! */
8771 switch (cur->nodesetval->nodeTab[i]->type) {
8772 case XML_ELEMENT_NODE:
8773 case XML_ATTRIBUTE_NODE:
8774 case XML_PI_NODE:
8775 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8776 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8777 else
8778 valuePush(ctxt,
8779 xmlXPathCacheNewString(ctxt->context,
8780 cur->nodesetval->nodeTab[i]->name));
8781 break;
8782 case XML_NAMESPACE_DECL:
8783 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8784 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8785 break;
8786 default:
8787 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8788 }
8789 }
8790 xmlXPathReleaseObject(ctxt->context, cur);
8791 }
8792
8793 /**
8794 * xmlXPathNamespaceURIFunction:
8795 * @ctxt: the XPath Parser context
8796 * @nargs: the number of arguments
8797 *
8798 * Implement the namespace-uri() XPath function
8799 * string namespace-uri(node-set?)
8800 * The namespace-uri function returns a string containing the
8801 * namespace URI of the expanded name of the node in the argument
8802 * node-set that is first in document order. If the node-set is empty,
8803 * the first node has no name, or the expanded name has no namespace
8804 * URI, an empty string is returned. If the argument is omitted it
8805 * defaults to the context node.
8806 */
8807 void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt,int nargs)8808 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8809 xmlXPathObjectPtr cur;
8810
8811 if (ctxt == NULL) return;
8812
8813 if (nargs == 0) {
8814 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8815 ctxt->context->node));
8816 nargs = 1;
8817 }
8818 CHECK_ARITY(1);
8819 if ((ctxt->value == NULL) ||
8820 ((ctxt->value->type != XPATH_NODESET) &&
8821 (ctxt->value->type != XPATH_XSLT_TREE)))
8822 XP_ERROR(XPATH_INVALID_TYPE);
8823 cur = valuePop(ctxt);
8824
8825 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8826 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8827 } else {
8828 int i = 0; /* Should be first in document order !!!!! */
8829 switch (cur->nodesetval->nodeTab[i]->type) {
8830 case XML_ELEMENT_NODE:
8831 case XML_ATTRIBUTE_NODE:
8832 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8833 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8834 else
8835 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8836 cur->nodesetval->nodeTab[i]->ns->href));
8837 break;
8838 default:
8839 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8840 }
8841 }
8842 xmlXPathReleaseObject(ctxt->context, cur);
8843 }
8844
8845 /**
8846 * xmlXPathNameFunction:
8847 * @ctxt: the XPath Parser context
8848 * @nargs: the number of arguments
8849 *
8850 * Implement the name() XPath function
8851 * string name(node-set?)
8852 * The name function returns a string containing a QName representing
8853 * the name of the node in the argument node-set that is first in document
8854 * order. The QName must represent the name with respect to the namespace
8855 * declarations in effect on the node whose name is being represented.
8856 * Typically, this will be the form in which the name occurred in the XML
8857 * source. This need not be the case if there are namespace declarations
8858 * in effect on the node that associate multiple prefixes with the same
8859 * namespace. However, an implementation may include information about
8860 * the original prefix in its representation of nodes; in this case, an
8861 * implementation can ensure that the returned string is always the same
8862 * as the QName used in the XML source. If the argument it omitted it
8863 * defaults to the context node.
8864 * Libxml keep the original prefix so the "real qualified name" used is
8865 * returned.
8866 */
8867 static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt,int nargs)8868 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8869 {
8870 xmlXPathObjectPtr cur;
8871
8872 if (nargs == 0) {
8873 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8874 ctxt->context->node));
8875 nargs = 1;
8876 }
8877
8878 CHECK_ARITY(1);
8879 if ((ctxt->value == NULL) ||
8880 ((ctxt->value->type != XPATH_NODESET) &&
8881 (ctxt->value->type != XPATH_XSLT_TREE)))
8882 XP_ERROR(XPATH_INVALID_TYPE);
8883 cur = valuePop(ctxt);
8884
8885 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8886 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8887 } else {
8888 int i = 0; /* Should be first in document order !!!!! */
8889
8890 switch (cur->nodesetval->nodeTab[i]->type) {
8891 case XML_ELEMENT_NODE:
8892 case XML_ATTRIBUTE_NODE:
8893 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8894 valuePush(ctxt,
8895 xmlXPathCacheNewCString(ctxt->context, ""));
8896 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8897 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8898 valuePush(ctxt,
8899 xmlXPathCacheNewString(ctxt->context,
8900 cur->nodesetval->nodeTab[i]->name));
8901 } else {
8902 xmlChar *fullname;
8903
8904 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8905 cur->nodesetval->nodeTab[i]->ns->prefix,
8906 NULL, 0);
8907 if (fullname == cur->nodesetval->nodeTab[i]->name)
8908 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8909 if (fullname == NULL) {
8910 XP_ERROR(XPATH_MEMORY_ERROR);
8911 }
8912 valuePush(ctxt, xmlXPathCacheWrapString(
8913 ctxt->context, fullname));
8914 }
8915 break;
8916 default:
8917 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8918 cur->nodesetval->nodeTab[i]));
8919 xmlXPathLocalNameFunction(ctxt, 1);
8920 }
8921 }
8922 xmlXPathReleaseObject(ctxt->context, cur);
8923 }
8924
8925
8926 /**
8927 * xmlXPathStringFunction:
8928 * @ctxt: the XPath Parser context
8929 * @nargs: the number of arguments
8930 *
8931 * Implement the string() XPath function
8932 * string string(object?)
8933 * The string function converts an object to a string as follows:
8934 * - A node-set is converted to a string by returning the value of
8935 * the node in the node-set that is first in document order.
8936 * If the node-set is empty, an empty string is returned.
8937 * - A number is converted to a string as follows
8938 * + NaN is converted to the string NaN
8939 * + positive zero is converted to the string 0
8940 * + negative zero is converted to the string 0
8941 * + positive infinity is converted to the string Infinity
8942 * + negative infinity is converted to the string -Infinity
8943 * + if the number is an integer, the number is represented in
8944 * decimal form as a Number with no decimal point and no leading
8945 * zeros, preceded by a minus sign (-) if the number is negative
8946 * + otherwise, the number is represented in decimal form as a
8947 * Number including a decimal point with at least one digit
8948 * before the decimal point and at least one digit after the
8949 * decimal point, preceded by a minus sign (-) if the number
8950 * is negative; there must be no leading zeros before the decimal
8951 * point apart possibly from the one required digit immediately
8952 * before the decimal point; beyond the one required digit
8953 * after the decimal point there must be as many, but only as
8954 * many, more digits as are needed to uniquely distinguish the
8955 * number from all other IEEE 754 numeric values.
8956 * - The boolean false value is converted to the string false.
8957 * The boolean true value is converted to the string true.
8958 *
8959 * If the argument is omitted, it defaults to a node-set with the
8960 * context node as its only member.
8961 */
8962 void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt,int nargs)8963 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8964 xmlXPathObjectPtr cur;
8965
8966 if (ctxt == NULL) return;
8967 if (nargs == 0) {
8968 valuePush(ctxt,
8969 xmlXPathCacheWrapString(ctxt->context,
8970 xmlXPathCastNodeToString(ctxt->context->node)));
8971 return;
8972 }
8973
8974 CHECK_ARITY(1);
8975 cur = valuePop(ctxt);
8976 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8977 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8978 }
8979
8980 /**
8981 * xmlXPathStringLengthFunction:
8982 * @ctxt: the XPath Parser context
8983 * @nargs: the number of arguments
8984 *
8985 * Implement the string-length() XPath function
8986 * number string-length(string?)
8987 * The string-length returns the number of characters in the string
8988 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8989 * the context node converted to a string, in other words the value
8990 * of the context node.
8991 */
8992 void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt,int nargs)8993 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8994 xmlXPathObjectPtr cur;
8995
8996 if (nargs == 0) {
8997 if ((ctxt == NULL) || (ctxt->context == NULL))
8998 return;
8999 if (ctxt->context->node == NULL) {
9000 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9001 } else {
9002 xmlChar *content;
9003
9004 content = xmlXPathCastNodeToString(ctxt->context->node);
9005 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9006 xmlUTF8Strlen(content)));
9007 xmlFree(content);
9008 }
9009 return;
9010 }
9011 CHECK_ARITY(1);
9012 CAST_TO_STRING;
9013 CHECK_TYPE(XPATH_STRING);
9014 cur = valuePop(ctxt);
9015 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9016 xmlUTF8Strlen(cur->stringval)));
9017 xmlXPathReleaseObject(ctxt->context, cur);
9018 }
9019
9020 /**
9021 * xmlXPathConcatFunction:
9022 * @ctxt: the XPath Parser context
9023 * @nargs: the number of arguments
9024 *
9025 * Implement the concat() XPath function
9026 * string concat(string, string, string*)
9027 * The concat function returns the concatenation of its arguments.
9028 */
9029 void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt,int nargs)9030 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9031 xmlXPathObjectPtr cur, newobj;
9032 xmlChar *tmp;
9033
9034 if (ctxt == NULL) return;
9035 if (nargs < 2) {
9036 CHECK_ARITY(2);
9037 }
9038
9039 CAST_TO_STRING;
9040 cur = valuePop(ctxt);
9041 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9042 xmlXPathReleaseObject(ctxt->context, cur);
9043 return;
9044 }
9045 nargs--;
9046
9047 while (nargs > 0) {
9048 CAST_TO_STRING;
9049 newobj = valuePop(ctxt);
9050 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9051 xmlXPathReleaseObject(ctxt->context, newobj);
9052 xmlXPathReleaseObject(ctxt->context, cur);
9053 XP_ERROR(XPATH_INVALID_TYPE);
9054 }
9055 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9056 newobj->stringval = cur->stringval;
9057 cur->stringval = tmp;
9058 xmlXPathReleaseObject(ctxt->context, newobj);
9059 nargs--;
9060 }
9061 valuePush(ctxt, cur);
9062 }
9063
9064 /**
9065 * xmlXPathContainsFunction:
9066 * @ctxt: the XPath Parser context
9067 * @nargs: the number of arguments
9068 *
9069 * Implement the contains() XPath function
9070 * boolean contains(string, string)
9071 * The contains function returns true if the first argument string
9072 * contains the second argument string, and otherwise returns false.
9073 */
9074 void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt,int nargs)9075 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9076 xmlXPathObjectPtr hay, needle;
9077
9078 CHECK_ARITY(2);
9079 CAST_TO_STRING;
9080 CHECK_TYPE(XPATH_STRING);
9081 needle = valuePop(ctxt);
9082 CAST_TO_STRING;
9083 hay = valuePop(ctxt);
9084
9085 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9086 xmlXPathReleaseObject(ctxt->context, hay);
9087 xmlXPathReleaseObject(ctxt->context, needle);
9088 XP_ERROR(XPATH_INVALID_TYPE);
9089 }
9090 if (xmlStrstr(hay->stringval, needle->stringval))
9091 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9092 else
9093 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9094 xmlXPathReleaseObject(ctxt->context, hay);
9095 xmlXPathReleaseObject(ctxt->context, needle);
9096 }
9097
9098 /**
9099 * xmlXPathStartsWithFunction:
9100 * @ctxt: the XPath Parser context
9101 * @nargs: the number of arguments
9102 *
9103 * Implement the starts-with() XPath function
9104 * boolean starts-with(string, string)
9105 * The starts-with function returns true if the first argument string
9106 * starts with the second argument string, and otherwise returns false.
9107 */
9108 void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt,int nargs)9109 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9110 xmlXPathObjectPtr hay, needle;
9111 int n;
9112
9113 CHECK_ARITY(2);
9114 CAST_TO_STRING;
9115 CHECK_TYPE(XPATH_STRING);
9116 needle = valuePop(ctxt);
9117 CAST_TO_STRING;
9118 hay = valuePop(ctxt);
9119
9120 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9121 xmlXPathReleaseObject(ctxt->context, hay);
9122 xmlXPathReleaseObject(ctxt->context, needle);
9123 XP_ERROR(XPATH_INVALID_TYPE);
9124 }
9125 n = xmlStrlen(needle->stringval);
9126 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9127 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9128 else
9129 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9130 xmlXPathReleaseObject(ctxt->context, hay);
9131 xmlXPathReleaseObject(ctxt->context, needle);
9132 }
9133
9134 /**
9135 * xmlXPathSubstringFunction:
9136 * @ctxt: the XPath Parser context
9137 * @nargs: the number of arguments
9138 *
9139 * Implement the substring() XPath function
9140 * string substring(string, number, number?)
9141 * The substring function returns the substring of the first argument
9142 * starting at the position specified in the second argument with
9143 * length specified in the third argument. For example,
9144 * substring("12345",2,3) returns "234". If the third argument is not
9145 * specified, it returns the substring starting at the position specified
9146 * in the second argument and continuing to the end of the string. For
9147 * example, substring("12345",2) returns "2345". More precisely, each
9148 * character in the string (see [3.6 Strings]) is considered to have a
9149 * numeric position: the position of the first character is 1, the position
9150 * of the second character is 2 and so on. The returned substring contains
9151 * those characters for which the position of the character is greater than
9152 * or equal to the second argument and, if the third argument is specified,
9153 * less than the sum of the second and third arguments; the comparisons
9154 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9155 * - substring("12345", 1.5, 2.6) returns "234"
9156 * - substring("12345", 0, 3) returns "12"
9157 * - substring("12345", 0 div 0, 3) returns ""
9158 * - substring("12345", 1, 0 div 0) returns ""
9159 * - substring("12345", -42, 1 div 0) returns "12345"
9160 * - substring("12345", -1 div 0, 1 div 0) returns ""
9161 */
9162 void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt,int nargs)9163 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9164 xmlXPathObjectPtr str, start, len;
9165 double le=0, in;
9166 int i, l, m;
9167 xmlChar *ret;
9168
9169 if (nargs < 2) {
9170 CHECK_ARITY(2);
9171 }
9172 if (nargs > 3) {
9173 CHECK_ARITY(3);
9174 }
9175 /*
9176 * take care of possible last (position) argument
9177 */
9178 if (nargs == 3) {
9179 CAST_TO_NUMBER;
9180 CHECK_TYPE(XPATH_NUMBER);
9181 len = valuePop(ctxt);
9182 le = len->floatval;
9183 xmlXPathReleaseObject(ctxt->context, len);
9184 }
9185
9186 CAST_TO_NUMBER;
9187 CHECK_TYPE(XPATH_NUMBER);
9188 start = valuePop(ctxt);
9189 in = start->floatval;
9190 xmlXPathReleaseObject(ctxt->context, start);
9191 CAST_TO_STRING;
9192 CHECK_TYPE(XPATH_STRING);
9193 str = valuePop(ctxt);
9194 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9195
9196 /*
9197 * If last pos not present, calculate last position
9198 */
9199 if (nargs != 3) {
9200 le = (double)m;
9201 if (in < 1.0)
9202 in = 1.0;
9203 }
9204
9205 /* Need to check for the special cases where either
9206 * the index is NaN, the length is NaN, or both
9207 * arguments are infinity (relying on Inf + -Inf = NaN)
9208 */
9209 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9210 /*
9211 * To meet the requirements of the spec, the arguments
9212 * must be converted to integer format before
9213 * initial index calculations are done
9214 *
9215 * First we go to integer form, rounding up
9216 * and checking for special cases
9217 */
9218 i = (int) in;
9219 if (((double)i)+0.5 <= in) i++;
9220
9221 if (xmlXPathIsInf(le) == 1) {
9222 l = m;
9223 if (i < 1)
9224 i = 1;
9225 }
9226 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9227 l = 0;
9228 else {
9229 l = (int) le;
9230 if (((double)l)+0.5 <= le) l++;
9231 }
9232
9233 /* Now we normalize inidices */
9234 i -= 1;
9235 l += i;
9236 if (i < 0)
9237 i = 0;
9238 if (l > m)
9239 l = m;
9240
9241 /* number of chars to copy */
9242 l -= i;
9243
9244 ret = xmlUTF8Strsub(str->stringval, i, l);
9245 }
9246 else {
9247 ret = NULL;
9248 }
9249 if (ret == NULL)
9250 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9251 else {
9252 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9253 xmlFree(ret);
9254 }
9255 xmlXPathReleaseObject(ctxt->context, str);
9256 }
9257
9258 /**
9259 * xmlXPathSubstringBeforeFunction:
9260 * @ctxt: the XPath Parser context
9261 * @nargs: the number of arguments
9262 *
9263 * Implement the substring-before() XPath function
9264 * string substring-before(string, string)
9265 * The substring-before function returns the substring of the first
9266 * argument string that precedes the first occurrence of the second
9267 * argument string in the first argument string, or the empty string
9268 * if the first argument string does not contain the second argument
9269 * string. For example, substring-before("1999/04/01","/") returns 1999.
9270 */
9271 void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt,int nargs)9272 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9273 xmlXPathObjectPtr str;
9274 xmlXPathObjectPtr find;
9275 xmlBufPtr target;
9276 const xmlChar *point;
9277 int offset;
9278
9279 CHECK_ARITY(2);
9280 CAST_TO_STRING;
9281 find = valuePop(ctxt);
9282 CAST_TO_STRING;
9283 str = valuePop(ctxt);
9284
9285 target = xmlBufCreate();
9286 if (target) {
9287 point = xmlStrstr(str->stringval, find->stringval);
9288 if (point) {
9289 offset = (int)(point - str->stringval);
9290 xmlBufAdd(target, str->stringval, offset);
9291 }
9292 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9293 xmlBufContent(target)));
9294 xmlBufFree(target);
9295 }
9296 xmlXPathReleaseObject(ctxt->context, str);
9297 xmlXPathReleaseObject(ctxt->context, find);
9298 }
9299
9300 /**
9301 * xmlXPathSubstringAfterFunction:
9302 * @ctxt: the XPath Parser context
9303 * @nargs: the number of arguments
9304 *
9305 * Implement the substring-after() XPath function
9306 * string substring-after(string, string)
9307 * The substring-after function returns the substring of the first
9308 * argument string that follows the first occurrence of the second
9309 * argument string in the first argument string, or the empty stringi
9310 * if the first argument string does not contain the second argument
9311 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9312 * and substring-after("1999/04/01","19") returns 99/04/01.
9313 */
9314 void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt,int nargs)9315 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9316 xmlXPathObjectPtr str;
9317 xmlXPathObjectPtr find;
9318 xmlBufPtr target;
9319 const xmlChar *point;
9320 int offset;
9321
9322 CHECK_ARITY(2);
9323 CAST_TO_STRING;
9324 find = valuePop(ctxt);
9325 CAST_TO_STRING;
9326 str = valuePop(ctxt);
9327
9328 target = xmlBufCreate();
9329 if (target) {
9330 point = xmlStrstr(str->stringval, find->stringval);
9331 if (point) {
9332 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9333 xmlBufAdd(target, &str->stringval[offset],
9334 xmlStrlen(str->stringval) - offset);
9335 }
9336 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9337 xmlBufContent(target)));
9338 xmlBufFree(target);
9339 }
9340 xmlXPathReleaseObject(ctxt->context, str);
9341 xmlXPathReleaseObject(ctxt->context, find);
9342 }
9343
9344 /**
9345 * xmlXPathNormalizeFunction:
9346 * @ctxt: the XPath Parser context
9347 * @nargs: the number of arguments
9348 *
9349 * Implement the normalize-space() XPath function
9350 * string normalize-space(string?)
9351 * The normalize-space function returns the argument string with white
9352 * space normalized by stripping leading and trailing whitespace
9353 * and replacing sequences of whitespace characters by a single
9354 * space. Whitespace characters are the same allowed by the S production
9355 * in XML. If the argument is omitted, it defaults to the context
9356 * node converted to a string, in other words the value of the context node.
9357 */
9358 void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt,int nargs)9359 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9360 xmlXPathObjectPtr obj = NULL;
9361 xmlChar *source = NULL;
9362 xmlBufPtr target;
9363 xmlChar blank;
9364
9365 if (ctxt == NULL) return;
9366 if (nargs == 0) {
9367 /* Use current context node */
9368 valuePush(ctxt,
9369 xmlXPathCacheWrapString(ctxt->context,
9370 xmlXPathCastNodeToString(ctxt->context->node)));
9371 nargs = 1;
9372 }
9373
9374 CHECK_ARITY(1);
9375 CAST_TO_STRING;
9376 CHECK_TYPE(XPATH_STRING);
9377 obj = valuePop(ctxt);
9378 source = obj->stringval;
9379
9380 target = xmlBufCreate();
9381 if (target && source) {
9382
9383 /* Skip leading whitespaces */
9384 while (IS_BLANK_CH(*source))
9385 source++;
9386
9387 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9388 blank = 0;
9389 while (*source) {
9390 if (IS_BLANK_CH(*source)) {
9391 blank = 0x20;
9392 } else {
9393 if (blank) {
9394 xmlBufAdd(target, &blank, 1);
9395 blank = 0;
9396 }
9397 xmlBufAdd(target, source, 1);
9398 }
9399 source++;
9400 }
9401 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9402 xmlBufContent(target)));
9403 xmlBufFree(target);
9404 }
9405 xmlXPathReleaseObject(ctxt->context, obj);
9406 }
9407
9408 /**
9409 * xmlXPathTranslateFunction:
9410 * @ctxt: the XPath Parser context
9411 * @nargs: the number of arguments
9412 *
9413 * Implement the translate() XPath function
9414 * string translate(string, string, string)
9415 * The translate function returns the first argument string with
9416 * occurrences of characters in the second argument string replaced
9417 * by the character at the corresponding position in the third argument
9418 * string. For example, translate("bar","abc","ABC") returns the string
9419 * BAr. If there is a character in the second argument string with no
9420 * character at a corresponding position in the third argument string
9421 * (because the second argument string is longer than the third argument
9422 * string), then occurrences of that character in the first argument
9423 * string are removed. For example, translate("--aaa--","abc-","ABC")
9424 * returns "AAA". If a character occurs more than once in second
9425 * argument string, then the first occurrence determines the replacement
9426 * character. If the third argument string is longer than the second
9427 * argument string, then excess characters are ignored.
9428 */
9429 void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt,int nargs)9430 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9431 xmlXPathObjectPtr str;
9432 xmlXPathObjectPtr from;
9433 xmlXPathObjectPtr to;
9434 xmlBufPtr target;
9435 int offset, max;
9436 xmlChar ch;
9437 const xmlChar *point;
9438 xmlChar *cptr;
9439
9440 CHECK_ARITY(3);
9441
9442 CAST_TO_STRING;
9443 to = valuePop(ctxt);
9444 CAST_TO_STRING;
9445 from = valuePop(ctxt);
9446 CAST_TO_STRING;
9447 str = valuePop(ctxt);
9448
9449 target = xmlBufCreate();
9450 if (target) {
9451 max = xmlUTF8Strlen(to->stringval);
9452 for (cptr = str->stringval; (ch=*cptr); ) {
9453 offset = xmlUTF8Strloc(from->stringval, cptr);
9454 if (offset >= 0) {
9455 if (offset < max) {
9456 point = xmlUTF8Strpos(to->stringval, offset);
9457 if (point)
9458 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9459 }
9460 } else
9461 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9462
9463 /* Step to next character in input */
9464 cptr++;
9465 if ( ch & 0x80 ) {
9466 /* if not simple ascii, verify proper format */
9467 if ( (ch & 0xc0) != 0xc0 ) {
9468 xmlGenericError(xmlGenericErrorContext,
9469 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9470 /* not asserting an XPath error is probably better */
9471 break;
9472 }
9473 /* then skip over remaining bytes for this char */
9474 while ( (ch <<= 1) & 0x80 )
9475 if ( (*cptr++ & 0xc0) != 0x80 ) {
9476 xmlGenericError(xmlGenericErrorContext,
9477 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9478 /* not asserting an XPath error is probably better */
9479 break;
9480 }
9481 if (ch & 0x80) /* must have had error encountered */
9482 break;
9483 }
9484 }
9485 }
9486 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9487 xmlBufContent(target)));
9488 xmlBufFree(target);
9489 xmlXPathReleaseObject(ctxt->context, str);
9490 xmlXPathReleaseObject(ctxt->context, from);
9491 xmlXPathReleaseObject(ctxt->context, to);
9492 }
9493
9494 /**
9495 * xmlXPathBooleanFunction:
9496 * @ctxt: the XPath Parser context
9497 * @nargs: the number of arguments
9498 *
9499 * Implement the boolean() XPath function
9500 * boolean boolean(object)
9501 * The boolean function converts its argument to a boolean as follows:
9502 * - a number is true if and only if it is neither positive or
9503 * negative zero nor NaN
9504 * - a node-set is true if and only if it is non-empty
9505 * - a string is true if and only if its length is non-zero
9506 */
9507 void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt,int nargs)9508 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9509 xmlXPathObjectPtr cur;
9510
9511 CHECK_ARITY(1);
9512 cur = valuePop(ctxt);
9513 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9514 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9515 valuePush(ctxt, cur);
9516 }
9517
9518 /**
9519 * xmlXPathNotFunction:
9520 * @ctxt: the XPath Parser context
9521 * @nargs: the number of arguments
9522 *
9523 * Implement the not() XPath function
9524 * boolean not(boolean)
9525 * The not function returns true if its argument is false,
9526 * and false otherwise.
9527 */
9528 void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt,int nargs)9529 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9530 CHECK_ARITY(1);
9531 CAST_TO_BOOLEAN;
9532 CHECK_TYPE(XPATH_BOOLEAN);
9533 ctxt->value->boolval = ! ctxt->value->boolval;
9534 }
9535
9536 /**
9537 * xmlXPathTrueFunction:
9538 * @ctxt: the XPath Parser context
9539 * @nargs: the number of arguments
9540 *
9541 * Implement the true() XPath function
9542 * boolean true()
9543 */
9544 void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt,int nargs)9545 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9546 CHECK_ARITY(0);
9547 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9548 }
9549
9550 /**
9551 * xmlXPathFalseFunction:
9552 * @ctxt: the XPath Parser context
9553 * @nargs: the number of arguments
9554 *
9555 * Implement the false() XPath function
9556 * boolean false()
9557 */
9558 void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt,int nargs)9559 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9560 CHECK_ARITY(0);
9561 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9562 }
9563
9564 /**
9565 * xmlXPathLangFunction:
9566 * @ctxt: the XPath Parser context
9567 * @nargs: the number of arguments
9568 *
9569 * Implement the lang() XPath function
9570 * boolean lang(string)
9571 * The lang function returns true or false depending on whether the
9572 * language of the context node as specified by xml:lang attributes
9573 * is the same as or is a sublanguage of the language specified by
9574 * the argument string. The language of the context node is determined
9575 * by the value of the xml:lang attribute on the context node, or, if
9576 * the context node has no xml:lang attribute, by the value of the
9577 * xml:lang attribute on the nearest ancestor of the context node that
9578 * has an xml:lang attribute. If there is no such attribute, then lang
9579 * returns false. If there is such an attribute, then lang returns
9580 * true if the attribute value is equal to the argument ignoring case,
9581 * or if there is some suffix starting with - such that the attribute
9582 * value is equal to the argument ignoring that suffix of the attribute
9583 * value and ignoring case.
9584 */
9585 void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt,int nargs)9586 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9587 xmlXPathObjectPtr val = NULL;
9588 const xmlChar *theLang = NULL;
9589 const xmlChar *lang;
9590 int ret = 0;
9591 int i;
9592
9593 CHECK_ARITY(1);
9594 CAST_TO_STRING;
9595 CHECK_TYPE(XPATH_STRING);
9596 val = valuePop(ctxt);
9597 lang = val->stringval;
9598 theLang = xmlNodeGetLang(ctxt->context->node);
9599 if ((theLang != NULL) && (lang != NULL)) {
9600 for (i = 0;lang[i] != 0;i++)
9601 if (toupper(lang[i]) != toupper(theLang[i]))
9602 goto not_equal;
9603 if ((theLang[i] == 0) || (theLang[i] == '-'))
9604 ret = 1;
9605 }
9606 not_equal:
9607 if (theLang != NULL)
9608 xmlFree((void *)theLang);
9609
9610 xmlXPathReleaseObject(ctxt->context, val);
9611 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9612 }
9613
9614 /**
9615 * xmlXPathNumberFunction:
9616 * @ctxt: the XPath Parser context
9617 * @nargs: the number of arguments
9618 *
9619 * Implement the number() XPath function
9620 * number number(object?)
9621 */
9622 void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt,int nargs)9623 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9624 xmlXPathObjectPtr cur;
9625 double res;
9626
9627 if (ctxt == NULL) return;
9628 if (nargs == 0) {
9629 if (ctxt->context->node == NULL) {
9630 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9631 } else {
9632 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9633
9634 res = xmlXPathStringEvalNumber(content);
9635 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9636 xmlFree(content);
9637 }
9638 return;
9639 }
9640
9641 CHECK_ARITY(1);
9642 cur = valuePop(ctxt);
9643 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9644 }
9645
9646 /**
9647 * xmlXPathSumFunction:
9648 * @ctxt: the XPath Parser context
9649 * @nargs: the number of arguments
9650 *
9651 * Implement the sum() XPath function
9652 * number sum(node-set)
9653 * The sum function returns the sum of the values of the nodes in
9654 * the argument node-set.
9655 */
9656 void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt,int nargs)9657 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9658 xmlXPathObjectPtr cur;
9659 int i;
9660 double res = 0.0;
9661
9662 CHECK_ARITY(1);
9663 if ((ctxt->value == NULL) ||
9664 ((ctxt->value->type != XPATH_NODESET) &&
9665 (ctxt->value->type != XPATH_XSLT_TREE)))
9666 XP_ERROR(XPATH_INVALID_TYPE);
9667 cur = valuePop(ctxt);
9668
9669 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9670 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9671 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9672 }
9673 }
9674 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9675 xmlXPathReleaseObject(ctxt->context, cur);
9676 }
9677
9678 /**
9679 * xmlXPathFloorFunction:
9680 * @ctxt: the XPath Parser context
9681 * @nargs: the number of arguments
9682 *
9683 * Implement the floor() XPath function
9684 * number floor(number)
9685 * The floor function returns the largest (closest to positive infinity)
9686 * number that is not greater than the argument and that is an integer.
9687 */
9688 void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt,int nargs)9689 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9690 CHECK_ARITY(1);
9691 CAST_TO_NUMBER;
9692 CHECK_TYPE(XPATH_NUMBER);
9693
9694 ctxt->value->floatval = floor(ctxt->value->floatval);
9695 }
9696
9697 /**
9698 * xmlXPathCeilingFunction:
9699 * @ctxt: the XPath Parser context
9700 * @nargs: the number of arguments
9701 *
9702 * Implement the ceiling() XPath function
9703 * number ceiling(number)
9704 * The ceiling function returns the smallest (closest to negative infinity)
9705 * number that is not less than the argument and that is an integer.
9706 */
9707 void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt,int nargs)9708 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9709 CHECK_ARITY(1);
9710 CAST_TO_NUMBER;
9711 CHECK_TYPE(XPATH_NUMBER);
9712
9713 ctxt->value->floatval = ceil(ctxt->value->floatval);
9714 }
9715
9716 /**
9717 * xmlXPathRoundFunction:
9718 * @ctxt: the XPath Parser context
9719 * @nargs: the number of arguments
9720 *
9721 * Implement the round() XPath function
9722 * number round(number)
9723 * The round function returns the number that is closest to the
9724 * argument and that is an integer. If there are two such numbers,
9725 * then the one that is closest to positive infinity is returned.
9726 */
9727 void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt,int nargs)9728 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9729 double f;
9730
9731 CHECK_ARITY(1);
9732 CAST_TO_NUMBER;
9733 CHECK_TYPE(XPATH_NUMBER);
9734
9735 f = ctxt->value->floatval;
9736
9737 if ((f >= -0.5) && (f < 0.5)) {
9738 /* Handles negative zero. */
9739 ctxt->value->floatval *= 0.0;
9740 }
9741 else {
9742 double rounded = floor(f);
9743 if (f - rounded >= 0.5)
9744 rounded += 1.0;
9745 ctxt->value->floatval = rounded;
9746 }
9747 }
9748
9749 /************************************************************************
9750 * *
9751 * The Parser *
9752 * *
9753 ************************************************************************/
9754
9755 /*
9756 * a few forward declarations since we use a recursive call based
9757 * implementation.
9758 */
9759 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9760 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9761 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9762 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9763 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9764 int qualified);
9765
9766 /**
9767 * xmlXPathCurrentChar:
9768 * @ctxt: the XPath parser context
9769 * @cur: pointer to the beginning of the char
9770 * @len: pointer to the length of the char read
9771 *
9772 * The current char value, if using UTF-8 this may actually span multiple
9773 * bytes in the input buffer.
9774 *
9775 * Returns the current char value and its length
9776 */
9777
9778 static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt,int * len)9779 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9780 unsigned char c;
9781 unsigned int val;
9782 const xmlChar *cur;
9783
9784 if (ctxt == NULL)
9785 return(0);
9786 cur = ctxt->cur;
9787
9788 /*
9789 * We are supposed to handle UTF8, check it's valid
9790 * From rfc2044: encoding of the Unicode values on UTF-8:
9791 *
9792 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9793 * 0000 0000-0000 007F 0xxxxxxx
9794 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9795 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9796 *
9797 * Check for the 0x110000 limit too
9798 */
9799 c = *cur;
9800 if (c & 0x80) {
9801 if ((cur[1] & 0xc0) != 0x80)
9802 goto encoding_error;
9803 if ((c & 0xe0) == 0xe0) {
9804
9805 if ((cur[2] & 0xc0) != 0x80)
9806 goto encoding_error;
9807 if ((c & 0xf0) == 0xf0) {
9808 if (((c & 0xf8) != 0xf0) ||
9809 ((cur[3] & 0xc0) != 0x80))
9810 goto encoding_error;
9811 /* 4-byte code */
9812 *len = 4;
9813 val = (cur[0] & 0x7) << 18;
9814 val |= (cur[1] & 0x3f) << 12;
9815 val |= (cur[2] & 0x3f) << 6;
9816 val |= cur[3] & 0x3f;
9817 } else {
9818 /* 3-byte code */
9819 *len = 3;
9820 val = (cur[0] & 0xf) << 12;
9821 val |= (cur[1] & 0x3f) << 6;
9822 val |= cur[2] & 0x3f;
9823 }
9824 } else {
9825 /* 2-byte code */
9826 *len = 2;
9827 val = (cur[0] & 0x1f) << 6;
9828 val |= cur[1] & 0x3f;
9829 }
9830 if (!IS_CHAR(val)) {
9831 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9832 }
9833 return(val);
9834 } else {
9835 /* 1-byte code */
9836 *len = 1;
9837 return((int) *cur);
9838 }
9839 encoding_error:
9840 /*
9841 * If we detect an UTF8 error that probably means that the
9842 * input encoding didn't get properly advertised in the
9843 * declaration header. Report the error and switch the encoding
9844 * to ISO-Latin-1 (if you don't like this policy, just declare the
9845 * encoding !)
9846 */
9847 *len = 0;
9848 XP_ERROR0(XPATH_ENCODING_ERROR);
9849 }
9850
9851 /**
9852 * xmlXPathParseNCName:
9853 * @ctxt: the XPath Parser context
9854 *
9855 * parse an XML namespace non qualified name.
9856 *
9857 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9858 *
9859 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9860 * CombiningChar | Extender
9861 *
9862 * Returns the namespace name or NULL
9863 */
9864
9865 xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt)9866 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9867 const xmlChar *in;
9868 xmlChar *ret;
9869 int count = 0;
9870
9871 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9872 /*
9873 * Accelerator for simple ASCII names
9874 */
9875 in = ctxt->cur;
9876 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9877 ((*in >= 0x41) && (*in <= 0x5A)) ||
9878 (*in == '_')) {
9879 in++;
9880 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9881 ((*in >= 0x41) && (*in <= 0x5A)) ||
9882 ((*in >= 0x30) && (*in <= 0x39)) ||
9883 (*in == '_') || (*in == '.') ||
9884 (*in == '-'))
9885 in++;
9886 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9887 (*in == '[') || (*in == ']') || (*in == ':') ||
9888 (*in == '@') || (*in == '*')) {
9889 count = in - ctxt->cur;
9890 if (count == 0)
9891 return(NULL);
9892 ret = xmlStrndup(ctxt->cur, count);
9893 ctxt->cur = in;
9894 return(ret);
9895 }
9896 }
9897 return(xmlXPathParseNameComplex(ctxt, 0));
9898 }
9899
9900
9901 /**
9902 * xmlXPathParseQName:
9903 * @ctxt: the XPath Parser context
9904 * @prefix: a xmlChar **
9905 *
9906 * parse an XML qualified name
9907 *
9908 * [NS 5] QName ::= (Prefix ':')? LocalPart
9909 *
9910 * [NS 6] Prefix ::= NCName
9911 *
9912 * [NS 7] LocalPart ::= NCName
9913 *
9914 * Returns the function returns the local part, and prefix is updated
9915 * to get the Prefix if any.
9916 */
9917
9918 static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt,xmlChar ** prefix)9919 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9920 xmlChar *ret = NULL;
9921
9922 *prefix = NULL;
9923 ret = xmlXPathParseNCName(ctxt);
9924 if (ret && CUR == ':') {
9925 *prefix = ret;
9926 NEXT;
9927 ret = xmlXPathParseNCName(ctxt);
9928 }
9929 return(ret);
9930 }
9931
9932 /**
9933 * xmlXPathParseName:
9934 * @ctxt: the XPath Parser context
9935 *
9936 * parse an XML name
9937 *
9938 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9939 * CombiningChar | Extender
9940 *
9941 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9942 *
9943 * Returns the namespace name or NULL
9944 */
9945
9946 xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt)9947 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9948 const xmlChar *in;
9949 xmlChar *ret;
9950 size_t count = 0;
9951
9952 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9953 /*
9954 * Accelerator for simple ASCII names
9955 */
9956 in = ctxt->cur;
9957 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9958 ((*in >= 0x41) && (*in <= 0x5A)) ||
9959 (*in == '_') || (*in == ':')) {
9960 in++;
9961 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9962 ((*in >= 0x41) && (*in <= 0x5A)) ||
9963 ((*in >= 0x30) && (*in <= 0x39)) ||
9964 (*in == '_') || (*in == '-') ||
9965 (*in == ':') || (*in == '.'))
9966 in++;
9967 if ((*in > 0) && (*in < 0x80)) {
9968 count = in - ctxt->cur;
9969 if (count > XML_MAX_NAME_LENGTH) {
9970 ctxt->cur = in;
9971 XP_ERRORNULL(XPATH_EXPR_ERROR);
9972 }
9973 ret = xmlStrndup(ctxt->cur, count);
9974 ctxt->cur = in;
9975 return(ret);
9976 }
9977 }
9978 return(xmlXPathParseNameComplex(ctxt, 1));
9979 }
9980
9981 static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,int qualified)9982 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9983 xmlChar buf[XML_MAX_NAMELEN + 5];
9984 int len = 0, l;
9985 int c;
9986
9987 /*
9988 * Handler for more complex cases
9989 */
9990 c = CUR_CHAR(l);
9991 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9992 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9993 (c == '*') || /* accelerators */
9994 (!IS_LETTER(c) && (c != '_') &&
9995 ((!qualified) || (c != ':')))) {
9996 return(NULL);
9997 }
9998
9999 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10000 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10001 (c == '.') || (c == '-') ||
10002 (c == '_') || ((qualified) && (c == ':')) ||
10003 (IS_COMBINING(c)) ||
10004 (IS_EXTENDER(c)))) {
10005 COPY_BUF(l,buf,len,c);
10006 NEXTL(l);
10007 c = CUR_CHAR(l);
10008 if (len >= XML_MAX_NAMELEN) {
10009 /*
10010 * Okay someone managed to make a huge name, so he's ready to pay
10011 * for the processing speed.
10012 */
10013 xmlChar *buffer;
10014 int max = len * 2;
10015
10016 if (len > XML_MAX_NAME_LENGTH) {
10017 XP_ERRORNULL(XPATH_EXPR_ERROR);
10018 }
10019 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10020 if (buffer == NULL) {
10021 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10022 }
10023 memcpy(buffer, buf, len);
10024 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10025 (c == '.') || (c == '-') ||
10026 (c == '_') || ((qualified) && (c == ':')) ||
10027 (IS_COMBINING(c)) ||
10028 (IS_EXTENDER(c))) {
10029 if (len + 10 > max) {
10030 if (max > XML_MAX_NAME_LENGTH) {
10031 XP_ERRORNULL(XPATH_EXPR_ERROR);
10032 }
10033 max *= 2;
10034 buffer = (xmlChar *) xmlRealloc(buffer,
10035 max * sizeof(xmlChar));
10036 if (buffer == NULL) {
10037 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10038 }
10039 }
10040 COPY_BUF(l,buffer,len,c);
10041 NEXTL(l);
10042 c = CUR_CHAR(l);
10043 }
10044 buffer[len] = 0;
10045 return(buffer);
10046 }
10047 }
10048 if (len == 0)
10049 return(NULL);
10050 return(xmlStrndup(buf, len));
10051 }
10052
10053 #define MAX_FRAC 20
10054
10055 /**
10056 * xmlXPathStringEvalNumber:
10057 * @str: A string to scan
10058 *
10059 * [30a] Float ::= Number ('e' Digits?)?
10060 *
10061 * [30] Number ::= Digits ('.' Digits?)?
10062 * | '.' Digits
10063 * [31] Digits ::= [0-9]+
10064 *
10065 * Compile a Number in the string
10066 * In complement of the Number expression, this function also handles
10067 * negative values : '-' Number.
10068 *
10069 * Returns the double value.
10070 */
10071 double
xmlXPathStringEvalNumber(const xmlChar * str)10072 xmlXPathStringEvalNumber(const xmlChar *str) {
10073 const xmlChar *cur = str;
10074 double ret;
10075 int ok = 0;
10076 int isneg = 0;
10077 int exponent = 0;
10078 int is_exponent_negative = 0;
10079 #ifdef __GNUC__
10080 unsigned long tmp = 0;
10081 double temp;
10082 #endif
10083 if (cur == NULL) return(0);
10084 while (IS_BLANK_CH(*cur)) cur++;
10085 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10086 return(NAN);
10087 }
10088 if (*cur == '-') {
10089 isneg = 1;
10090 cur++;
10091 }
10092
10093 #ifdef __GNUC__
10094 /*
10095 * tmp/temp is a workaround against a gcc compiler bug
10096 * http://veillard.com/gcc.bug
10097 */
10098 ret = 0;
10099 while ((*cur >= '0') && (*cur <= '9')) {
10100 ret = ret * 10;
10101 tmp = (*cur - '0');
10102 ok = 1;
10103 cur++;
10104 temp = (double) tmp;
10105 ret = ret + temp;
10106 }
10107 #else
10108 ret = 0;
10109 while ((*cur >= '0') && (*cur <= '9')) {
10110 ret = ret * 10 + (*cur - '0');
10111 ok = 1;
10112 cur++;
10113 }
10114 #endif
10115
10116 if (*cur == '.') {
10117 int v, frac = 0, max;
10118 double fraction = 0;
10119
10120 cur++;
10121 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10122 return(NAN);
10123 }
10124 while (*cur == '0') {
10125 frac = frac + 1;
10126 cur++;
10127 }
10128 max = frac + MAX_FRAC;
10129 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10130 v = (*cur - '0');
10131 fraction = fraction * 10 + v;
10132 frac = frac + 1;
10133 cur++;
10134 }
10135 fraction /= pow(10.0, frac);
10136 ret = ret + fraction;
10137 while ((*cur >= '0') && (*cur <= '9'))
10138 cur++;
10139 }
10140 if ((*cur == 'e') || (*cur == 'E')) {
10141 cur++;
10142 if (*cur == '-') {
10143 is_exponent_negative = 1;
10144 cur++;
10145 } else if (*cur == '+') {
10146 cur++;
10147 }
10148 while ((*cur >= '0') && (*cur <= '9')) {
10149 if (exponent < 1000000)
10150 exponent = exponent * 10 + (*cur - '0');
10151 cur++;
10152 }
10153 }
10154 while (IS_BLANK_CH(*cur)) cur++;
10155 if (*cur != 0) return(NAN);
10156 if (isneg) ret = -ret;
10157 if (is_exponent_negative) exponent = -exponent;
10158 ret *= pow(10.0, (double)exponent);
10159 return(ret);
10160 }
10161
10162 /**
10163 * xmlXPathCompNumber:
10164 * @ctxt: the XPath Parser context
10165 *
10166 * [30] Number ::= Digits ('.' Digits?)?
10167 * | '.' Digits
10168 * [31] Digits ::= [0-9]+
10169 *
10170 * Compile a Number, then push it on the stack
10171 *
10172 */
10173 static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)10174 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10175 {
10176 double ret = 0.0;
10177 int ok = 0;
10178 int exponent = 0;
10179 int is_exponent_negative = 0;
10180 #ifdef __GNUC__
10181 unsigned long tmp = 0;
10182 double temp;
10183 #endif
10184
10185 CHECK_ERROR;
10186 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10187 XP_ERROR(XPATH_NUMBER_ERROR);
10188 }
10189 #ifdef __GNUC__
10190 /*
10191 * tmp/temp is a workaround against a gcc compiler bug
10192 * http://veillard.com/gcc.bug
10193 */
10194 ret = 0;
10195 while ((CUR >= '0') && (CUR <= '9')) {
10196 ret = ret * 10;
10197 tmp = (CUR - '0');
10198 ok = 1;
10199 NEXT;
10200 temp = (double) tmp;
10201 ret = ret + temp;
10202 }
10203 #else
10204 ret = 0;
10205 while ((CUR >= '0') && (CUR <= '9')) {
10206 ret = ret * 10 + (CUR - '0');
10207 ok = 1;
10208 NEXT;
10209 }
10210 #endif
10211 if (CUR == '.') {
10212 int v, frac = 0, max;
10213 double fraction = 0;
10214
10215 NEXT;
10216 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10217 XP_ERROR(XPATH_NUMBER_ERROR);
10218 }
10219 while (CUR == '0') {
10220 frac = frac + 1;
10221 NEXT;
10222 }
10223 max = frac + MAX_FRAC;
10224 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10225 v = (CUR - '0');
10226 fraction = fraction * 10 + v;
10227 frac = frac + 1;
10228 NEXT;
10229 }
10230 fraction /= pow(10.0, frac);
10231 ret = ret + fraction;
10232 while ((CUR >= '0') && (CUR <= '9'))
10233 NEXT;
10234 }
10235 if ((CUR == 'e') || (CUR == 'E')) {
10236 NEXT;
10237 if (CUR == '-') {
10238 is_exponent_negative = 1;
10239 NEXT;
10240 } else if (CUR == '+') {
10241 NEXT;
10242 }
10243 while ((CUR >= '0') && (CUR <= '9')) {
10244 if (exponent < 1000000)
10245 exponent = exponent * 10 + (CUR - '0');
10246 NEXT;
10247 }
10248 if (is_exponent_negative)
10249 exponent = -exponent;
10250 ret *= pow(10.0, (double) exponent);
10251 }
10252 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10253 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10254 }
10255
10256 /**
10257 * xmlXPathParseLiteral:
10258 * @ctxt: the XPath Parser context
10259 *
10260 * Parse a Literal
10261 *
10262 * [29] Literal ::= '"' [^"]* '"'
10263 * | "'" [^']* "'"
10264 *
10265 * Returns the value found or NULL in case of error
10266 */
10267 static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt)10268 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10269 const xmlChar *q;
10270 xmlChar *ret = NULL;
10271
10272 if (CUR == '"') {
10273 NEXT;
10274 q = CUR_PTR;
10275 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10276 NEXT;
10277 if (!IS_CHAR_CH(CUR)) {
10278 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10279 } else {
10280 ret = xmlStrndup(q, CUR_PTR - q);
10281 NEXT;
10282 }
10283 } else if (CUR == '\'') {
10284 NEXT;
10285 q = CUR_PTR;
10286 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10287 NEXT;
10288 if (!IS_CHAR_CH(CUR)) {
10289 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10290 } else {
10291 ret = xmlStrndup(q, CUR_PTR - q);
10292 NEXT;
10293 }
10294 } else {
10295 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10296 }
10297 return(ret);
10298 }
10299
10300 /**
10301 * xmlXPathCompLiteral:
10302 * @ctxt: the XPath Parser context
10303 *
10304 * Parse a Literal and push it on the stack.
10305 *
10306 * [29] Literal ::= '"' [^"]* '"'
10307 * | "'" [^']* "'"
10308 *
10309 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10310 */
10311 static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt)10312 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10313 const xmlChar *q;
10314 xmlChar *ret = NULL;
10315
10316 if (CUR == '"') {
10317 NEXT;
10318 q = CUR_PTR;
10319 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10320 NEXT;
10321 if (!IS_CHAR_CH(CUR)) {
10322 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10323 } else {
10324 ret = xmlStrndup(q, CUR_PTR - q);
10325 NEXT;
10326 }
10327 } else if (CUR == '\'') {
10328 NEXT;
10329 q = CUR_PTR;
10330 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10331 NEXT;
10332 if (!IS_CHAR_CH(CUR)) {
10333 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10334 } else {
10335 ret = xmlStrndup(q, CUR_PTR - q);
10336 NEXT;
10337 }
10338 } else {
10339 XP_ERROR(XPATH_START_LITERAL_ERROR);
10340 }
10341 if (ret == NULL) return;
10342 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10343 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10344 xmlFree(ret);
10345 }
10346
10347 /**
10348 * xmlXPathCompVariableReference:
10349 * @ctxt: the XPath Parser context
10350 *
10351 * Parse a VariableReference, evaluate it and push it on the stack.
10352 *
10353 * The variable bindings consist of a mapping from variable names
10354 * to variable values. The value of a variable is an object, which can be
10355 * of any of the types that are possible for the value of an expression,
10356 * and may also be of additional types not specified here.
10357 *
10358 * Early evaluation is possible since:
10359 * The variable bindings [...] used to evaluate a subexpression are
10360 * always the same as those used to evaluate the containing expression.
10361 *
10362 * [36] VariableReference ::= '$' QName
10363 */
10364 static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt)10365 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10366 xmlChar *name;
10367 xmlChar *prefix;
10368
10369 SKIP_BLANKS;
10370 if (CUR != '$') {
10371 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10372 }
10373 NEXT;
10374 name = xmlXPathParseQName(ctxt, &prefix);
10375 if (name == NULL) {
10376 xmlFree(prefix);
10377 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10378 }
10379 ctxt->comp->last = -1;
10380 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10381 name, prefix);
10382 SKIP_BLANKS;
10383 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10384 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10385 }
10386 }
10387
10388 /**
10389 * xmlXPathIsNodeType:
10390 * @name: a name string
10391 *
10392 * Is the name given a NodeType one.
10393 *
10394 * [38] NodeType ::= 'comment'
10395 * | 'text'
10396 * | 'processing-instruction'
10397 * | 'node'
10398 *
10399 * Returns 1 if true 0 otherwise
10400 */
10401 int
xmlXPathIsNodeType(const xmlChar * name)10402 xmlXPathIsNodeType(const xmlChar *name) {
10403 if (name == NULL)
10404 return(0);
10405
10406 if (xmlStrEqual(name, BAD_CAST "node"))
10407 return(1);
10408 if (xmlStrEqual(name, BAD_CAST "text"))
10409 return(1);
10410 if (xmlStrEqual(name, BAD_CAST "comment"))
10411 return(1);
10412 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10413 return(1);
10414 return(0);
10415 }
10416
10417 /**
10418 * xmlXPathCompFunctionCall:
10419 * @ctxt: the XPath Parser context
10420 *
10421 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10422 * [17] Argument ::= Expr
10423 *
10424 * Compile a function call, the evaluation of all arguments are
10425 * pushed on the stack
10426 */
10427 static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt)10428 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10429 xmlChar *name;
10430 xmlChar *prefix;
10431 int nbargs = 0;
10432 int sort = 1;
10433
10434 name = xmlXPathParseQName(ctxt, &prefix);
10435 if (name == NULL) {
10436 xmlFree(prefix);
10437 XP_ERROR(XPATH_EXPR_ERROR);
10438 }
10439 SKIP_BLANKS;
10440 #ifdef DEBUG_EXPR
10441 if (prefix == NULL)
10442 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10443 name);
10444 else
10445 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10446 prefix, name);
10447 #endif
10448
10449 if (CUR != '(') {
10450 xmlFree(name);
10451 xmlFree(prefix);
10452 XP_ERROR(XPATH_EXPR_ERROR);
10453 }
10454 NEXT;
10455 SKIP_BLANKS;
10456
10457 /*
10458 * Optimization for count(): we don't need the node-set to be sorted.
10459 */
10460 if ((prefix == NULL) && (name[0] == 'c') &&
10461 xmlStrEqual(name, BAD_CAST "count"))
10462 {
10463 sort = 0;
10464 }
10465 ctxt->comp->last = -1;
10466 if (CUR != ')') {
10467 while (CUR != 0) {
10468 int op1 = ctxt->comp->last;
10469 ctxt->comp->last = -1;
10470 xmlXPathCompileExpr(ctxt, sort);
10471 if (ctxt->error != XPATH_EXPRESSION_OK) {
10472 xmlFree(name);
10473 xmlFree(prefix);
10474 return;
10475 }
10476 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10477 nbargs++;
10478 if (CUR == ')') break;
10479 if (CUR != ',') {
10480 xmlFree(name);
10481 xmlFree(prefix);
10482 XP_ERROR(XPATH_EXPR_ERROR);
10483 }
10484 NEXT;
10485 SKIP_BLANKS;
10486 }
10487 }
10488 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10489 name, prefix);
10490 NEXT;
10491 SKIP_BLANKS;
10492 }
10493
10494 /**
10495 * xmlXPathCompPrimaryExpr:
10496 * @ctxt: the XPath Parser context
10497 *
10498 * [15] PrimaryExpr ::= VariableReference
10499 * | '(' Expr ')'
10500 * | Literal
10501 * | Number
10502 * | FunctionCall
10503 *
10504 * Compile a primary expression.
10505 */
10506 static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt)10507 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10508 SKIP_BLANKS;
10509 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10510 else if (CUR == '(') {
10511 NEXT;
10512 SKIP_BLANKS;
10513 xmlXPathCompileExpr(ctxt, 1);
10514 CHECK_ERROR;
10515 if (CUR != ')') {
10516 XP_ERROR(XPATH_EXPR_ERROR);
10517 }
10518 NEXT;
10519 SKIP_BLANKS;
10520 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10521 xmlXPathCompNumber(ctxt);
10522 } else if ((CUR == '\'') || (CUR == '"')) {
10523 xmlXPathCompLiteral(ctxt);
10524 } else {
10525 xmlXPathCompFunctionCall(ctxt);
10526 }
10527 SKIP_BLANKS;
10528 }
10529
10530 /**
10531 * xmlXPathCompFilterExpr:
10532 * @ctxt: the XPath Parser context
10533 *
10534 * [20] FilterExpr ::= PrimaryExpr
10535 * | FilterExpr Predicate
10536 *
10537 * Compile a filter expression.
10538 * Square brackets are used to filter expressions in the same way that
10539 * they are used in location paths. It is an error if the expression to
10540 * be filtered does not evaluate to a node-set. The context node list
10541 * used for evaluating the expression in square brackets is the node-set
10542 * to be filtered listed in document order.
10543 */
10544
10545 static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt)10546 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10547 xmlXPathCompPrimaryExpr(ctxt);
10548 CHECK_ERROR;
10549 SKIP_BLANKS;
10550
10551 while (CUR == '[') {
10552 xmlXPathCompPredicate(ctxt, 1);
10553 SKIP_BLANKS;
10554 }
10555
10556
10557 }
10558
10559 /**
10560 * xmlXPathScanName:
10561 * @ctxt: the XPath Parser context
10562 *
10563 * Trickery: parse an XML name but without consuming the input flow
10564 * Needed to avoid insanity in the parser state.
10565 *
10566 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10567 * CombiningChar | Extender
10568 *
10569 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10570 *
10571 * [6] Names ::= Name (S Name)*
10572 *
10573 * Returns the Name parsed or NULL
10574 */
10575
10576 static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt)10577 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10578 int len = 0, l;
10579 int c;
10580 const xmlChar *cur;
10581 xmlChar *ret;
10582
10583 cur = ctxt->cur;
10584
10585 c = CUR_CHAR(l);
10586 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10587 (!IS_LETTER(c) && (c != '_') &&
10588 (c != ':'))) {
10589 return(NULL);
10590 }
10591
10592 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10593 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10594 (c == '.') || (c == '-') ||
10595 (c == '_') || (c == ':') ||
10596 (IS_COMBINING(c)) ||
10597 (IS_EXTENDER(c)))) {
10598 len += l;
10599 NEXTL(l);
10600 c = CUR_CHAR(l);
10601 }
10602 ret = xmlStrndup(cur, ctxt->cur - cur);
10603 ctxt->cur = cur;
10604 return(ret);
10605 }
10606
10607 /**
10608 * xmlXPathCompPathExpr:
10609 * @ctxt: the XPath Parser context
10610 *
10611 * [19] PathExpr ::= LocationPath
10612 * | FilterExpr
10613 * | FilterExpr '/' RelativeLocationPath
10614 * | FilterExpr '//' RelativeLocationPath
10615 *
10616 * Compile a path expression.
10617 * The / operator and // operators combine an arbitrary expression
10618 * and a relative location path. It is an error if the expression
10619 * does not evaluate to a node-set.
10620 * The / operator does composition in the same way as when / is
10621 * used in a location path. As in location paths, // is short for
10622 * /descendant-or-self::node()/.
10623 */
10624
10625 static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt)10626 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10627 int lc = 1; /* Should we branch to LocationPath ? */
10628 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10629
10630 SKIP_BLANKS;
10631 if ((CUR == '$') || (CUR == '(') ||
10632 (IS_ASCII_DIGIT(CUR)) ||
10633 (CUR == '\'') || (CUR == '"') ||
10634 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10635 lc = 0;
10636 } else if (CUR == '*') {
10637 /* relative or absolute location path */
10638 lc = 1;
10639 } else if (CUR == '/') {
10640 /* relative or absolute location path */
10641 lc = 1;
10642 } else if (CUR == '@') {
10643 /* relative abbreviated attribute location path */
10644 lc = 1;
10645 } else if (CUR == '.') {
10646 /* relative abbreviated attribute location path */
10647 lc = 1;
10648 } else {
10649 /*
10650 * Problem is finding if we have a name here whether it's:
10651 * - a nodetype
10652 * - a function call in which case it's followed by '('
10653 * - an axis in which case it's followed by ':'
10654 * - a element name
10655 * We do an a priori analysis here rather than having to
10656 * maintain parsed token content through the recursive function
10657 * calls. This looks uglier but makes the code easier to
10658 * read/write/debug.
10659 */
10660 SKIP_BLANKS;
10661 name = xmlXPathScanName(ctxt);
10662 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10663 #ifdef DEBUG_STEP
10664 xmlGenericError(xmlGenericErrorContext,
10665 "PathExpr: Axis\n");
10666 #endif
10667 lc = 1;
10668 xmlFree(name);
10669 } else if (name != NULL) {
10670 int len =xmlStrlen(name);
10671
10672
10673 while (NXT(len) != 0) {
10674 if (NXT(len) == '/') {
10675 /* element name */
10676 #ifdef DEBUG_STEP
10677 xmlGenericError(xmlGenericErrorContext,
10678 "PathExpr: AbbrRelLocation\n");
10679 #endif
10680 lc = 1;
10681 break;
10682 } else if (IS_BLANK_CH(NXT(len))) {
10683 /* ignore blanks */
10684 ;
10685 } else if (NXT(len) == ':') {
10686 #ifdef DEBUG_STEP
10687 xmlGenericError(xmlGenericErrorContext,
10688 "PathExpr: AbbrRelLocation\n");
10689 #endif
10690 lc = 1;
10691 break;
10692 } else if ((NXT(len) == '(')) {
10693 /* Node Type or Function */
10694 if (xmlXPathIsNodeType(name)) {
10695 #ifdef DEBUG_STEP
10696 xmlGenericError(xmlGenericErrorContext,
10697 "PathExpr: Type search\n");
10698 #endif
10699 lc = 1;
10700 #ifdef LIBXML_XPTR_ENABLED
10701 } else if (ctxt->xptr &&
10702 xmlStrEqual(name, BAD_CAST "range-to")) {
10703 lc = 1;
10704 #endif
10705 } else {
10706 #ifdef DEBUG_STEP
10707 xmlGenericError(xmlGenericErrorContext,
10708 "PathExpr: function call\n");
10709 #endif
10710 lc = 0;
10711 }
10712 break;
10713 } else if ((NXT(len) == '[')) {
10714 /* element name */
10715 #ifdef DEBUG_STEP
10716 xmlGenericError(xmlGenericErrorContext,
10717 "PathExpr: AbbrRelLocation\n");
10718 #endif
10719 lc = 1;
10720 break;
10721 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10722 (NXT(len) == '=')) {
10723 lc = 1;
10724 break;
10725 } else {
10726 lc = 1;
10727 break;
10728 }
10729 len++;
10730 }
10731 if (NXT(len) == 0) {
10732 #ifdef DEBUG_STEP
10733 xmlGenericError(xmlGenericErrorContext,
10734 "PathExpr: AbbrRelLocation\n");
10735 #endif
10736 /* element name */
10737 lc = 1;
10738 }
10739 xmlFree(name);
10740 } else {
10741 /* make sure all cases are covered explicitly */
10742 XP_ERROR(XPATH_EXPR_ERROR);
10743 }
10744 }
10745
10746 if (lc) {
10747 if (CUR == '/') {
10748 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10749 } else {
10750 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10751 }
10752 xmlXPathCompLocationPath(ctxt);
10753 } else {
10754 xmlXPathCompFilterExpr(ctxt);
10755 CHECK_ERROR;
10756 if ((CUR == '/') && (NXT(1) == '/')) {
10757 SKIP(2);
10758 SKIP_BLANKS;
10759
10760 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10761 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10762
10763 xmlXPathCompRelativeLocationPath(ctxt);
10764 } else if (CUR == '/') {
10765 xmlXPathCompRelativeLocationPath(ctxt);
10766 }
10767 }
10768 SKIP_BLANKS;
10769 }
10770
10771 /**
10772 * xmlXPathCompUnionExpr:
10773 * @ctxt: the XPath Parser context
10774 *
10775 * [18] UnionExpr ::= PathExpr
10776 * | UnionExpr '|' PathExpr
10777 *
10778 * Compile an union expression.
10779 */
10780
10781 static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt)10782 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10783 xmlXPathCompPathExpr(ctxt);
10784 CHECK_ERROR;
10785 SKIP_BLANKS;
10786 while (CUR == '|') {
10787 int op1 = ctxt->comp->last;
10788 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10789
10790 NEXT;
10791 SKIP_BLANKS;
10792 xmlXPathCompPathExpr(ctxt);
10793
10794 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10795
10796 SKIP_BLANKS;
10797 }
10798 }
10799
10800 /**
10801 * xmlXPathCompUnaryExpr:
10802 * @ctxt: the XPath Parser context
10803 *
10804 * [27] UnaryExpr ::= UnionExpr
10805 * | '-' UnaryExpr
10806 *
10807 * Compile an unary expression.
10808 */
10809
10810 static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt)10811 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10812 int minus = 0;
10813 int found = 0;
10814
10815 SKIP_BLANKS;
10816 while (CUR == '-') {
10817 minus = 1 - minus;
10818 found = 1;
10819 NEXT;
10820 SKIP_BLANKS;
10821 }
10822
10823 xmlXPathCompUnionExpr(ctxt);
10824 CHECK_ERROR;
10825 if (found) {
10826 if (minus)
10827 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10828 else
10829 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10830 }
10831 }
10832
10833 /**
10834 * xmlXPathCompMultiplicativeExpr:
10835 * @ctxt: the XPath Parser context
10836 *
10837 * [26] MultiplicativeExpr ::= UnaryExpr
10838 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10839 * | MultiplicativeExpr 'div' UnaryExpr
10840 * | MultiplicativeExpr 'mod' UnaryExpr
10841 * [34] MultiplyOperator ::= '*'
10842 *
10843 * Compile an Additive expression.
10844 */
10845
10846 static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt)10847 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10848 xmlXPathCompUnaryExpr(ctxt);
10849 CHECK_ERROR;
10850 SKIP_BLANKS;
10851 while ((CUR == '*') ||
10852 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10853 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10854 int op = -1;
10855 int op1 = ctxt->comp->last;
10856
10857 if (CUR == '*') {
10858 op = 0;
10859 NEXT;
10860 } else if (CUR == 'd') {
10861 op = 1;
10862 SKIP(3);
10863 } else if (CUR == 'm') {
10864 op = 2;
10865 SKIP(3);
10866 }
10867 SKIP_BLANKS;
10868 xmlXPathCompUnaryExpr(ctxt);
10869 CHECK_ERROR;
10870 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10871 SKIP_BLANKS;
10872 }
10873 }
10874
10875 /**
10876 * xmlXPathCompAdditiveExpr:
10877 * @ctxt: the XPath Parser context
10878 *
10879 * [25] AdditiveExpr ::= MultiplicativeExpr
10880 * | AdditiveExpr '+' MultiplicativeExpr
10881 * | AdditiveExpr '-' MultiplicativeExpr
10882 *
10883 * Compile an Additive expression.
10884 */
10885
10886 static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt)10887 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10888
10889 xmlXPathCompMultiplicativeExpr(ctxt);
10890 CHECK_ERROR;
10891 SKIP_BLANKS;
10892 while ((CUR == '+') || (CUR == '-')) {
10893 int plus;
10894 int op1 = ctxt->comp->last;
10895
10896 if (CUR == '+') plus = 1;
10897 else plus = 0;
10898 NEXT;
10899 SKIP_BLANKS;
10900 xmlXPathCompMultiplicativeExpr(ctxt);
10901 CHECK_ERROR;
10902 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10903 SKIP_BLANKS;
10904 }
10905 }
10906
10907 /**
10908 * xmlXPathCompRelationalExpr:
10909 * @ctxt: the XPath Parser context
10910 *
10911 * [24] RelationalExpr ::= AdditiveExpr
10912 * | RelationalExpr '<' AdditiveExpr
10913 * | RelationalExpr '>' AdditiveExpr
10914 * | RelationalExpr '<=' AdditiveExpr
10915 * | RelationalExpr '>=' AdditiveExpr
10916 *
10917 * A <= B > C is allowed ? Answer from James, yes with
10918 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10919 * which is basically what got implemented.
10920 *
10921 * Compile a Relational expression, then push the result
10922 * on the stack
10923 */
10924
10925 static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt)10926 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10927 xmlXPathCompAdditiveExpr(ctxt);
10928 CHECK_ERROR;
10929 SKIP_BLANKS;
10930 while ((CUR == '<') ||
10931 (CUR == '>') ||
10932 ((CUR == '<') && (NXT(1) == '=')) ||
10933 ((CUR == '>') && (NXT(1) == '='))) {
10934 int inf, strict;
10935 int op1 = ctxt->comp->last;
10936
10937 if (CUR == '<') inf = 1;
10938 else inf = 0;
10939 if (NXT(1) == '=') strict = 0;
10940 else strict = 1;
10941 NEXT;
10942 if (!strict) NEXT;
10943 SKIP_BLANKS;
10944 xmlXPathCompAdditiveExpr(ctxt);
10945 CHECK_ERROR;
10946 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10947 SKIP_BLANKS;
10948 }
10949 }
10950
10951 /**
10952 * xmlXPathCompEqualityExpr:
10953 * @ctxt: the XPath Parser context
10954 *
10955 * [23] EqualityExpr ::= RelationalExpr
10956 * | EqualityExpr '=' RelationalExpr
10957 * | EqualityExpr '!=' RelationalExpr
10958 *
10959 * A != B != C is allowed ? Answer from James, yes with
10960 * (RelationalExpr = RelationalExpr) = RelationalExpr
10961 * (RelationalExpr != RelationalExpr) != RelationalExpr
10962 * which is basically what got implemented.
10963 *
10964 * Compile an Equality expression.
10965 *
10966 */
10967 static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt)10968 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10969 xmlXPathCompRelationalExpr(ctxt);
10970 CHECK_ERROR;
10971 SKIP_BLANKS;
10972 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10973 int eq;
10974 int op1 = ctxt->comp->last;
10975
10976 if (CUR == '=') eq = 1;
10977 else eq = 0;
10978 NEXT;
10979 if (!eq) NEXT;
10980 SKIP_BLANKS;
10981 xmlXPathCompRelationalExpr(ctxt);
10982 CHECK_ERROR;
10983 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10984 SKIP_BLANKS;
10985 }
10986 }
10987
10988 /**
10989 * xmlXPathCompAndExpr:
10990 * @ctxt: the XPath Parser context
10991 *
10992 * [22] AndExpr ::= EqualityExpr
10993 * | AndExpr 'and' EqualityExpr
10994 *
10995 * Compile an AND expression.
10996 *
10997 */
10998 static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt)10999 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11000 xmlXPathCompEqualityExpr(ctxt);
11001 CHECK_ERROR;
11002 SKIP_BLANKS;
11003 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11004 int op1 = ctxt->comp->last;
11005 SKIP(3);
11006 SKIP_BLANKS;
11007 xmlXPathCompEqualityExpr(ctxt);
11008 CHECK_ERROR;
11009 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11010 SKIP_BLANKS;
11011 }
11012 }
11013
11014 /**
11015 * xmlXPathCompileExpr:
11016 * @ctxt: the XPath Parser context
11017 *
11018 * [14] Expr ::= OrExpr
11019 * [21] OrExpr ::= AndExpr
11020 * | OrExpr 'or' AndExpr
11021 *
11022 * Parse and compile an expression
11023 */
11024 static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt,int sort)11025 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11026 xmlXPathCompAndExpr(ctxt);
11027 CHECK_ERROR;
11028 SKIP_BLANKS;
11029 while ((CUR == 'o') && (NXT(1) == 'r')) {
11030 int op1 = ctxt->comp->last;
11031 SKIP(2);
11032 SKIP_BLANKS;
11033 xmlXPathCompAndExpr(ctxt);
11034 CHECK_ERROR;
11035 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11036 SKIP_BLANKS;
11037 }
11038 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11039 /* more ops could be optimized too */
11040 /*
11041 * This is the main place to eliminate sorting for
11042 * operations which don't require a sorted node-set.
11043 * E.g. count().
11044 */
11045 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11046 }
11047 }
11048
11049 /**
11050 * xmlXPathCompPredicate:
11051 * @ctxt: the XPath Parser context
11052 * @filter: act as a filter
11053 *
11054 * [8] Predicate ::= '[' PredicateExpr ']'
11055 * [9] PredicateExpr ::= Expr
11056 *
11057 * Compile a predicate expression
11058 */
11059 static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt,int filter)11060 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11061 int op1 = ctxt->comp->last;
11062
11063 SKIP_BLANKS;
11064 if (CUR != '[') {
11065 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11066 }
11067 NEXT;
11068 SKIP_BLANKS;
11069
11070 ctxt->comp->last = -1;
11071 /*
11072 * This call to xmlXPathCompileExpr() will deactivate sorting
11073 * of the predicate result.
11074 * TODO: Sorting is still activated for filters, since I'm not
11075 * sure if needed. Normally sorting should not be needed, since
11076 * a filter can only diminish the number of items in a sequence,
11077 * but won't change its order; so if the initial sequence is sorted,
11078 * subsequent sorting is not needed.
11079 */
11080 if (! filter)
11081 xmlXPathCompileExpr(ctxt, 0);
11082 else
11083 xmlXPathCompileExpr(ctxt, 1);
11084 CHECK_ERROR;
11085
11086 if (CUR != ']') {
11087 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11088 }
11089
11090 if (filter)
11091 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11092 else
11093 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11094
11095 NEXT;
11096 SKIP_BLANKS;
11097 }
11098
11099 /**
11100 * xmlXPathCompNodeTest:
11101 * @ctxt: the XPath Parser context
11102 * @test: pointer to a xmlXPathTestVal
11103 * @type: pointer to a xmlXPathTypeVal
11104 * @prefix: placeholder for a possible name prefix
11105 *
11106 * [7] NodeTest ::= NameTest
11107 * | NodeType '(' ')'
11108 * | 'processing-instruction' '(' Literal ')'
11109 *
11110 * [37] NameTest ::= '*'
11111 * | NCName ':' '*'
11112 * | QName
11113 * [38] NodeType ::= 'comment'
11114 * | 'text'
11115 * | 'processing-instruction'
11116 * | 'node'
11117 *
11118 * Returns the name found and updates @test, @type and @prefix appropriately
11119 */
11120 static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt,xmlXPathTestVal * test,xmlXPathTypeVal * type,const xmlChar ** prefix,xmlChar * name)11121 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11122 xmlXPathTypeVal *type, const xmlChar **prefix,
11123 xmlChar *name) {
11124 int blanks;
11125
11126 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11127 STRANGE;
11128 return(NULL);
11129 }
11130 *type = (xmlXPathTypeVal) 0;
11131 *test = (xmlXPathTestVal) 0;
11132 *prefix = NULL;
11133 SKIP_BLANKS;
11134
11135 if ((name == NULL) && (CUR == '*')) {
11136 /*
11137 * All elements
11138 */
11139 NEXT;
11140 *test = NODE_TEST_ALL;
11141 return(NULL);
11142 }
11143
11144 if (name == NULL)
11145 name = xmlXPathParseNCName(ctxt);
11146 if (name == NULL) {
11147 XP_ERRORNULL(XPATH_EXPR_ERROR);
11148 }
11149
11150 blanks = IS_BLANK_CH(CUR);
11151 SKIP_BLANKS;
11152 if (CUR == '(') {
11153 NEXT;
11154 /*
11155 * NodeType or PI search
11156 */
11157 if (xmlStrEqual(name, BAD_CAST "comment"))
11158 *type = NODE_TYPE_COMMENT;
11159 else if (xmlStrEqual(name, BAD_CAST "node"))
11160 *type = NODE_TYPE_NODE;
11161 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11162 *type = NODE_TYPE_PI;
11163 else if (xmlStrEqual(name, BAD_CAST "text"))
11164 *type = NODE_TYPE_TEXT;
11165 else {
11166 if (name != NULL)
11167 xmlFree(name);
11168 XP_ERRORNULL(XPATH_EXPR_ERROR);
11169 }
11170
11171 *test = NODE_TEST_TYPE;
11172
11173 SKIP_BLANKS;
11174 if (*type == NODE_TYPE_PI) {
11175 /*
11176 * Specific case: search a PI by name.
11177 */
11178 if (name != NULL)
11179 xmlFree(name);
11180 name = NULL;
11181 if (CUR != ')') {
11182 name = xmlXPathParseLiteral(ctxt);
11183 CHECK_ERROR NULL;
11184 *test = NODE_TEST_PI;
11185 SKIP_BLANKS;
11186 }
11187 }
11188 if (CUR != ')') {
11189 if (name != NULL)
11190 xmlFree(name);
11191 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11192 }
11193 NEXT;
11194 return(name);
11195 }
11196 *test = NODE_TEST_NAME;
11197 if ((!blanks) && (CUR == ':')) {
11198 NEXT;
11199
11200 /*
11201 * Since currently the parser context don't have a
11202 * namespace list associated:
11203 * The namespace name for this prefix can be computed
11204 * only at evaluation time. The compilation is done
11205 * outside of any context.
11206 */
11207 #if 0
11208 *prefix = xmlXPathNsLookup(ctxt->context, name);
11209 if (name != NULL)
11210 xmlFree(name);
11211 if (*prefix == NULL) {
11212 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11213 }
11214 #else
11215 *prefix = name;
11216 #endif
11217
11218 if (CUR == '*') {
11219 /*
11220 * All elements
11221 */
11222 NEXT;
11223 *test = NODE_TEST_ALL;
11224 return(NULL);
11225 }
11226
11227 name = xmlXPathParseNCName(ctxt);
11228 if (name == NULL) {
11229 XP_ERRORNULL(XPATH_EXPR_ERROR);
11230 }
11231 }
11232 return(name);
11233 }
11234
11235 /**
11236 * xmlXPathIsAxisName:
11237 * @name: a preparsed name token
11238 *
11239 * [6] AxisName ::= 'ancestor'
11240 * | 'ancestor-or-self'
11241 * | 'attribute'
11242 * | 'child'
11243 * | 'descendant'
11244 * | 'descendant-or-self'
11245 * | 'following'
11246 * | 'following-sibling'
11247 * | 'namespace'
11248 * | 'parent'
11249 * | 'preceding'
11250 * | 'preceding-sibling'
11251 * | 'self'
11252 *
11253 * Returns the axis or 0
11254 */
11255 static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar * name)11256 xmlXPathIsAxisName(const xmlChar *name) {
11257 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11258 switch (name[0]) {
11259 case 'a':
11260 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11261 ret = AXIS_ANCESTOR;
11262 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11263 ret = AXIS_ANCESTOR_OR_SELF;
11264 if (xmlStrEqual(name, BAD_CAST "attribute"))
11265 ret = AXIS_ATTRIBUTE;
11266 break;
11267 case 'c':
11268 if (xmlStrEqual(name, BAD_CAST "child"))
11269 ret = AXIS_CHILD;
11270 break;
11271 case 'd':
11272 if (xmlStrEqual(name, BAD_CAST "descendant"))
11273 ret = AXIS_DESCENDANT;
11274 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11275 ret = AXIS_DESCENDANT_OR_SELF;
11276 break;
11277 case 'f':
11278 if (xmlStrEqual(name, BAD_CAST "following"))
11279 ret = AXIS_FOLLOWING;
11280 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11281 ret = AXIS_FOLLOWING_SIBLING;
11282 break;
11283 case 'n':
11284 if (xmlStrEqual(name, BAD_CAST "namespace"))
11285 ret = AXIS_NAMESPACE;
11286 break;
11287 case 'p':
11288 if (xmlStrEqual(name, BAD_CAST "parent"))
11289 ret = AXIS_PARENT;
11290 if (xmlStrEqual(name, BAD_CAST "preceding"))
11291 ret = AXIS_PRECEDING;
11292 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11293 ret = AXIS_PRECEDING_SIBLING;
11294 break;
11295 case 's':
11296 if (xmlStrEqual(name, BAD_CAST "self"))
11297 ret = AXIS_SELF;
11298 break;
11299 }
11300 return(ret);
11301 }
11302
11303 /**
11304 * xmlXPathCompStep:
11305 * @ctxt: the XPath Parser context
11306 *
11307 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11308 * | AbbreviatedStep
11309 *
11310 * [12] AbbreviatedStep ::= '.' | '..'
11311 *
11312 * [5] AxisSpecifier ::= AxisName '::'
11313 * | AbbreviatedAxisSpecifier
11314 *
11315 * [13] AbbreviatedAxisSpecifier ::= '@'?
11316 *
11317 * Modified for XPtr range support as:
11318 *
11319 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11320 * | AbbreviatedStep
11321 * | 'range-to' '(' Expr ')' Predicate*
11322 *
11323 * Compile one step in a Location Path
11324 * A location step of . is short for self::node(). This is
11325 * particularly useful in conjunction with //. For example, the
11326 * location path .//para is short for
11327 * self::node()/descendant-or-self::node()/child::para
11328 * and so will select all para descendant elements of the context
11329 * node.
11330 * Similarly, a location step of .. is short for parent::node().
11331 * For example, ../title is short for parent::node()/child::title
11332 * and so will select the title children of the parent of the context
11333 * node.
11334 */
11335 static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt)11336 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11337 #ifdef LIBXML_XPTR_ENABLED
11338 int rangeto = 0;
11339 int op2 = -1;
11340 #endif
11341
11342 SKIP_BLANKS;
11343 if ((CUR == '.') && (NXT(1) == '.')) {
11344 SKIP(2);
11345 SKIP_BLANKS;
11346 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11347 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11348 } else if (CUR == '.') {
11349 NEXT;
11350 SKIP_BLANKS;
11351 } else {
11352 xmlChar *name = NULL;
11353 const xmlChar *prefix = NULL;
11354 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11355 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11356 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11357 int op1;
11358
11359 /*
11360 * The modification needed for XPointer change to the production
11361 */
11362 #ifdef LIBXML_XPTR_ENABLED
11363 if (ctxt->xptr) {
11364 name = xmlXPathParseNCName(ctxt);
11365 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11366 op2 = ctxt->comp->last;
11367 xmlFree(name);
11368 SKIP_BLANKS;
11369 if (CUR != '(') {
11370 XP_ERROR(XPATH_EXPR_ERROR);
11371 }
11372 NEXT;
11373 SKIP_BLANKS;
11374
11375 xmlXPathCompileExpr(ctxt, 1);
11376 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11377 CHECK_ERROR;
11378
11379 SKIP_BLANKS;
11380 if (CUR != ')') {
11381 XP_ERROR(XPATH_EXPR_ERROR);
11382 }
11383 NEXT;
11384 rangeto = 1;
11385 goto eval_predicates;
11386 }
11387 }
11388 #endif
11389 if (CUR == '*') {
11390 axis = AXIS_CHILD;
11391 } else {
11392 if (name == NULL)
11393 name = xmlXPathParseNCName(ctxt);
11394 if (name != NULL) {
11395 axis = xmlXPathIsAxisName(name);
11396 if (axis != 0) {
11397 SKIP_BLANKS;
11398 if ((CUR == ':') && (NXT(1) == ':')) {
11399 SKIP(2);
11400 xmlFree(name);
11401 name = NULL;
11402 } else {
11403 /* an element name can conflict with an axis one :-\ */
11404 axis = AXIS_CHILD;
11405 }
11406 } else {
11407 axis = AXIS_CHILD;
11408 }
11409 } else if (CUR == '@') {
11410 NEXT;
11411 axis = AXIS_ATTRIBUTE;
11412 } else {
11413 axis = AXIS_CHILD;
11414 }
11415 }
11416
11417 if (ctxt->error != XPATH_EXPRESSION_OK) {
11418 xmlFree(name);
11419 return;
11420 }
11421
11422 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11423 if (test == 0)
11424 return;
11425
11426 if ((prefix != NULL) && (ctxt->context != NULL) &&
11427 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11428 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11429 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11430 }
11431 }
11432 #ifdef DEBUG_STEP
11433 xmlGenericError(xmlGenericErrorContext,
11434 "Basis : computing new set\n");
11435 #endif
11436
11437 #ifdef DEBUG_STEP
11438 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11439 if (ctxt->value == NULL)
11440 xmlGenericError(xmlGenericErrorContext, "no value\n");
11441 else if (ctxt->value->nodesetval == NULL)
11442 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11443 else
11444 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11445 #endif
11446
11447 #ifdef LIBXML_XPTR_ENABLED
11448 eval_predicates:
11449 #endif
11450 op1 = ctxt->comp->last;
11451 ctxt->comp->last = -1;
11452
11453 SKIP_BLANKS;
11454 while (CUR == '[') {
11455 xmlXPathCompPredicate(ctxt, 0);
11456 }
11457
11458 #ifdef LIBXML_XPTR_ENABLED
11459 if (rangeto) {
11460 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11461 } else
11462 #endif
11463 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11464 test, type, (void *)prefix, (void *)name);
11465
11466 }
11467 #ifdef DEBUG_STEP
11468 xmlGenericError(xmlGenericErrorContext, "Step : ");
11469 if (ctxt->value == NULL)
11470 xmlGenericError(xmlGenericErrorContext, "no value\n");
11471 else if (ctxt->value->nodesetval == NULL)
11472 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11473 else
11474 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11475 ctxt->value->nodesetval);
11476 #endif
11477 }
11478
11479 /**
11480 * xmlXPathCompRelativeLocationPath:
11481 * @ctxt: the XPath Parser context
11482 *
11483 * [3] RelativeLocationPath ::= Step
11484 * | RelativeLocationPath '/' Step
11485 * | AbbreviatedRelativeLocationPath
11486 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11487 *
11488 * Compile a relative location path.
11489 */
11490 static void
xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt)11491 xmlXPathCompRelativeLocationPath
11492 (xmlXPathParserContextPtr ctxt) {
11493 SKIP_BLANKS;
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 } else if (CUR == '/') {
11500 NEXT;
11501 SKIP_BLANKS;
11502 }
11503 xmlXPathCompStep(ctxt);
11504 CHECK_ERROR;
11505 SKIP_BLANKS;
11506 while (CUR == '/') {
11507 if ((CUR == '/') && (NXT(1) == '/')) {
11508 SKIP(2);
11509 SKIP_BLANKS;
11510 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11511 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11512 xmlXPathCompStep(ctxt);
11513 } else if (CUR == '/') {
11514 NEXT;
11515 SKIP_BLANKS;
11516 xmlXPathCompStep(ctxt);
11517 }
11518 SKIP_BLANKS;
11519 }
11520 }
11521
11522 /**
11523 * xmlXPathCompLocationPath:
11524 * @ctxt: the XPath Parser context
11525 *
11526 * [1] LocationPath ::= RelativeLocationPath
11527 * | AbsoluteLocationPath
11528 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11529 * | AbbreviatedAbsoluteLocationPath
11530 * [10] AbbreviatedAbsoluteLocationPath ::=
11531 * '//' RelativeLocationPath
11532 *
11533 * Compile a location path
11534 *
11535 * // is short for /descendant-or-self::node()/. For example,
11536 * //para is short for /descendant-or-self::node()/child::para and
11537 * so will select any para element in the document (even a para element
11538 * that is a document element will be selected by //para since the
11539 * document element node is a child of the root node); div//para is
11540 * short for div/descendant-or-self::node()/child::para and so will
11541 * select all para descendants of div children.
11542 */
11543 static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt)11544 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11545 SKIP_BLANKS;
11546 if (CUR != '/') {
11547 xmlXPathCompRelativeLocationPath(ctxt);
11548 } else {
11549 while (CUR == '/') {
11550 if ((CUR == '/') && (NXT(1) == '/')) {
11551 SKIP(2);
11552 SKIP_BLANKS;
11553 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11554 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11555 xmlXPathCompRelativeLocationPath(ctxt);
11556 } else if (CUR == '/') {
11557 NEXT;
11558 SKIP_BLANKS;
11559 if ((CUR != 0 ) &&
11560 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11561 (CUR == '@') || (CUR == '*')))
11562 xmlXPathCompRelativeLocationPath(ctxt);
11563 }
11564 CHECK_ERROR;
11565 }
11566 }
11567 }
11568
11569 /************************************************************************
11570 * *
11571 * XPath precompiled expression evaluation *
11572 * *
11573 ************************************************************************/
11574
11575 static int
11576 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11577
11578 #ifdef DEBUG_STEP
11579 static void
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,int nbNodes)11580 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11581 int nbNodes)
11582 {
11583 xmlGenericError(xmlGenericErrorContext, "new step : ");
11584 switch (op->value) {
11585 case AXIS_ANCESTOR:
11586 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11587 break;
11588 case AXIS_ANCESTOR_OR_SELF:
11589 xmlGenericError(xmlGenericErrorContext,
11590 "axis 'ancestors-or-self' ");
11591 break;
11592 case AXIS_ATTRIBUTE:
11593 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11594 break;
11595 case AXIS_CHILD:
11596 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11597 break;
11598 case AXIS_DESCENDANT:
11599 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11600 break;
11601 case AXIS_DESCENDANT_OR_SELF:
11602 xmlGenericError(xmlGenericErrorContext,
11603 "axis 'descendant-or-self' ");
11604 break;
11605 case AXIS_FOLLOWING:
11606 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11607 break;
11608 case AXIS_FOLLOWING_SIBLING:
11609 xmlGenericError(xmlGenericErrorContext,
11610 "axis 'following-siblings' ");
11611 break;
11612 case AXIS_NAMESPACE:
11613 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11614 break;
11615 case AXIS_PARENT:
11616 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11617 break;
11618 case AXIS_PRECEDING:
11619 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11620 break;
11621 case AXIS_PRECEDING_SIBLING:
11622 xmlGenericError(xmlGenericErrorContext,
11623 "axis 'preceding-sibling' ");
11624 break;
11625 case AXIS_SELF:
11626 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11627 break;
11628 }
11629 xmlGenericError(xmlGenericErrorContext,
11630 " context contains %d nodes\n", nbNodes);
11631 switch (op->value2) {
11632 case NODE_TEST_NONE:
11633 xmlGenericError(xmlGenericErrorContext,
11634 " searching for none !!!\n");
11635 break;
11636 case NODE_TEST_TYPE:
11637 xmlGenericError(xmlGenericErrorContext,
11638 " searching for type %d\n", op->value3);
11639 break;
11640 case NODE_TEST_PI:
11641 xmlGenericError(xmlGenericErrorContext,
11642 " searching for PI !!!\n");
11643 break;
11644 case NODE_TEST_ALL:
11645 xmlGenericError(xmlGenericErrorContext,
11646 " searching for *\n");
11647 break;
11648 case NODE_TEST_NS:
11649 xmlGenericError(xmlGenericErrorContext,
11650 " searching for namespace %s\n",
11651 op->value5);
11652 break;
11653 case NODE_TEST_NAME:
11654 xmlGenericError(xmlGenericErrorContext,
11655 " searching for name %s\n", op->value5);
11656 if (op->value4)
11657 xmlGenericError(xmlGenericErrorContext,
11658 " with namespace %s\n", op->value4);
11659 break;
11660 }
11661 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11662 }
11663 #endif /* DEBUG_STEP */
11664
11665 static int
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int hasNsNodes)11666 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11667 xmlXPathStepOpPtr op,
11668 xmlNodeSetPtr set,
11669 int contextSize,
11670 int hasNsNodes)
11671 {
11672 if (op->ch1 != -1) {
11673 xmlXPathCompExprPtr comp = ctxt->comp;
11674 /*
11675 * Process inner predicates first.
11676 */
11677 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11678 /*
11679 * TODO: raise an internal error.
11680 */
11681 }
11682 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11683 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11684 CHECK_ERROR0;
11685 if (contextSize <= 0)
11686 return(0);
11687 }
11688 if (op->ch2 != -1) {
11689 xmlXPathContextPtr xpctxt = ctxt->context;
11690 xmlNodePtr contextNode, oldContextNode;
11691 xmlDocPtr oldContextDoc;
11692 int oldcs, oldpp;
11693 int i, res, contextPos = 0, newContextSize;
11694 xmlXPathStepOpPtr exprOp;
11695 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11696
11697 #ifdef LIBXML_XPTR_ENABLED
11698 /*
11699 * URGENT TODO: Check the following:
11700 * We don't expect location sets if evaluating prediates, right?
11701 * Only filters should expect location sets, right?
11702 */
11703 #endif
11704 /*
11705 * SPEC XPath 1.0:
11706 * "For each node in the node-set to be filtered, the
11707 * PredicateExpr is evaluated with that node as the
11708 * context node, with the number of nodes in the
11709 * node-set as the context size, and with the proximity
11710 * position of the node in the node-set with respect to
11711 * the axis as the context position;"
11712 * @oldset is the node-set" to be filtered.
11713 *
11714 * SPEC XPath 1.0:
11715 * "only predicates change the context position and
11716 * context size (see [2.4 Predicates])."
11717 * Example:
11718 * node-set context pos
11719 * nA 1
11720 * nB 2
11721 * nC 3
11722 * After applying predicate [position() > 1] :
11723 * node-set context pos
11724 * nB 1
11725 * nC 2
11726 */
11727 oldContextNode = xpctxt->node;
11728 oldContextDoc = xpctxt->doc;
11729 oldcs = xpctxt->contextSize;
11730 oldpp = xpctxt->proximityPosition;
11731 /*
11732 * Get the expression of this predicate.
11733 */
11734 exprOp = &ctxt->comp->steps[op->ch2];
11735 newContextSize = 0;
11736 for (i = 0; i < set->nodeNr; i++) {
11737 if (set->nodeTab[i] == NULL)
11738 continue;
11739
11740 contextNode = set->nodeTab[i];
11741 xpctxt->node = contextNode;
11742 xpctxt->contextSize = contextSize;
11743 xpctxt->proximityPosition = ++contextPos;
11744
11745 /*
11746 * Also set the xpath document in case things like
11747 * key() are evaluated in the predicate.
11748 */
11749 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11750 (contextNode->doc != NULL))
11751 xpctxt->doc = contextNode->doc;
11752 /*
11753 * Evaluate the predicate expression with 1 context node
11754 * at a time; this node is packaged into a node set; this
11755 * node set is handed over to the evaluation mechanism.
11756 */
11757 if (contextObj == NULL)
11758 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11759 else {
11760 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11761 contextNode) < 0) {
11762 ctxt->error = XPATH_MEMORY_ERROR;
11763 goto evaluation_exit;
11764 }
11765 }
11766
11767 valuePush(ctxt, contextObj);
11768
11769 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11770
11771 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11772 xmlXPathNodeSetClear(set, hasNsNodes);
11773 newContextSize = 0;
11774 goto evaluation_exit;
11775 }
11776
11777 if (res != 0) {
11778 newContextSize++;
11779 } else {
11780 /*
11781 * Remove the entry from the initial node set.
11782 */
11783 set->nodeTab[i] = NULL;
11784 if (contextNode->type == XML_NAMESPACE_DECL)
11785 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11786 }
11787 if (ctxt->value == contextObj) {
11788 /*
11789 * Don't free the temporary XPath object holding the
11790 * context node, in order to avoid massive recreation
11791 * inside this loop.
11792 */
11793 valuePop(ctxt);
11794 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11795 } else {
11796 /*
11797 * TODO: The object was lost in the evaluation machinery.
11798 * Can this happen? Maybe in internal-error cases.
11799 */
11800 contextObj = NULL;
11801 }
11802 }
11803
11804 if (contextObj != NULL) {
11805 if (ctxt->value == contextObj)
11806 valuePop(ctxt);
11807 xmlXPathReleaseObject(xpctxt, contextObj);
11808 }
11809 evaluation_exit:
11810 if (exprRes != NULL)
11811 xmlXPathReleaseObject(ctxt->context, exprRes);
11812 /*
11813 * Reset/invalidate the context.
11814 */
11815 xpctxt->node = oldContextNode;
11816 xpctxt->doc = oldContextDoc;
11817 xpctxt->contextSize = oldcs;
11818 xpctxt->proximityPosition = oldpp;
11819 return(newContextSize);
11820 }
11821 return(contextSize);
11822 }
11823
11824 static int
xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodeSetPtr set,int contextSize,int minPos,int maxPos,int hasNsNodes)11825 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11826 xmlXPathStepOpPtr op,
11827 xmlNodeSetPtr set,
11828 int contextSize,
11829 int minPos,
11830 int maxPos,
11831 int hasNsNodes)
11832 {
11833 if (op->ch1 != -1) {
11834 xmlXPathCompExprPtr comp = ctxt->comp;
11835 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11836 /*
11837 * TODO: raise an internal error.
11838 */
11839 }
11840 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11841 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11842 CHECK_ERROR0;
11843 if (contextSize <= 0)
11844 return(0);
11845 }
11846 /*
11847 * Check if the node set contains a sufficient number of nodes for
11848 * the requested range.
11849 */
11850 if (contextSize < minPos) {
11851 xmlXPathNodeSetClear(set, hasNsNodes);
11852 return(0);
11853 }
11854 if (op->ch2 == -1) {
11855 /*
11856 * TODO: Can this ever happen?
11857 */
11858 return (contextSize);
11859 } else {
11860 xmlDocPtr oldContextDoc;
11861 int oldcs, oldpp;
11862 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11863 xmlXPathStepOpPtr exprOp;
11864 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11865 xmlNodePtr oldContextNode, contextNode = NULL;
11866 xmlXPathContextPtr xpctxt = ctxt->context;
11867 int frame;
11868
11869 #ifdef LIBXML_XPTR_ENABLED
11870 /*
11871 * URGENT TODO: Check the following:
11872 * We don't expect location sets if evaluating prediates, right?
11873 * Only filters should expect location sets, right?
11874 */
11875 #endif /* LIBXML_XPTR_ENABLED */
11876
11877 /*
11878 * Save old context.
11879 */
11880 oldContextNode = xpctxt->node;
11881 oldContextDoc = xpctxt->doc;
11882 oldcs = xpctxt->contextSize;
11883 oldpp = xpctxt->proximityPosition;
11884 /*
11885 * Get the expression of this predicate.
11886 */
11887 exprOp = &ctxt->comp->steps[op->ch2];
11888 for (i = 0; i < set->nodeNr; i++) {
11889 xmlXPathObjectPtr tmp;
11890
11891 if (set->nodeTab[i] == NULL)
11892 continue;
11893
11894 contextNode = set->nodeTab[i];
11895 xpctxt->node = contextNode;
11896 xpctxt->contextSize = contextSize;
11897 xpctxt->proximityPosition = ++contextPos;
11898
11899 /*
11900 * Initialize the new set.
11901 * Also set the xpath document in case things like
11902 * key() evaluation are attempted on the predicate
11903 */
11904 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11905 (contextNode->doc != NULL))
11906 xpctxt->doc = contextNode->doc;
11907 /*
11908 * Evaluate the predicate expression with 1 context node
11909 * at a time; this node is packaged into a node set; this
11910 * node set is handed over to the evaluation mechanism.
11911 */
11912 if (contextObj == NULL)
11913 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11914 else {
11915 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11916 contextNode) < 0) {
11917 ctxt->error = XPATH_MEMORY_ERROR;
11918 goto evaluation_exit;
11919 }
11920 }
11921
11922 valuePush(ctxt, contextObj);
11923 frame = xmlXPathSetFrame(ctxt);
11924 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11925 xmlXPathPopFrame(ctxt, frame);
11926 tmp = valuePop(ctxt);
11927
11928 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11929 while (tmp != contextObj) {
11930 /*
11931 * Free up the result
11932 * then pop off contextObj, which will be freed later
11933 */
11934 xmlXPathReleaseObject(xpctxt, tmp);
11935 tmp = valuePop(ctxt);
11936 }
11937 goto evaluation_error;
11938 }
11939 /* push the result back onto the stack */
11940 valuePush(ctxt, tmp);
11941
11942 if (res)
11943 pos++;
11944
11945 if (res && (pos >= minPos) && (pos <= maxPos)) {
11946 /*
11947 * Fits in the requested range.
11948 */
11949 newContextSize++;
11950 if (minPos == maxPos) {
11951 /*
11952 * Only 1 node was requested.
11953 */
11954 if (contextNode->type == XML_NAMESPACE_DECL) {
11955 /*
11956 * As always: take care of those nasty
11957 * namespace nodes.
11958 */
11959 set->nodeTab[i] = NULL;
11960 }
11961 xmlXPathNodeSetClear(set, hasNsNodes);
11962 set->nodeNr = 1;
11963 set->nodeTab[0] = contextNode;
11964 goto evaluation_exit;
11965 }
11966 if (pos == maxPos) {
11967 /*
11968 * We are done.
11969 */
11970 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11971 goto evaluation_exit;
11972 }
11973 } else {
11974 /*
11975 * Remove the entry from the initial node set.
11976 */
11977 set->nodeTab[i] = NULL;
11978 if (contextNode->type == XML_NAMESPACE_DECL)
11979 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11980 }
11981 if (exprRes != NULL) {
11982 xmlXPathReleaseObject(ctxt->context, exprRes);
11983 exprRes = NULL;
11984 }
11985 if (ctxt->value == contextObj) {
11986 /*
11987 * Don't free the temporary XPath object holding the
11988 * context node, in order to avoid massive recreation
11989 * inside this loop.
11990 */
11991 valuePop(ctxt);
11992 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11993 } else {
11994 /*
11995 * The object was lost in the evaluation machinery.
11996 * Can this happen? Maybe in case of internal-errors.
11997 */
11998 contextObj = NULL;
11999 }
12000 }
12001 goto evaluation_exit;
12002
12003 evaluation_error:
12004 xmlXPathNodeSetClear(set, hasNsNodes);
12005 newContextSize = 0;
12006
12007 evaluation_exit:
12008 if (contextObj != NULL) {
12009 if (ctxt->value == contextObj)
12010 valuePop(ctxt);
12011 xmlXPathReleaseObject(xpctxt, contextObj);
12012 }
12013 if (exprRes != NULL)
12014 xmlXPathReleaseObject(ctxt->context, exprRes);
12015 /*
12016 * Reset/invalidate the context.
12017 */
12018 xpctxt->node = oldContextNode;
12019 xpctxt->doc = oldContextDoc;
12020 xpctxt->contextSize = oldcs;
12021 xpctxt->proximityPosition = oldpp;
12022 return(newContextSize);
12023 }
12024 return(contextSize);
12025 }
12026
12027 static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int * maxPos)12028 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12029 xmlXPathStepOpPtr op,
12030 int *maxPos)
12031 {
12032
12033 xmlXPathStepOpPtr exprOp;
12034
12035 /*
12036 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12037 */
12038
12039 /*
12040 * If not -1, then ch1 will point to:
12041 * 1) For predicates (XPATH_OP_PREDICATE):
12042 * - an inner predicate operator
12043 * 2) For filters (XPATH_OP_FILTER):
12044 * - an inner filter operater OR
12045 * - an expression selecting the node set.
12046 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12047 */
12048 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12049 return(0);
12050
12051 if (op->ch2 != -1) {
12052 exprOp = &ctxt->comp->steps[op->ch2];
12053 } else
12054 return(0);
12055
12056 if ((exprOp != NULL) &&
12057 (exprOp->op == XPATH_OP_VALUE) &&
12058 (exprOp->value4 != NULL) &&
12059 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12060 {
12061 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12062
12063 /*
12064 * We have a "[n]" predicate here.
12065 * TODO: Unfortunately this simplistic test here is not
12066 * able to detect a position() predicate in compound
12067 * expressions like "[@attr = 'a" and position() = 1],
12068 * and even not the usage of position() in
12069 * "[position() = 1]"; thus - obviously - a position-range,
12070 * like it "[position() < 5]", is also not detected.
12071 * Maybe we could rewrite the AST to ease the optimization.
12072 */
12073
12074 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12075 *maxPos = (int) floatval;
12076 if (floatval == (double) *maxPos)
12077 return(1);
12078 }
12079 }
12080 return(0);
12081 }
12082
12083 static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first,xmlNodePtr * last,int toBool)12084 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12085 xmlXPathStepOpPtr op,
12086 xmlNodePtr * first, xmlNodePtr * last,
12087 int toBool)
12088 {
12089
12090 #define XP_TEST_HIT \
12091 if (hasAxisRange != 0) { \
12092 if (++pos == maxPos) { \
12093 if (addNode(seq, cur) < 0) \
12094 ctxt->error = XPATH_MEMORY_ERROR; \
12095 goto axis_range_end; } \
12096 } else { \
12097 if (addNode(seq, cur) < 0) \
12098 ctxt->error = XPATH_MEMORY_ERROR; \
12099 if (breakOnFirstHit) goto first_hit; }
12100
12101 #define XP_TEST_HIT_NS \
12102 if (hasAxisRange != 0) { \
12103 if (++pos == maxPos) { \
12104 hasNsNodes = 1; \
12105 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12106 ctxt->error = XPATH_MEMORY_ERROR; \
12107 goto axis_range_end; } \
12108 } else { \
12109 hasNsNodes = 1; \
12110 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12111 ctxt->error = XPATH_MEMORY_ERROR; \
12112 if (breakOnFirstHit) goto first_hit; }
12113
12114 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12115 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12116 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12117 const xmlChar *prefix = op->value4;
12118 const xmlChar *name = op->value5;
12119 const xmlChar *URI = NULL;
12120
12121 #ifdef DEBUG_STEP
12122 int nbMatches = 0, prevMatches = 0;
12123 #endif
12124 int total = 0, hasNsNodes = 0;
12125 /* The popped object holding the context nodes */
12126 xmlXPathObjectPtr obj;
12127 /* The set of context nodes for the node tests */
12128 xmlNodeSetPtr contextSeq;
12129 int contextIdx;
12130 xmlNodePtr contextNode;
12131 /* The final resulting node set wrt to all context nodes */
12132 xmlNodeSetPtr outSeq;
12133 /*
12134 * The temporary resulting node set wrt 1 context node.
12135 * Used to feed predicate evaluation.
12136 */
12137 xmlNodeSetPtr seq;
12138 xmlNodePtr cur;
12139 /* First predicate operator */
12140 xmlXPathStepOpPtr predOp;
12141 int maxPos; /* The requested position() (when a "[n]" predicate) */
12142 int hasPredicateRange, hasAxisRange, pos, size, newSize;
12143 int breakOnFirstHit;
12144
12145 xmlXPathTraversalFunction next = NULL;
12146 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12147 xmlXPathNodeSetMergeFunction mergeAndClear;
12148 xmlNodePtr oldContextNode;
12149 xmlXPathContextPtr xpctxt = ctxt->context;
12150
12151
12152 CHECK_TYPE0(XPATH_NODESET);
12153 obj = valuePop(ctxt);
12154 /*
12155 * Setup namespaces.
12156 */
12157 if (prefix != NULL) {
12158 URI = xmlXPathNsLookup(xpctxt, prefix);
12159 if (URI == NULL) {
12160 xmlXPathReleaseObject(xpctxt, obj);
12161 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12162 }
12163 }
12164 /*
12165 * Setup axis.
12166 *
12167 * MAYBE FUTURE TODO: merging optimizations:
12168 * - If the nodes to be traversed wrt to the initial nodes and
12169 * the current axis cannot overlap, then we could avoid searching
12170 * for duplicates during the merge.
12171 * But the question is how/when to evaluate if they cannot overlap.
12172 * Example: if we know that for two initial nodes, the one is
12173 * not in the ancestor-or-self axis of the other, then we could safely
12174 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12175 * the descendant-or-self axis.
12176 */
12177 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12178 switch (axis) {
12179 case AXIS_ANCESTOR:
12180 first = NULL;
12181 next = xmlXPathNextAncestor;
12182 break;
12183 case AXIS_ANCESTOR_OR_SELF:
12184 first = NULL;
12185 next = xmlXPathNextAncestorOrSelf;
12186 break;
12187 case AXIS_ATTRIBUTE:
12188 first = NULL;
12189 last = NULL;
12190 next = xmlXPathNextAttribute;
12191 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12192 break;
12193 case AXIS_CHILD:
12194 last = NULL;
12195 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12196 (type == NODE_TYPE_NODE))
12197 {
12198 /*
12199 * Optimization if an element node type is 'element'.
12200 */
12201 next = xmlXPathNextChildElement;
12202 } else
12203 next = xmlXPathNextChild;
12204 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12205 break;
12206 case AXIS_DESCENDANT:
12207 last = NULL;
12208 next = xmlXPathNextDescendant;
12209 break;
12210 case AXIS_DESCENDANT_OR_SELF:
12211 last = NULL;
12212 next = xmlXPathNextDescendantOrSelf;
12213 break;
12214 case AXIS_FOLLOWING:
12215 last = NULL;
12216 next = xmlXPathNextFollowing;
12217 break;
12218 case AXIS_FOLLOWING_SIBLING:
12219 last = NULL;
12220 next = xmlXPathNextFollowingSibling;
12221 break;
12222 case AXIS_NAMESPACE:
12223 first = NULL;
12224 last = NULL;
12225 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12226 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12227 break;
12228 case AXIS_PARENT:
12229 first = NULL;
12230 next = xmlXPathNextParent;
12231 break;
12232 case AXIS_PRECEDING:
12233 first = NULL;
12234 next = xmlXPathNextPrecedingInternal;
12235 break;
12236 case AXIS_PRECEDING_SIBLING:
12237 first = NULL;
12238 next = xmlXPathNextPrecedingSibling;
12239 break;
12240 case AXIS_SELF:
12241 first = NULL;
12242 last = NULL;
12243 next = xmlXPathNextSelf;
12244 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12245 break;
12246 }
12247
12248 #ifdef DEBUG_STEP
12249 xmlXPathDebugDumpStepAxis(op,
12250 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12251 #endif
12252
12253 if (next == NULL) {
12254 xmlXPathReleaseObject(xpctxt, obj);
12255 return(0);
12256 }
12257 contextSeq = obj->nodesetval;
12258 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12259 xmlXPathReleaseObject(xpctxt, obj);
12260 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12261 return(0);
12262 }
12263 /*
12264 * Predicate optimization ---------------------------------------------
12265 * If this step has a last predicate, which contains a position(),
12266 * then we'll optimize (although not exactly "position()", but only
12267 * the short-hand form, i.e., "[n]".
12268 *
12269 * Example - expression "/foo[parent::bar][1]":
12270 *
12271 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12272 * ROOT -- op->ch1
12273 * PREDICATE -- op->ch2 (predOp)
12274 * PREDICATE -- predOp->ch1 = [parent::bar]
12275 * SORT
12276 * COLLECT 'parent' 'name' 'node' bar
12277 * NODE
12278 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12279 *
12280 */
12281 maxPos = 0;
12282 predOp = NULL;
12283 hasPredicateRange = 0;
12284 hasAxisRange = 0;
12285 if (op->ch2 != -1) {
12286 /*
12287 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12288 */
12289 predOp = &ctxt->comp->steps[op->ch2];
12290 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12291 if (predOp->ch1 != -1) {
12292 /*
12293 * Use the next inner predicate operator.
12294 */
12295 predOp = &ctxt->comp->steps[predOp->ch1];
12296 hasPredicateRange = 1;
12297 } else {
12298 /*
12299 * There's no other predicate than the [n] predicate.
12300 */
12301 predOp = NULL;
12302 hasAxisRange = 1;
12303 }
12304 }
12305 }
12306 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12307 /*
12308 * Axis traversal -----------------------------------------------------
12309 */
12310 /*
12311 * 2.3 Node Tests
12312 * - For the attribute axis, the principal node type is attribute.
12313 * - For the namespace axis, the principal node type is namespace.
12314 * - For other axes, the principal node type is element.
12315 *
12316 * A node test * is true for any node of the
12317 * principal node type. For example, child::* will
12318 * select all element children of the context node
12319 */
12320 oldContextNode = xpctxt->node;
12321 addNode = xmlXPathNodeSetAddUnique;
12322 outSeq = NULL;
12323 seq = NULL;
12324 contextNode = NULL;
12325 contextIdx = 0;
12326
12327
12328 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12329 (ctxt->error == XPATH_EXPRESSION_OK)) {
12330 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12331
12332 if (seq == NULL) {
12333 seq = xmlXPathNodeSetCreate(NULL);
12334 if (seq == NULL) {
12335 total = 0;
12336 goto error;
12337 }
12338 }
12339 /*
12340 * Traverse the axis and test the nodes.
12341 */
12342 pos = 0;
12343 cur = NULL;
12344 hasNsNodes = 0;
12345 do {
12346 cur = next(ctxt, cur);
12347 if (cur == NULL)
12348 break;
12349
12350 /*
12351 * QUESTION TODO: What does the "first" and "last" stuff do?
12352 */
12353 if ((first != NULL) && (*first != NULL)) {
12354 if (*first == cur)
12355 break;
12356 if (((total % 256) == 0) &&
12357 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12358 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12359 #else
12360 (xmlXPathCmpNodes(*first, cur) >= 0))
12361 #endif
12362 {
12363 break;
12364 }
12365 }
12366 if ((last != NULL) && (*last != NULL)) {
12367 if (*last == cur)
12368 break;
12369 if (((total % 256) == 0) &&
12370 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12371 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12372 #else
12373 (xmlXPathCmpNodes(cur, *last) >= 0))
12374 #endif
12375 {
12376 break;
12377 }
12378 }
12379
12380 total++;
12381
12382 #ifdef DEBUG_STEP
12383 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12384 #endif
12385
12386 switch (test) {
12387 case NODE_TEST_NONE:
12388 total = 0;
12389 STRANGE
12390 goto error;
12391 case NODE_TEST_TYPE:
12392 if (type == NODE_TYPE_NODE) {
12393 switch (cur->type) {
12394 case XML_DOCUMENT_NODE:
12395 case XML_HTML_DOCUMENT_NODE:
12396 #ifdef LIBXML_DOCB_ENABLED
12397 case XML_DOCB_DOCUMENT_NODE:
12398 #endif
12399 case XML_ELEMENT_NODE:
12400 case XML_ATTRIBUTE_NODE:
12401 case XML_PI_NODE:
12402 case XML_COMMENT_NODE:
12403 case XML_CDATA_SECTION_NODE:
12404 case XML_TEXT_NODE:
12405 XP_TEST_HIT
12406 break;
12407 case XML_NAMESPACE_DECL: {
12408 if (axis == AXIS_NAMESPACE) {
12409 XP_TEST_HIT_NS
12410 } else {
12411 hasNsNodes = 1;
12412 XP_TEST_HIT
12413 }
12414 break;
12415 }
12416 default:
12417 break;
12418 }
12419 } else if (cur->type == (xmlElementType) type) {
12420 if (cur->type == XML_NAMESPACE_DECL)
12421 XP_TEST_HIT_NS
12422 else
12423 XP_TEST_HIT
12424 } else if ((type == NODE_TYPE_TEXT) &&
12425 (cur->type == XML_CDATA_SECTION_NODE))
12426 {
12427 XP_TEST_HIT
12428 }
12429 break;
12430 case NODE_TEST_PI:
12431 if ((cur->type == XML_PI_NODE) &&
12432 ((name == NULL) || xmlStrEqual(name, cur->name)))
12433 {
12434 XP_TEST_HIT
12435 }
12436 break;
12437 case NODE_TEST_ALL:
12438 if (axis == AXIS_ATTRIBUTE) {
12439 if (cur->type == XML_ATTRIBUTE_NODE)
12440 {
12441 if (prefix == NULL)
12442 {
12443 XP_TEST_HIT
12444 } else if ((cur->ns != NULL) &&
12445 (xmlStrEqual(URI, cur->ns->href)))
12446 {
12447 XP_TEST_HIT
12448 }
12449 }
12450 } else if (axis == AXIS_NAMESPACE) {
12451 if (cur->type == XML_NAMESPACE_DECL)
12452 {
12453 XP_TEST_HIT_NS
12454 }
12455 } else {
12456 if (cur->type == XML_ELEMENT_NODE) {
12457 if (prefix == NULL)
12458 {
12459 XP_TEST_HIT
12460
12461 } else if ((cur->ns != NULL) &&
12462 (xmlStrEqual(URI, cur->ns->href)))
12463 {
12464 XP_TEST_HIT
12465 }
12466 }
12467 }
12468 break;
12469 case NODE_TEST_NS:{
12470 TODO;
12471 break;
12472 }
12473 case NODE_TEST_NAME:
12474 if (axis == AXIS_ATTRIBUTE) {
12475 if (cur->type != XML_ATTRIBUTE_NODE)
12476 break;
12477 } else if (axis == AXIS_NAMESPACE) {
12478 if (cur->type != XML_NAMESPACE_DECL)
12479 break;
12480 } else {
12481 if (cur->type != XML_ELEMENT_NODE)
12482 break;
12483 }
12484 switch (cur->type) {
12485 case XML_ELEMENT_NODE:
12486 if (xmlStrEqual(name, cur->name)) {
12487 if (prefix == NULL) {
12488 if (cur->ns == NULL)
12489 {
12490 XP_TEST_HIT
12491 }
12492 } else {
12493 if ((cur->ns != NULL) &&
12494 (xmlStrEqual(URI, cur->ns->href)))
12495 {
12496 XP_TEST_HIT
12497 }
12498 }
12499 }
12500 break;
12501 case XML_ATTRIBUTE_NODE:{
12502 xmlAttrPtr attr = (xmlAttrPtr) cur;
12503
12504 if (xmlStrEqual(name, attr->name)) {
12505 if (prefix == NULL) {
12506 if ((attr->ns == NULL) ||
12507 (attr->ns->prefix == NULL))
12508 {
12509 XP_TEST_HIT
12510 }
12511 } else {
12512 if ((attr->ns != NULL) &&
12513 (xmlStrEqual(URI,
12514 attr->ns->href)))
12515 {
12516 XP_TEST_HIT
12517 }
12518 }
12519 }
12520 break;
12521 }
12522 case XML_NAMESPACE_DECL:
12523 if (cur->type == XML_NAMESPACE_DECL) {
12524 xmlNsPtr ns = (xmlNsPtr) cur;
12525
12526 if ((ns->prefix != NULL) && (name != NULL)
12527 && (xmlStrEqual(ns->prefix, name)))
12528 {
12529 XP_TEST_HIT_NS
12530 }
12531 }
12532 break;
12533 default:
12534 break;
12535 }
12536 break;
12537 } /* switch(test) */
12538 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12539
12540 goto apply_predicates;
12541
12542 axis_range_end: /* ----------------------------------------------------- */
12543 /*
12544 * We have a "/foo[n]", and position() = n was reached.
12545 * Note that we can have as well "/foo/::parent::foo[1]", so
12546 * a duplicate-aware merge is still needed.
12547 * Merge with the result.
12548 */
12549 if (outSeq == NULL) {
12550 outSeq = seq;
12551 seq = NULL;
12552 } else
12553 outSeq = mergeAndClear(outSeq, seq, 0);
12554 /*
12555 * Break if only a true/false result was requested.
12556 */
12557 if (toBool)
12558 break;
12559 continue;
12560
12561 first_hit: /* ---------------------------------------------------------- */
12562 /*
12563 * Break if only a true/false result was requested and
12564 * no predicates existed and a node test succeeded.
12565 */
12566 if (outSeq == NULL) {
12567 outSeq = seq;
12568 seq = NULL;
12569 } else
12570 outSeq = mergeAndClear(outSeq, seq, 0);
12571 break;
12572
12573 #ifdef DEBUG_STEP
12574 if (seq != NULL)
12575 nbMatches += seq->nodeNr;
12576 #endif
12577
12578 apply_predicates: /* --------------------------------------------------- */
12579 if (ctxt->error != XPATH_EXPRESSION_OK)
12580 goto error;
12581
12582 /*
12583 * Apply predicates.
12584 */
12585 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12586 /*
12587 * E.g. when we have a "/foo[some expression][n]".
12588 */
12589 /*
12590 * QUESTION TODO: The old predicate evaluation took into
12591 * account location-sets.
12592 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12593 * Do we expect such a set here?
12594 * All what I learned now from the evaluation semantics
12595 * does not indicate that a location-set will be processed
12596 * here, so this looks OK.
12597 */
12598 /*
12599 * Iterate over all predicates, starting with the outermost
12600 * predicate.
12601 * TODO: Problem: we cannot execute the inner predicates first
12602 * since we cannot go back *up* the operator tree!
12603 * Options we have:
12604 * 1) Use of recursive functions (like is it currently done
12605 * via xmlXPathCompOpEval())
12606 * 2) Add a predicate evaluation information stack to the
12607 * context struct
12608 * 3) Change the way the operators are linked; we need a
12609 * "parent" field on xmlXPathStepOp
12610 *
12611 * For the moment, I'll try to solve this with a recursive
12612 * function: xmlXPathCompOpEvalPredicate().
12613 */
12614 size = seq->nodeNr;
12615 if (hasPredicateRange != 0)
12616 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12617 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12618 else
12619 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12620 predOp, seq, size, hasNsNodes);
12621
12622 if (ctxt->error != XPATH_EXPRESSION_OK) {
12623 total = 0;
12624 goto error;
12625 }
12626 /*
12627 * Add the filtered set of nodes to the result node set.
12628 */
12629 if (newSize == 0) {
12630 /*
12631 * The predicates filtered all nodes out.
12632 */
12633 xmlXPathNodeSetClear(seq, hasNsNodes);
12634 } else if (seq->nodeNr > 0) {
12635 /*
12636 * Add to result set.
12637 */
12638 if (outSeq == NULL) {
12639 if (size != newSize) {
12640 /*
12641 * We need to merge and clear here, since
12642 * the sequence will contained NULLed entries.
12643 */
12644 outSeq = mergeAndClear(NULL, seq, 1);
12645 } else {
12646 outSeq = seq;
12647 seq = NULL;
12648 }
12649 } else
12650 outSeq = mergeAndClear(outSeq, seq,
12651 (size != newSize) ? 1: 0);
12652 /*
12653 * Break if only a true/false result was requested.
12654 */
12655 if (toBool)
12656 break;
12657 }
12658 } else if (seq->nodeNr > 0) {
12659 /*
12660 * Add to result set.
12661 */
12662 if (outSeq == NULL) {
12663 outSeq = seq;
12664 seq = NULL;
12665 } else {
12666 outSeq = mergeAndClear(outSeq, seq, 0);
12667 }
12668 }
12669 }
12670
12671 error:
12672 if ((obj->boolval) && (obj->user != NULL)) {
12673 /*
12674 * QUESTION TODO: What does this do and why?
12675 * TODO: Do we have to do this also for the "error"
12676 * cleanup further down?
12677 */
12678 ctxt->value->boolval = 1;
12679 ctxt->value->user = obj->user;
12680 obj->user = NULL;
12681 obj->boolval = 0;
12682 }
12683 xmlXPathReleaseObject(xpctxt, obj);
12684
12685 /*
12686 * Ensure we return at least an emtpy set.
12687 */
12688 if (outSeq == NULL) {
12689 if ((seq != NULL) && (seq->nodeNr == 0))
12690 outSeq = seq;
12691 else
12692 outSeq = xmlXPathNodeSetCreate(NULL);
12693 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12694 }
12695 if ((seq != NULL) && (seq != outSeq)) {
12696 xmlXPathFreeNodeSet(seq);
12697 }
12698 /*
12699 * Hand over the result. Better to push the set also in
12700 * case of errors.
12701 */
12702 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12703 /*
12704 * Reset the context node.
12705 */
12706 xpctxt->node = oldContextNode;
12707 /*
12708 * When traversing the namespace axis in "toBool" mode, it's
12709 * possible that tmpNsList wasn't freed.
12710 */
12711 if (xpctxt->tmpNsList != NULL) {
12712 xmlFree(xpctxt->tmpNsList);
12713 xpctxt->tmpNsList = NULL;
12714 }
12715
12716 #ifdef DEBUG_STEP
12717 xmlGenericError(xmlGenericErrorContext,
12718 "\nExamined %d nodes, found %d nodes at that step\n",
12719 total, nbMatches);
12720 #endif
12721
12722 return(total);
12723 }
12724
12725 static int
12726 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12727 xmlXPathStepOpPtr op, xmlNodePtr * first);
12728
12729 /**
12730 * xmlXPathCompOpEvalFirst:
12731 * @ctxt: the XPath parser context with the compiled expression
12732 * @op: an XPath compiled operation
12733 * @first: the first elem found so far
12734 *
12735 * Evaluate the Precompiled XPath operation searching only the first
12736 * element in document order
12737 *
12738 * Returns the number of examined objects.
12739 */
12740 static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12741 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12742 xmlXPathStepOpPtr op, xmlNodePtr * first)
12743 {
12744 int total = 0, cur;
12745 xmlXPathCompExprPtr comp;
12746 xmlXPathObjectPtr arg1, arg2;
12747
12748 CHECK_ERROR0;
12749 comp = ctxt->comp;
12750 switch (op->op) {
12751 case XPATH_OP_END:
12752 return (0);
12753 case XPATH_OP_UNION:
12754 total =
12755 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12756 first);
12757 CHECK_ERROR0;
12758 if ((ctxt->value != NULL)
12759 && (ctxt->value->type == XPATH_NODESET)
12760 && (ctxt->value->nodesetval != NULL)
12761 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12762 /*
12763 * limit tree traversing to first node in the result
12764 */
12765 /*
12766 * OPTIMIZE TODO: This implicitely sorts
12767 * the result, even if not needed. E.g. if the argument
12768 * of the count() function, no sorting is needed.
12769 * OPTIMIZE TODO: How do we know if the node-list wasn't
12770 * aready sorted?
12771 */
12772 if (ctxt->value->nodesetval->nodeNr > 1)
12773 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12774 *first = ctxt->value->nodesetval->nodeTab[0];
12775 }
12776 cur =
12777 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12778 first);
12779 CHECK_ERROR0;
12780
12781 arg2 = valuePop(ctxt);
12782 arg1 = valuePop(ctxt);
12783 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12784 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12785 xmlXPathReleaseObject(ctxt->context, arg1);
12786 xmlXPathReleaseObject(ctxt->context, arg2);
12787 XP_ERROR0(XPATH_INVALID_TYPE);
12788 }
12789
12790 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12791 arg2->nodesetval);
12792 valuePush(ctxt, arg1);
12793 xmlXPathReleaseObject(ctxt->context, arg2);
12794 /* optimizer */
12795 if (total > cur)
12796 xmlXPathCompSwap(op);
12797 return (total + cur);
12798 case XPATH_OP_ROOT:
12799 xmlXPathRoot(ctxt);
12800 return (0);
12801 case XPATH_OP_NODE:
12802 if (op->ch1 != -1)
12803 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12804 CHECK_ERROR0;
12805 if (op->ch2 != -1)
12806 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12807 CHECK_ERROR0;
12808 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12809 ctxt->context->node));
12810 return (total);
12811 case XPATH_OP_COLLECT:{
12812 if (op->ch1 == -1)
12813 return (total);
12814
12815 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12816 CHECK_ERROR0;
12817
12818 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12819 return (total);
12820 }
12821 case XPATH_OP_VALUE:
12822 valuePush(ctxt,
12823 xmlXPathCacheObjectCopy(ctxt->context,
12824 (xmlXPathObjectPtr) op->value4));
12825 return (0);
12826 case XPATH_OP_SORT:
12827 if (op->ch1 != -1)
12828 total +=
12829 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12830 first);
12831 CHECK_ERROR0;
12832 if ((ctxt->value != NULL)
12833 && (ctxt->value->type == XPATH_NODESET)
12834 && (ctxt->value->nodesetval != NULL)
12835 && (ctxt->value->nodesetval->nodeNr > 1))
12836 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12837 return (total);
12838 #ifdef XP_OPTIMIZED_FILTER_FIRST
12839 case XPATH_OP_FILTER:
12840 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12841 return (total);
12842 #endif
12843 default:
12844 return (xmlXPathCompOpEval(ctxt, op));
12845 }
12846 }
12847
12848 /**
12849 * xmlXPathCompOpEvalLast:
12850 * @ctxt: the XPath parser context with the compiled expression
12851 * @op: an XPath compiled operation
12852 * @last: the last elem found so far
12853 *
12854 * Evaluate the Precompiled XPath operation searching only the last
12855 * element in document order
12856 *
12857 * Returns the number of nodes traversed
12858 */
12859 static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * last)12860 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12861 xmlNodePtr * last)
12862 {
12863 int total = 0, cur;
12864 xmlXPathCompExprPtr comp;
12865 xmlXPathObjectPtr arg1, arg2;
12866
12867 CHECK_ERROR0;
12868 comp = ctxt->comp;
12869 switch (op->op) {
12870 case XPATH_OP_END:
12871 return (0);
12872 case XPATH_OP_UNION:
12873 total =
12874 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12875 CHECK_ERROR0;
12876 if ((ctxt->value != NULL)
12877 && (ctxt->value->type == XPATH_NODESET)
12878 && (ctxt->value->nodesetval != NULL)
12879 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12880 /*
12881 * limit tree traversing to first node in the result
12882 */
12883 if (ctxt->value->nodesetval->nodeNr > 1)
12884 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12885 *last =
12886 ctxt->value->nodesetval->nodeTab[ctxt->value->
12887 nodesetval->nodeNr -
12888 1];
12889 }
12890 cur =
12891 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12892 CHECK_ERROR0;
12893 if ((ctxt->value != NULL)
12894 && (ctxt->value->type == XPATH_NODESET)
12895 && (ctxt->value->nodesetval != NULL)
12896 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12897 }
12898
12899 arg2 = valuePop(ctxt);
12900 arg1 = valuePop(ctxt);
12901 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12902 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12903 xmlXPathReleaseObject(ctxt->context, arg1);
12904 xmlXPathReleaseObject(ctxt->context, arg2);
12905 XP_ERROR0(XPATH_INVALID_TYPE);
12906 }
12907
12908 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12909 arg2->nodesetval);
12910 valuePush(ctxt, arg1);
12911 xmlXPathReleaseObject(ctxt->context, arg2);
12912 /* optimizer */
12913 if (total > cur)
12914 xmlXPathCompSwap(op);
12915 return (total + cur);
12916 case XPATH_OP_ROOT:
12917 xmlXPathRoot(ctxt);
12918 return (0);
12919 case XPATH_OP_NODE:
12920 if (op->ch1 != -1)
12921 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12922 CHECK_ERROR0;
12923 if (op->ch2 != -1)
12924 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12925 CHECK_ERROR0;
12926 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12927 ctxt->context->node));
12928 return (total);
12929 case XPATH_OP_COLLECT:{
12930 if (op->ch1 == -1)
12931 return (0);
12932
12933 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12934 CHECK_ERROR0;
12935
12936 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12937 return (total);
12938 }
12939 case XPATH_OP_VALUE:
12940 valuePush(ctxt,
12941 xmlXPathCacheObjectCopy(ctxt->context,
12942 (xmlXPathObjectPtr) op->value4));
12943 return (0);
12944 case XPATH_OP_SORT:
12945 if (op->ch1 != -1)
12946 total +=
12947 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12948 last);
12949 CHECK_ERROR0;
12950 if ((ctxt->value != NULL)
12951 && (ctxt->value->type == XPATH_NODESET)
12952 && (ctxt->value->nodesetval != NULL)
12953 && (ctxt->value->nodesetval->nodeNr > 1))
12954 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12955 return (total);
12956 default:
12957 return (xmlXPathCompOpEval(ctxt, op));
12958 }
12959 }
12960
12961 #ifdef XP_OPTIMIZED_FILTER_FIRST
12962 static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,xmlNodePtr * first)12963 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12964 xmlXPathStepOpPtr op, xmlNodePtr * first)
12965 {
12966 int total = 0;
12967 xmlXPathCompExprPtr comp;
12968 xmlXPathObjectPtr res;
12969 xmlXPathObjectPtr obj;
12970 xmlNodeSetPtr oldset;
12971 xmlNodePtr oldnode;
12972 xmlDocPtr oldDoc;
12973 int oldcs, oldpp;
12974 int i;
12975
12976 CHECK_ERROR0;
12977 comp = ctxt->comp;
12978 /*
12979 * Optimization for ()[last()] selection i.e. the last elem
12980 */
12981 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12982 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12983 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12984 int f = comp->steps[op->ch2].ch1;
12985
12986 if ((f != -1) &&
12987 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12988 (comp->steps[f].value5 == NULL) &&
12989 (comp->steps[f].value == 0) &&
12990 (comp->steps[f].value4 != NULL) &&
12991 (xmlStrEqual
12992 (comp->steps[f].value4, BAD_CAST "last"))) {
12993 xmlNodePtr last = NULL;
12994
12995 total +=
12996 xmlXPathCompOpEvalLast(ctxt,
12997 &comp->steps[op->ch1],
12998 &last);
12999 CHECK_ERROR0;
13000 /*
13001 * The nodeset should be in document order,
13002 * Keep only the last value
13003 */
13004 if ((ctxt->value != NULL) &&
13005 (ctxt->value->type == XPATH_NODESET) &&
13006 (ctxt->value->nodesetval != NULL) &&
13007 (ctxt->value->nodesetval->nodeTab != NULL) &&
13008 (ctxt->value->nodesetval->nodeNr > 1)) {
13009 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13010 *first = *(ctxt->value->nodesetval->nodeTab);
13011 }
13012 return (total);
13013 }
13014 }
13015
13016 if (op->ch1 != -1)
13017 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13018 CHECK_ERROR0;
13019 if (op->ch2 == -1)
13020 return (total);
13021 if (ctxt->value == NULL)
13022 return (total);
13023
13024 #ifdef LIBXML_XPTR_ENABLED
13025 /*
13026 * Hum are we filtering the result of an XPointer expression
13027 */
13028 if (ctxt->value->type == XPATH_LOCATIONSET) {
13029 xmlXPathObjectPtr tmp = NULL;
13030 xmlLocationSetPtr newlocset = NULL;
13031 xmlLocationSetPtr oldlocset;
13032
13033 /*
13034 * Extract the old locset, and then evaluate the result of the
13035 * expression for all the element in the locset. use it to grow
13036 * up a new locset.
13037 */
13038 CHECK_TYPE0(XPATH_LOCATIONSET);
13039
13040 if ((ctxt->value->user == NULL) ||
13041 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13042 return (total);
13043
13044 obj = valuePop(ctxt);
13045 oldlocset = obj->user;
13046 oldnode = ctxt->context->node;
13047 oldcs = ctxt->context->contextSize;
13048 oldpp = ctxt->context->proximityPosition;
13049
13050 newlocset = xmlXPtrLocationSetCreate(NULL);
13051
13052 for (i = 0; i < oldlocset->locNr; i++) {
13053 /*
13054 * Run the evaluation with a node list made of a
13055 * single item in the nodelocset.
13056 */
13057 ctxt->context->node = oldlocset->locTab[i]->user;
13058 ctxt->context->contextSize = oldlocset->locNr;
13059 ctxt->context->proximityPosition = i + 1;
13060 if (tmp == NULL) {
13061 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13062 ctxt->context->node);
13063 } else {
13064 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13065 ctxt->context->node) < 0) {
13066 ctxt->error = XPATH_MEMORY_ERROR;
13067 }
13068 }
13069 valuePush(ctxt, tmp);
13070 if (op->ch2 != -1)
13071 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13072 if (ctxt->error != XPATH_EXPRESSION_OK) {
13073 xmlXPtrFreeLocationSet(newlocset);
13074 goto xptr_error;
13075 }
13076 /*
13077 * The result of the evaluation need to be tested to
13078 * decided whether the filter succeeded or not
13079 */
13080 res = valuePop(ctxt);
13081 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13082 xmlXPtrLocationSetAdd(newlocset,
13083 xmlXPathCacheObjectCopy(ctxt->context,
13084 oldlocset->locTab[i]));
13085 }
13086 /*
13087 * Cleanup
13088 */
13089 if (res != NULL) {
13090 xmlXPathReleaseObject(ctxt->context, res);
13091 }
13092 if (ctxt->value == tmp) {
13093 valuePop(ctxt);
13094 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13095 /*
13096 * REVISIT TODO: Don't create a temporary nodeset
13097 * for everly iteration.
13098 */
13099 /* OLD: xmlXPathFreeObject(res); */
13100 } else
13101 tmp = NULL;
13102 /*
13103 * Only put the first node in the result, then leave.
13104 */
13105 if (newlocset->locNr > 0) {
13106 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13107 break;
13108 }
13109 }
13110 if (tmp != NULL) {
13111 xmlXPathReleaseObject(ctxt->context, tmp);
13112 }
13113 /*
13114 * The result is used as the new evaluation locset.
13115 */
13116 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13117 xptr_error:
13118 xmlXPathReleaseObject(ctxt->context, obj);
13119 ctxt->context->node = oldnode;
13120 ctxt->context->contextSize = oldcs;
13121 ctxt->context->proximityPosition = oldpp;
13122 return (total);
13123 }
13124 #endif /* LIBXML_XPTR_ENABLED */
13125
13126 /*
13127 * Extract the old set, and then evaluate the result of the
13128 * expression for all the element in the set. use it to grow
13129 * up a new set.
13130 */
13131 CHECK_TYPE0(XPATH_NODESET);
13132
13133 if ((ctxt->value->nodesetval != NULL) &&
13134 (ctxt->value->nodesetval->nodeNr != 0)) {
13135 xmlNodeSetPtr newset;
13136 xmlXPathObjectPtr tmp = NULL;
13137
13138 obj = valuePop(ctxt);
13139 oldset = obj->nodesetval;
13140 oldnode = ctxt->context->node;
13141 oldDoc = ctxt->context->doc;
13142 oldcs = ctxt->context->contextSize;
13143 oldpp = ctxt->context->proximityPosition;
13144
13145 /*
13146 * Initialize the new set.
13147 * Also set the xpath document in case things like
13148 * key() evaluation are attempted on the predicate
13149 */
13150 newset = xmlXPathNodeSetCreate(NULL);
13151 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13152
13153 for (i = 0; i < oldset->nodeNr; i++) {
13154 /*
13155 * Run the evaluation with a node list made of
13156 * a single item in the nodeset.
13157 */
13158 ctxt->context->node = oldset->nodeTab[i];
13159 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13160 (oldset->nodeTab[i]->doc != NULL))
13161 ctxt->context->doc = oldset->nodeTab[i]->doc;
13162 if (tmp == NULL) {
13163 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13164 ctxt->context->node);
13165 } else {
13166 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13167 ctxt->context->node) < 0) {
13168 ctxt->error = XPATH_MEMORY_ERROR;
13169 }
13170 }
13171 valuePush(ctxt, tmp);
13172 ctxt->context->contextSize = oldset->nodeNr;
13173 ctxt->context->proximityPosition = i + 1;
13174 if (op->ch2 != -1)
13175 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13176 if (ctxt->error != XPATH_EXPRESSION_OK) {
13177 xmlXPathFreeNodeSet(newset);
13178 goto error;
13179 }
13180 /*
13181 * The result of the evaluation needs to be tested to
13182 * decide whether the filter succeeded or not
13183 */
13184 res = valuePop(ctxt);
13185 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13186 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13187 ctxt->error = XPATH_MEMORY_ERROR;
13188 }
13189 /*
13190 * Cleanup
13191 */
13192 if (res != NULL) {
13193 xmlXPathReleaseObject(ctxt->context, res);
13194 }
13195 if (ctxt->value == tmp) {
13196 valuePop(ctxt);
13197 /*
13198 * Don't free the temporary nodeset
13199 * in order to avoid massive recreation inside this
13200 * loop.
13201 */
13202 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13203 } else
13204 tmp = NULL;
13205 /*
13206 * Only put the first node in the result, then leave.
13207 */
13208 if (newset->nodeNr > 0) {
13209 *first = *(newset->nodeTab);
13210 break;
13211 }
13212 }
13213 if (tmp != NULL) {
13214 xmlXPathReleaseObject(ctxt->context, tmp);
13215 }
13216 /*
13217 * The result is used as the new evaluation set.
13218 */
13219 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13220 error:
13221 xmlXPathReleaseObject(ctxt->context, obj);
13222 ctxt->context->node = oldnode;
13223 ctxt->context->doc = oldDoc;
13224 ctxt->context->contextSize = oldcs;
13225 ctxt->context->proximityPosition = oldpp;
13226 }
13227 return(total);
13228 }
13229 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13230
13231 /**
13232 * xmlXPathCompOpEval:
13233 * @ctxt: the XPath parser context with the compiled expression
13234 * @op: an XPath compiled operation
13235 *
13236 * Evaluate the Precompiled XPath operation
13237 * Returns the number of nodes traversed
13238 */
13239 static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op)13240 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13241 {
13242 int total = 0;
13243 int equal, ret;
13244 xmlXPathCompExprPtr comp;
13245 xmlXPathObjectPtr arg1, arg2;
13246
13247 CHECK_ERROR0;
13248 comp = ctxt->comp;
13249 switch (op->op) {
13250 case XPATH_OP_END:
13251 return (0);
13252 case XPATH_OP_AND:
13253 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13254 CHECK_ERROR0;
13255 xmlXPathBooleanFunction(ctxt, 1);
13256 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13257 return (total);
13258 arg2 = valuePop(ctxt);
13259 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13260 if (ctxt->error) {
13261 xmlXPathFreeObject(arg2);
13262 return(0);
13263 }
13264 xmlXPathBooleanFunction(ctxt, 1);
13265 if (ctxt->value != NULL)
13266 ctxt->value->boolval &= arg2->boolval;
13267 xmlXPathReleaseObject(ctxt->context, arg2);
13268 return (total);
13269 case XPATH_OP_OR:
13270 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13271 CHECK_ERROR0;
13272 xmlXPathBooleanFunction(ctxt, 1);
13273 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13274 return (total);
13275 arg2 = valuePop(ctxt);
13276 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13277 if (ctxt->error) {
13278 xmlXPathFreeObject(arg2);
13279 return(0);
13280 }
13281 xmlXPathBooleanFunction(ctxt, 1);
13282 if (ctxt->value != NULL)
13283 ctxt->value->boolval |= arg2->boolval;
13284 xmlXPathReleaseObject(ctxt->context, arg2);
13285 return (total);
13286 case XPATH_OP_EQUAL:
13287 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13288 CHECK_ERROR0;
13289 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13290 CHECK_ERROR0;
13291 if (op->value)
13292 equal = xmlXPathEqualValues(ctxt);
13293 else
13294 equal = xmlXPathNotEqualValues(ctxt);
13295 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13296 return (total);
13297 case XPATH_OP_CMP:
13298 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13299 CHECK_ERROR0;
13300 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13301 CHECK_ERROR0;
13302 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13303 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13304 return (total);
13305 case XPATH_OP_PLUS:
13306 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13307 CHECK_ERROR0;
13308 if (op->ch2 != -1) {
13309 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13310 }
13311 CHECK_ERROR0;
13312 if (op->value == 0)
13313 xmlXPathSubValues(ctxt);
13314 else if (op->value == 1)
13315 xmlXPathAddValues(ctxt);
13316 else if (op->value == 2)
13317 xmlXPathValueFlipSign(ctxt);
13318 else if (op->value == 3) {
13319 CAST_TO_NUMBER;
13320 CHECK_TYPE0(XPATH_NUMBER);
13321 }
13322 return (total);
13323 case XPATH_OP_MULT:
13324 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13325 CHECK_ERROR0;
13326 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13327 CHECK_ERROR0;
13328 if (op->value == 0)
13329 xmlXPathMultValues(ctxt);
13330 else if (op->value == 1)
13331 xmlXPathDivValues(ctxt);
13332 else if (op->value == 2)
13333 xmlXPathModValues(ctxt);
13334 return (total);
13335 case XPATH_OP_UNION:
13336 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13337 CHECK_ERROR0;
13338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13339 CHECK_ERROR0;
13340
13341 arg2 = valuePop(ctxt);
13342 arg1 = valuePop(ctxt);
13343 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13344 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13345 xmlXPathReleaseObject(ctxt->context, arg1);
13346 xmlXPathReleaseObject(ctxt->context, arg2);
13347 XP_ERROR0(XPATH_INVALID_TYPE);
13348 }
13349
13350 if ((arg1->nodesetval == NULL) ||
13351 ((arg2->nodesetval != NULL) &&
13352 (arg2->nodesetval->nodeNr != 0)))
13353 {
13354 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13355 arg2->nodesetval);
13356 }
13357
13358 valuePush(ctxt, arg1);
13359 xmlXPathReleaseObject(ctxt->context, arg2);
13360 return (total);
13361 case XPATH_OP_ROOT:
13362 xmlXPathRoot(ctxt);
13363 return (total);
13364 case XPATH_OP_NODE:
13365 if (op->ch1 != -1)
13366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367 CHECK_ERROR0;
13368 if (op->ch2 != -1)
13369 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13370 CHECK_ERROR0;
13371 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13372 ctxt->context->node));
13373 return (total);
13374 case XPATH_OP_COLLECT:{
13375 if (op->ch1 == -1)
13376 return (total);
13377
13378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13379 CHECK_ERROR0;
13380
13381 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13382 return (total);
13383 }
13384 case XPATH_OP_VALUE:
13385 valuePush(ctxt,
13386 xmlXPathCacheObjectCopy(ctxt->context,
13387 (xmlXPathObjectPtr) op->value4));
13388 return (total);
13389 case XPATH_OP_VARIABLE:{
13390 xmlXPathObjectPtr val;
13391
13392 if (op->ch1 != -1)
13393 total +=
13394 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13395 if (op->value5 == NULL) {
13396 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13397 if (val == NULL)
13398 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13399 valuePush(ctxt, val);
13400 } else {
13401 const xmlChar *URI;
13402
13403 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13404 if (URI == NULL) {
13405 xmlGenericError(xmlGenericErrorContext,
13406 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13407 (char *) op->value4, (char *)op->value5);
13408 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13409 return (total);
13410 }
13411 val = xmlXPathVariableLookupNS(ctxt->context,
13412 op->value4, URI);
13413 if (val == NULL)
13414 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13415 valuePush(ctxt, val);
13416 }
13417 return (total);
13418 }
13419 case XPATH_OP_FUNCTION:{
13420 xmlXPathFunction func;
13421 const xmlChar *oldFunc, *oldFuncURI;
13422 int i;
13423 int frame;
13424
13425 frame = xmlXPathSetFrame(ctxt);
13426 if (op->ch1 != -1) {
13427 total +=
13428 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13429 if (ctxt->error != XPATH_EXPRESSION_OK) {
13430 xmlXPathPopFrame(ctxt, frame);
13431 return (total);
13432 }
13433 }
13434 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13435 xmlGenericError(xmlGenericErrorContext,
13436 "xmlXPathCompOpEval: parameter error\n");
13437 ctxt->error = XPATH_INVALID_OPERAND;
13438 xmlXPathPopFrame(ctxt, frame);
13439 return (total);
13440 }
13441 for (i = 0; i < op->value; i++) {
13442 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13443 xmlGenericError(xmlGenericErrorContext,
13444 "xmlXPathCompOpEval: parameter error\n");
13445 ctxt->error = XPATH_INVALID_OPERAND;
13446 xmlXPathPopFrame(ctxt, frame);
13447 return (total);
13448 }
13449 }
13450 if (op->cache != NULL)
13451 func = op->cache;
13452 else {
13453 const xmlChar *URI = NULL;
13454
13455 if (op->value5 == NULL)
13456 func =
13457 xmlXPathFunctionLookup(ctxt->context,
13458 op->value4);
13459 else {
13460 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13461 if (URI == NULL) {
13462 xmlGenericError(xmlGenericErrorContext,
13463 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13464 (char *)op->value4, (char *)op->value5);
13465 xmlXPathPopFrame(ctxt, frame);
13466 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13467 return (total);
13468 }
13469 func = xmlXPathFunctionLookupNS(ctxt->context,
13470 op->value4, URI);
13471 }
13472 if (func == NULL) {
13473 xmlGenericError(xmlGenericErrorContext,
13474 "xmlXPathCompOpEval: function %s not found\n",
13475 (char *)op->value4);
13476 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13477 }
13478 op->cache = func;
13479 op->cacheURI = (void *) URI;
13480 }
13481 oldFunc = ctxt->context->function;
13482 oldFuncURI = ctxt->context->functionURI;
13483 ctxt->context->function = op->value4;
13484 ctxt->context->functionURI = op->cacheURI;
13485 func(ctxt, op->value);
13486 ctxt->context->function = oldFunc;
13487 ctxt->context->functionURI = oldFuncURI;
13488 xmlXPathPopFrame(ctxt, frame);
13489 return (total);
13490 }
13491 case XPATH_OP_ARG:
13492 if (op->ch1 != -1) {
13493 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13494 CHECK_ERROR0;
13495 }
13496 if (op->ch2 != -1) {
13497 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13498 CHECK_ERROR0;
13499 }
13500 return (total);
13501 case XPATH_OP_PREDICATE:
13502 case XPATH_OP_FILTER:{
13503 xmlXPathObjectPtr res;
13504 xmlXPathObjectPtr obj, tmp;
13505 xmlNodeSetPtr newset = NULL;
13506 xmlNodeSetPtr oldset;
13507 xmlNodePtr oldnode;
13508 xmlDocPtr oldDoc;
13509 int oldcs, oldpp;
13510 int i;
13511
13512 /*
13513 * Optimization for ()[1] selection i.e. the first elem
13514 */
13515 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13516 #ifdef XP_OPTIMIZED_FILTER_FIRST
13517 /*
13518 * FILTER TODO: Can we assume that the inner processing
13519 * will result in an ordered list if we have an
13520 * XPATH_OP_FILTER?
13521 * What about an additional field or flag on
13522 * xmlXPathObject like @sorted ? This way we wouln'd need
13523 * to assume anything, so it would be more robust and
13524 * easier to optimize.
13525 */
13526 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13527 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13528 #else
13529 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13530 #endif
13531 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13532 xmlXPathObjectPtr val;
13533
13534 val = comp->steps[op->ch2].value4;
13535 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13536 (val->floatval == 1.0)) {
13537 xmlNodePtr first = NULL;
13538
13539 total +=
13540 xmlXPathCompOpEvalFirst(ctxt,
13541 &comp->steps[op->ch1],
13542 &first);
13543 CHECK_ERROR0;
13544 /*
13545 * The nodeset should be in document order,
13546 * Keep only the first value
13547 */
13548 if ((ctxt->value != NULL) &&
13549 (ctxt->value->type == XPATH_NODESET) &&
13550 (ctxt->value->nodesetval != NULL) &&
13551 (ctxt->value->nodesetval->nodeNr > 1))
13552 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13553 1, 1);
13554 return (total);
13555 }
13556 }
13557 /*
13558 * Optimization for ()[last()] selection i.e. the last elem
13559 */
13560 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13561 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13562 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13563 int f = comp->steps[op->ch2].ch1;
13564
13565 if ((f != -1) &&
13566 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13567 (comp->steps[f].value5 == NULL) &&
13568 (comp->steps[f].value == 0) &&
13569 (comp->steps[f].value4 != NULL) &&
13570 (xmlStrEqual
13571 (comp->steps[f].value4, BAD_CAST "last"))) {
13572 xmlNodePtr last = NULL;
13573
13574 total +=
13575 xmlXPathCompOpEvalLast(ctxt,
13576 &comp->steps[op->ch1],
13577 &last);
13578 CHECK_ERROR0;
13579 /*
13580 * The nodeset should be in document order,
13581 * Keep only the last value
13582 */
13583 if ((ctxt->value != NULL) &&
13584 (ctxt->value->type == XPATH_NODESET) &&
13585 (ctxt->value->nodesetval != NULL) &&
13586 (ctxt->value->nodesetval->nodeTab != NULL) &&
13587 (ctxt->value->nodesetval->nodeNr > 1))
13588 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13589 return (total);
13590 }
13591 }
13592 /*
13593 * Process inner predicates first.
13594 * Example "index[parent::book][1]":
13595 * ...
13596 * PREDICATE <-- we are here "[1]"
13597 * PREDICATE <-- process "[parent::book]" first
13598 * SORT
13599 * COLLECT 'parent' 'name' 'node' book
13600 * NODE
13601 * ELEM Object is a number : 1
13602 */
13603 if (op->ch1 != -1)
13604 total +=
13605 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13606 CHECK_ERROR0;
13607 if (op->ch2 == -1)
13608 return (total);
13609 if (ctxt->value == NULL)
13610 return (total);
13611
13612 #ifdef LIBXML_XPTR_ENABLED
13613 /*
13614 * Hum are we filtering the result of an XPointer expression
13615 */
13616 if (ctxt->value->type == XPATH_LOCATIONSET) {
13617 xmlLocationSetPtr newlocset = NULL;
13618 xmlLocationSetPtr oldlocset;
13619
13620 /*
13621 * Extract the old locset, and then evaluate the result of the
13622 * expression for all the element in the locset. use it to grow
13623 * up a new locset.
13624 */
13625 CHECK_TYPE0(XPATH_LOCATIONSET);
13626
13627 if ((ctxt->value->user == NULL) ||
13628 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13629 return (total);
13630
13631 obj = valuePop(ctxt);
13632 oldlocset = obj->user;
13633 oldnode = ctxt->context->node;
13634 oldcs = ctxt->context->contextSize;
13635 oldpp = ctxt->context->proximityPosition;
13636
13637 newlocset = xmlXPtrLocationSetCreate(NULL);
13638
13639 for (i = 0; i < oldlocset->locNr; i++) {
13640 /*
13641 * Run the evaluation with a node list made of a
13642 * single item in the nodelocset.
13643 */
13644 ctxt->context->node = oldlocset->locTab[i]->user;
13645 ctxt->context->contextSize = oldlocset->locNr;
13646 ctxt->context->proximityPosition = i + 1;
13647 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13648 ctxt->context->node);
13649 valuePush(ctxt, tmp);
13650
13651 if (op->ch2 != -1)
13652 total +=
13653 xmlXPathCompOpEval(ctxt,
13654 &comp->steps[op->ch2]);
13655 if (ctxt->error != XPATH_EXPRESSION_OK) {
13656 xmlXPtrFreeLocationSet(newlocset);
13657 goto filter_xptr_error;
13658 }
13659
13660 /*
13661 * The result of the evaluation need to be tested to
13662 * decided whether the filter succeeded or not
13663 */
13664 res = valuePop(ctxt);
13665 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13666 xmlXPtrLocationSetAdd(newlocset,
13667 xmlXPathObjectCopy
13668 (oldlocset->locTab[i]));
13669 }
13670
13671 /*
13672 * Cleanup
13673 */
13674 if (res != NULL) {
13675 xmlXPathReleaseObject(ctxt->context, res);
13676 }
13677 if (ctxt->value == tmp) {
13678 res = valuePop(ctxt);
13679 xmlXPathReleaseObject(ctxt->context, res);
13680 }
13681 }
13682
13683 /*
13684 * The result is used as the new evaluation locset.
13685 */
13686 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13687 filter_xptr_error:
13688 xmlXPathReleaseObject(ctxt->context, obj);
13689 ctxt->context->node = oldnode;
13690 ctxt->context->contextSize = oldcs;
13691 ctxt->context->proximityPosition = oldpp;
13692 return (total);
13693 }
13694 #endif /* LIBXML_XPTR_ENABLED */
13695
13696 /*
13697 * Extract the old set, and then evaluate the result of the
13698 * expression for all the element in the set. use it to grow
13699 * up a new set.
13700 */
13701 CHECK_TYPE0(XPATH_NODESET);
13702
13703 if ((ctxt->value->nodesetval != NULL) &&
13704 (ctxt->value->nodesetval->nodeNr != 0)) {
13705 obj = valuePop(ctxt);
13706 oldset = obj->nodesetval;
13707 oldnode = ctxt->context->node;
13708 oldDoc = ctxt->context->doc;
13709 oldcs = ctxt->context->contextSize;
13710 oldpp = ctxt->context->proximityPosition;
13711 tmp = NULL;
13712 /*
13713 * Initialize the new set.
13714 * Also set the xpath document in case things like
13715 * key() evaluation are attempted on the predicate
13716 */
13717 newset = xmlXPathNodeSetCreate(NULL);
13718 /*
13719 * SPEC XPath 1.0:
13720 * "For each node in the node-set to be filtered, the
13721 * PredicateExpr is evaluated with that node as the
13722 * context node, with the number of nodes in the
13723 * node-set as the context size, and with the proximity
13724 * position of the node in the node-set with respect to
13725 * the axis as the context position;"
13726 * @oldset is the node-set" to be filtered.
13727 *
13728 * SPEC XPath 1.0:
13729 * "only predicates change the context position and
13730 * context size (see [2.4 Predicates])."
13731 * Example:
13732 * node-set context pos
13733 * nA 1
13734 * nB 2
13735 * nC 3
13736 * After applying predicate [position() > 1] :
13737 * node-set context pos
13738 * nB 1
13739 * nC 2
13740 *
13741 * removed the first node in the node-set, then
13742 * the context position of the
13743 */
13744 for (i = 0; i < oldset->nodeNr; i++) {
13745 /*
13746 * Run the evaluation with a node list made of
13747 * a single item in the nodeset.
13748 */
13749 ctxt->context->node = oldset->nodeTab[i];
13750 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13751 (oldset->nodeTab[i]->doc != NULL))
13752 ctxt->context->doc = oldset->nodeTab[i]->doc;
13753 if (tmp == NULL) {
13754 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13755 ctxt->context->node);
13756 } else {
13757 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13758 ctxt->context->node) < 0) {
13759 ctxt->error = XPATH_MEMORY_ERROR;
13760 }
13761 }
13762 valuePush(ctxt, tmp);
13763 ctxt->context->contextSize = oldset->nodeNr;
13764 ctxt->context->proximityPosition = i + 1;
13765 /*
13766 * Evaluate the predicate against the context node.
13767 * Can/should we optimize position() predicates
13768 * here (e.g. "[1]")?
13769 */
13770 if (op->ch2 != -1)
13771 total +=
13772 xmlXPathCompOpEval(ctxt,
13773 &comp->steps[op->ch2]);
13774 if (ctxt->error != XPATH_EXPRESSION_OK) {
13775 xmlXPathFreeNodeSet(newset);
13776 goto filter_error;
13777 }
13778
13779 /*
13780 * The result of the evaluation needs to be tested to
13781 * decide whether the filter succeeded or not
13782 */
13783 /*
13784 * OPTIMIZE TODO: Can we use
13785 * xmlXPathNodeSetAdd*Unique()* instead?
13786 */
13787 res = valuePop(ctxt);
13788 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13789 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13790 < 0)
13791 ctxt->error = XPATH_MEMORY_ERROR;
13792 }
13793
13794 /*
13795 * Cleanup
13796 */
13797 if (res != NULL) {
13798 xmlXPathReleaseObject(ctxt->context, res);
13799 }
13800 if (ctxt->value == tmp) {
13801 valuePop(ctxt);
13802 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13803 /*
13804 * Don't free the temporary nodeset
13805 * in order to avoid massive recreation inside this
13806 * loop.
13807 */
13808 } else
13809 tmp = NULL;
13810 }
13811 if (tmp != NULL)
13812 xmlXPathReleaseObject(ctxt->context, tmp);
13813 /*
13814 * The result is used as the new evaluation set.
13815 */
13816 valuePush(ctxt,
13817 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13818 filter_error:
13819 xmlXPathReleaseObject(ctxt->context, obj);
13820 ctxt->context->node = oldnode;
13821 ctxt->context->doc = oldDoc;
13822 ctxt->context->contextSize = oldcs;
13823 ctxt->context->proximityPosition = oldpp;
13824 }
13825 return (total);
13826 }
13827 case XPATH_OP_SORT:
13828 if (op->ch1 != -1)
13829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13830 CHECK_ERROR0;
13831 if ((ctxt->value != NULL) &&
13832 (ctxt->value->type == XPATH_NODESET) &&
13833 (ctxt->value->nodesetval != NULL) &&
13834 (ctxt->value->nodesetval->nodeNr > 1))
13835 {
13836 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13837 }
13838 return (total);
13839 #ifdef LIBXML_XPTR_ENABLED
13840 case XPATH_OP_RANGETO:{
13841 xmlXPathObjectPtr range;
13842 xmlXPathObjectPtr res, obj;
13843 xmlXPathObjectPtr tmp;
13844 xmlLocationSetPtr newlocset = NULL;
13845 xmlLocationSetPtr oldlocset;
13846 xmlNodeSetPtr oldset;
13847 xmlNodePtr oldnode = ctxt->context->node;
13848 int oldcs = ctxt->context->contextSize;
13849 int oldpp = ctxt->context->proximityPosition;
13850 int i, j;
13851
13852 if (op->ch1 != -1) {
13853 total +=
13854 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13855 CHECK_ERROR0;
13856 }
13857 if (ctxt->value == NULL) {
13858 XP_ERROR0(XPATH_INVALID_OPERAND);
13859 }
13860 if (op->ch2 == -1)
13861 return (total);
13862
13863 if (ctxt->value->type == XPATH_LOCATIONSET) {
13864 /*
13865 * Extract the old locset, and then evaluate the result of the
13866 * expression for all the element in the locset. use it to grow
13867 * up a new locset.
13868 */
13869 CHECK_TYPE0(XPATH_LOCATIONSET);
13870
13871 if ((ctxt->value->user == NULL) ||
13872 (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13873 return (total);
13874
13875 obj = valuePop(ctxt);
13876 oldlocset = obj->user;
13877
13878 newlocset = xmlXPtrLocationSetCreate(NULL);
13879
13880 for (i = 0; i < oldlocset->locNr; i++) {
13881 /*
13882 * Run the evaluation with a node list made of a
13883 * single item in the nodelocset.
13884 */
13885 ctxt->context->node = oldlocset->locTab[i]->user;
13886 ctxt->context->contextSize = oldlocset->locNr;
13887 ctxt->context->proximityPosition = i + 1;
13888 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13889 ctxt->context->node);
13890 valuePush(ctxt, tmp);
13891
13892 if (op->ch2 != -1)
13893 total +=
13894 xmlXPathCompOpEval(ctxt,
13895 &comp->steps[op->ch2]);
13896 if (ctxt->error != XPATH_EXPRESSION_OK) {
13897 xmlXPtrFreeLocationSet(newlocset);
13898 goto rangeto_error;
13899 }
13900
13901 res = valuePop(ctxt);
13902 if (res->type == XPATH_LOCATIONSET) {
13903 xmlLocationSetPtr rloc =
13904 (xmlLocationSetPtr)res->user;
13905 for (j=0; j<rloc->locNr; j++) {
13906 range = xmlXPtrNewRange(
13907 oldlocset->locTab[i]->user,
13908 oldlocset->locTab[i]->index,
13909 rloc->locTab[j]->user2,
13910 rloc->locTab[j]->index2);
13911 if (range != NULL) {
13912 xmlXPtrLocationSetAdd(newlocset, range);
13913 }
13914 }
13915 } else {
13916 range = xmlXPtrNewRangeNodeObject(
13917 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13918 if (range != NULL) {
13919 xmlXPtrLocationSetAdd(newlocset,range);
13920 }
13921 }
13922
13923 /*
13924 * Cleanup
13925 */
13926 if (res != NULL) {
13927 xmlXPathReleaseObject(ctxt->context, res);
13928 }
13929 if (ctxt->value == tmp) {
13930 res = valuePop(ctxt);
13931 xmlXPathReleaseObject(ctxt->context, res);
13932 }
13933 }
13934 } else { /* Not a location set */
13935 CHECK_TYPE0(XPATH_NODESET);
13936 obj = valuePop(ctxt);
13937 oldset = obj->nodesetval;
13938
13939 newlocset = xmlXPtrLocationSetCreate(NULL);
13940
13941 if (oldset != NULL) {
13942 for (i = 0; i < oldset->nodeNr; i++) {
13943 /*
13944 * Run the evaluation with a node list made of a single item
13945 * in the nodeset.
13946 */
13947 ctxt->context->node = oldset->nodeTab[i];
13948 /*
13949 * OPTIMIZE TODO: Avoid recreation for every iteration.
13950 */
13951 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13952 ctxt->context->node);
13953 valuePush(ctxt, tmp);
13954
13955 if (op->ch2 != -1)
13956 total +=
13957 xmlXPathCompOpEval(ctxt,
13958 &comp->steps[op->ch2]);
13959 if (ctxt->error != XPATH_EXPRESSION_OK) {
13960 xmlXPtrFreeLocationSet(newlocset);
13961 goto rangeto_error;
13962 }
13963
13964 res = valuePop(ctxt);
13965 range =
13966 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13967 res);
13968 if (range != NULL) {
13969 xmlXPtrLocationSetAdd(newlocset, range);
13970 }
13971
13972 /*
13973 * Cleanup
13974 */
13975 if (res != NULL) {
13976 xmlXPathReleaseObject(ctxt->context, res);
13977 }
13978 if (ctxt->value == tmp) {
13979 res = valuePop(ctxt);
13980 xmlXPathReleaseObject(ctxt->context, res);
13981 }
13982 }
13983 }
13984 }
13985
13986 /*
13987 * The result is used as the new evaluation set.
13988 */
13989 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13990 rangeto_error:
13991 xmlXPathReleaseObject(ctxt->context, obj);
13992 ctxt->context->node = oldnode;
13993 ctxt->context->contextSize = oldcs;
13994 ctxt->context->proximityPosition = oldpp;
13995 return (total);
13996 }
13997 #endif /* LIBXML_XPTR_ENABLED */
13998 }
13999 xmlGenericError(xmlGenericErrorContext,
14000 "XPath: unknown precompiled operation %d\n", op->op);
14001 ctxt->error = XPATH_INVALID_OPERAND;
14002 return (total);
14003 }
14004
14005 /**
14006 * xmlXPathCompOpEvalToBoolean:
14007 * @ctxt: the XPath parser context
14008 *
14009 * Evaluates if the expression evaluates to true.
14010 *
14011 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14012 */
14013 static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,xmlXPathStepOpPtr op,int isPredicate)14014 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14015 xmlXPathStepOpPtr op,
14016 int isPredicate)
14017 {
14018 xmlXPathObjectPtr resObj = NULL;
14019
14020 start:
14021 /* comp = ctxt->comp; */
14022 switch (op->op) {
14023 case XPATH_OP_END:
14024 return (0);
14025 case XPATH_OP_VALUE:
14026 resObj = (xmlXPathObjectPtr) op->value4;
14027 if (isPredicate)
14028 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14029 return(xmlXPathCastToBoolean(resObj));
14030 case XPATH_OP_SORT:
14031 /*
14032 * We don't need sorting for boolean results. Skip this one.
14033 */
14034 if (op->ch1 != -1) {
14035 op = &ctxt->comp->steps[op->ch1];
14036 goto start;
14037 }
14038 return(0);
14039 case XPATH_OP_COLLECT:
14040 if (op->ch1 == -1)
14041 return(0);
14042
14043 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14044 if (ctxt->error != XPATH_EXPRESSION_OK)
14045 return(-1);
14046
14047 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14048 if (ctxt->error != XPATH_EXPRESSION_OK)
14049 return(-1);
14050
14051 resObj = valuePop(ctxt);
14052 if (resObj == NULL)
14053 return(-1);
14054 break;
14055 default:
14056 /*
14057 * Fallback to call xmlXPathCompOpEval().
14058 */
14059 xmlXPathCompOpEval(ctxt, op);
14060 if (ctxt->error != XPATH_EXPRESSION_OK)
14061 return(-1);
14062
14063 resObj = valuePop(ctxt);
14064 if (resObj == NULL)
14065 return(-1);
14066 break;
14067 }
14068
14069 if (resObj) {
14070 int res;
14071
14072 if (resObj->type == XPATH_BOOLEAN) {
14073 res = resObj->boolval;
14074 } else if (isPredicate) {
14075 /*
14076 * For predicates a result of type "number" is handled
14077 * differently:
14078 * SPEC XPath 1.0:
14079 * "If the result is a number, the result will be converted
14080 * to true if the number is equal to the context position
14081 * and will be converted to false otherwise;"
14082 */
14083 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14084 } else {
14085 res = xmlXPathCastToBoolean(resObj);
14086 }
14087 xmlXPathReleaseObject(ctxt->context, resObj);
14088 return(res);
14089 }
14090
14091 return(0);
14092 }
14093
14094 #ifdef XPATH_STREAMING
14095 /**
14096 * xmlXPathRunStreamEval:
14097 * @ctxt: the XPath parser context with the compiled expression
14098 *
14099 * Evaluate the Precompiled Streamable XPath expression in the given context.
14100 */
14101 static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt,xmlPatternPtr comp,xmlXPathObjectPtr * resultSeq,int toBool)14102 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14103 xmlXPathObjectPtr *resultSeq, int toBool)
14104 {
14105 int max_depth, min_depth;
14106 int from_root;
14107 int ret, depth;
14108 int eval_all_nodes;
14109 xmlNodePtr cur = NULL, limit = NULL;
14110 xmlStreamCtxtPtr patstream = NULL;
14111
14112 int nb_nodes = 0;
14113
14114 if ((ctxt == NULL) || (comp == NULL))
14115 return(-1);
14116 max_depth = xmlPatternMaxDepth(comp);
14117 if (max_depth == -1)
14118 return(-1);
14119 if (max_depth == -2)
14120 max_depth = 10000;
14121 min_depth = xmlPatternMinDepth(comp);
14122 if (min_depth == -1)
14123 return(-1);
14124 from_root = xmlPatternFromRoot(comp);
14125 if (from_root < 0)
14126 return(-1);
14127 #if 0
14128 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14129 #endif
14130
14131 if (! toBool) {
14132 if (resultSeq == NULL)
14133 return(-1);
14134 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14135 if (*resultSeq == NULL)
14136 return(-1);
14137 }
14138
14139 /*
14140 * handle the special cases of "/" amd "." being matched
14141 */
14142 if (min_depth == 0) {
14143 if (from_root) {
14144 /* Select "/" */
14145 if (toBool)
14146 return(1);
14147 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14148 (xmlNodePtr) ctxt->doc);
14149 } else {
14150 /* Select "self::node()" */
14151 if (toBool)
14152 return(1);
14153 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14154 }
14155 }
14156 if (max_depth == 0) {
14157 return(0);
14158 }
14159
14160 if (from_root) {
14161 cur = (xmlNodePtr)ctxt->doc;
14162 } else if (ctxt->node != NULL) {
14163 switch (ctxt->node->type) {
14164 case XML_ELEMENT_NODE:
14165 case XML_DOCUMENT_NODE:
14166 case XML_DOCUMENT_FRAG_NODE:
14167 case XML_HTML_DOCUMENT_NODE:
14168 #ifdef LIBXML_DOCB_ENABLED
14169 case XML_DOCB_DOCUMENT_NODE:
14170 #endif
14171 cur = ctxt->node;
14172 break;
14173 case XML_ATTRIBUTE_NODE:
14174 case XML_TEXT_NODE:
14175 case XML_CDATA_SECTION_NODE:
14176 case XML_ENTITY_REF_NODE:
14177 case XML_ENTITY_NODE:
14178 case XML_PI_NODE:
14179 case XML_COMMENT_NODE:
14180 case XML_NOTATION_NODE:
14181 case XML_DTD_NODE:
14182 case XML_DOCUMENT_TYPE_NODE:
14183 case XML_ELEMENT_DECL:
14184 case XML_ATTRIBUTE_DECL:
14185 case XML_ENTITY_DECL:
14186 case XML_NAMESPACE_DECL:
14187 case XML_XINCLUDE_START:
14188 case XML_XINCLUDE_END:
14189 break;
14190 }
14191 limit = cur;
14192 }
14193 if (cur == NULL) {
14194 return(0);
14195 }
14196
14197 patstream = xmlPatternGetStreamCtxt(comp);
14198 if (patstream == NULL) {
14199 /*
14200 * QUESTION TODO: Is this an error?
14201 */
14202 return(0);
14203 }
14204
14205 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14206
14207 if (from_root) {
14208 ret = xmlStreamPush(patstream, NULL, NULL);
14209 if (ret < 0) {
14210 } else if (ret == 1) {
14211 if (toBool)
14212 goto return_1;
14213 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14214 }
14215 }
14216 depth = 0;
14217 goto scan_children;
14218 next_node:
14219 do {
14220 nb_nodes++;
14221
14222 switch (cur->type) {
14223 case XML_ELEMENT_NODE:
14224 case XML_TEXT_NODE:
14225 case XML_CDATA_SECTION_NODE:
14226 case XML_COMMENT_NODE:
14227 case XML_PI_NODE:
14228 if (cur->type == XML_ELEMENT_NODE) {
14229 ret = xmlStreamPush(patstream, cur->name,
14230 (cur->ns ? cur->ns->href : NULL));
14231 } else if (eval_all_nodes)
14232 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14233 else
14234 break;
14235
14236 if (ret < 0) {
14237 /* NOP. */
14238 } else if (ret == 1) {
14239 if (toBool)
14240 goto return_1;
14241 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14242 < 0) {
14243 ctxt->lastError.domain = XML_FROM_XPATH;
14244 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14245 }
14246 }
14247 if ((cur->children == NULL) || (depth >= max_depth)) {
14248 ret = xmlStreamPop(patstream);
14249 while (cur->next != NULL) {
14250 cur = cur->next;
14251 if ((cur->type != XML_ENTITY_DECL) &&
14252 (cur->type != XML_DTD_NODE))
14253 goto next_node;
14254 }
14255 }
14256 default:
14257 break;
14258 }
14259
14260 scan_children:
14261 if (cur->type == XML_NAMESPACE_DECL) break;
14262 if ((cur->children != NULL) && (depth < max_depth)) {
14263 /*
14264 * Do not descend on entities declarations
14265 */
14266 if (cur->children->type != XML_ENTITY_DECL) {
14267 cur = cur->children;
14268 depth++;
14269 /*
14270 * Skip DTDs
14271 */
14272 if (cur->type != XML_DTD_NODE)
14273 continue;
14274 }
14275 }
14276
14277 if (cur == limit)
14278 break;
14279
14280 while (cur->next != NULL) {
14281 cur = cur->next;
14282 if ((cur->type != XML_ENTITY_DECL) &&
14283 (cur->type != XML_DTD_NODE))
14284 goto next_node;
14285 }
14286
14287 do {
14288 cur = cur->parent;
14289 depth--;
14290 if ((cur == NULL) || (cur == limit))
14291 goto done;
14292 if (cur->type == XML_ELEMENT_NODE) {
14293 ret = xmlStreamPop(patstream);
14294 } else if ((eval_all_nodes) &&
14295 ((cur->type == XML_TEXT_NODE) ||
14296 (cur->type == XML_CDATA_SECTION_NODE) ||
14297 (cur->type == XML_COMMENT_NODE) ||
14298 (cur->type == XML_PI_NODE)))
14299 {
14300 ret = xmlStreamPop(patstream);
14301 }
14302 if (cur->next != NULL) {
14303 cur = cur->next;
14304 break;
14305 }
14306 } while (cur != NULL);
14307
14308 } while ((cur != NULL) && (depth >= 0));
14309
14310 done:
14311
14312 #if 0
14313 printf("stream eval: checked %d nodes selected %d\n",
14314 nb_nodes, retObj->nodesetval->nodeNr);
14315 #endif
14316
14317 if (patstream)
14318 xmlFreeStreamCtxt(patstream);
14319 return(0);
14320
14321 return_1:
14322 if (patstream)
14323 xmlFreeStreamCtxt(patstream);
14324 return(1);
14325 }
14326 #endif /* XPATH_STREAMING */
14327
14328 /**
14329 * xmlXPathRunEval:
14330 * @ctxt: the XPath parser context with the compiled expression
14331 * @toBool: evaluate to a boolean result
14332 *
14333 * Evaluate the Precompiled XPath expression in the given context.
14334 */
14335 static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt,int toBool)14336 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14337 {
14338 xmlXPathCompExprPtr comp;
14339
14340 if ((ctxt == NULL) || (ctxt->comp == NULL))
14341 return(-1);
14342
14343 if (ctxt->valueTab == NULL) {
14344 /* Allocate the value stack */
14345 ctxt->valueTab = (xmlXPathObjectPtr *)
14346 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14347 if (ctxt->valueTab == NULL) {
14348 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14349 xmlFree(ctxt);
14350 }
14351 ctxt->valueNr = 0;
14352 ctxt->valueMax = 10;
14353 ctxt->value = NULL;
14354 ctxt->valueFrame = 0;
14355 }
14356 #ifdef XPATH_STREAMING
14357 if (ctxt->comp->stream) {
14358 int res;
14359
14360 if (toBool) {
14361 /*
14362 * Evaluation to boolean result.
14363 */
14364 res = xmlXPathRunStreamEval(ctxt->context,
14365 ctxt->comp->stream, NULL, 1);
14366 if (res != -1)
14367 return(res);
14368 } else {
14369 xmlXPathObjectPtr resObj = NULL;
14370
14371 /*
14372 * Evaluation to a sequence.
14373 */
14374 res = xmlXPathRunStreamEval(ctxt->context,
14375 ctxt->comp->stream, &resObj, 0);
14376
14377 if ((res != -1) && (resObj != NULL)) {
14378 valuePush(ctxt, resObj);
14379 return(0);
14380 }
14381 if (resObj != NULL)
14382 xmlXPathReleaseObject(ctxt->context, resObj);
14383 }
14384 /*
14385 * QUESTION TODO: This falls back to normal XPath evaluation
14386 * if res == -1. Is this intended?
14387 */
14388 }
14389 #endif
14390 comp = ctxt->comp;
14391 if (comp->last < 0) {
14392 xmlGenericError(xmlGenericErrorContext,
14393 "xmlXPathRunEval: last is less than zero\n");
14394 return(-1);
14395 }
14396 if (toBool)
14397 return(xmlXPathCompOpEvalToBoolean(ctxt,
14398 &comp->steps[comp->last], 0));
14399 else
14400 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14401
14402 return(0);
14403 }
14404
14405 /************************************************************************
14406 * *
14407 * Public interfaces *
14408 * *
14409 ************************************************************************/
14410
14411 /**
14412 * xmlXPathEvalPredicate:
14413 * @ctxt: the XPath context
14414 * @res: the Predicate Expression evaluation result
14415 *
14416 * Evaluate a predicate result for the current node.
14417 * A PredicateExpr is evaluated by evaluating the Expr and converting
14418 * the result to a boolean. If the result is a number, the result will
14419 * be converted to true if the number is equal to the position of the
14420 * context node in the context node list (as returned by the position
14421 * function) and will be converted to false otherwise; if the result
14422 * is not a number, then the result will be converted as if by a call
14423 * to the boolean function.
14424 *
14425 * Returns 1 if predicate is true, 0 otherwise
14426 */
14427 int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt,xmlXPathObjectPtr res)14428 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14429 if ((ctxt == NULL) || (res == NULL)) return(0);
14430 switch (res->type) {
14431 case XPATH_BOOLEAN:
14432 return(res->boolval);
14433 case XPATH_NUMBER:
14434 return(res->floatval == ctxt->proximityPosition);
14435 case XPATH_NODESET:
14436 case XPATH_XSLT_TREE:
14437 if (res->nodesetval == NULL)
14438 return(0);
14439 return(res->nodesetval->nodeNr != 0);
14440 case XPATH_STRING:
14441 return((res->stringval != NULL) &&
14442 (xmlStrlen(res->stringval) != 0));
14443 default:
14444 STRANGE
14445 }
14446 return(0);
14447 }
14448
14449 /**
14450 * xmlXPathEvaluatePredicateResult:
14451 * @ctxt: the XPath Parser context
14452 * @res: the Predicate Expression evaluation result
14453 *
14454 * Evaluate a predicate result for the current node.
14455 * A PredicateExpr is evaluated by evaluating the Expr and converting
14456 * the result to a boolean. If the result is a number, the result will
14457 * be converted to true if the number is equal to the position of the
14458 * context node in the context node list (as returned by the position
14459 * function) and will be converted to false otherwise; if the result
14460 * is not a number, then the result will be converted as if by a call
14461 * to the boolean function.
14462 *
14463 * Returns 1 if predicate is true, 0 otherwise
14464 */
14465 int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,xmlXPathObjectPtr res)14466 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14467 xmlXPathObjectPtr res) {
14468 if ((ctxt == NULL) || (res == NULL)) return(0);
14469 switch (res->type) {
14470 case XPATH_BOOLEAN:
14471 return(res->boolval);
14472 case XPATH_NUMBER:
14473 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14474 return((res->floatval == ctxt->context->proximityPosition) &&
14475 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14476 #else
14477 return(res->floatval == ctxt->context->proximityPosition);
14478 #endif
14479 case XPATH_NODESET:
14480 case XPATH_XSLT_TREE:
14481 if (res->nodesetval == NULL)
14482 return(0);
14483 return(res->nodesetval->nodeNr != 0);
14484 case XPATH_STRING:
14485 return((res->stringval != NULL) && (res->stringval[0] != 0));
14486 #ifdef LIBXML_XPTR_ENABLED
14487 case XPATH_LOCATIONSET:{
14488 xmlLocationSetPtr ptr = res->user;
14489 if (ptr == NULL)
14490 return(0);
14491 return (ptr->locNr != 0);
14492 }
14493 #endif
14494 default:
14495 STRANGE
14496 }
14497 return(0);
14498 }
14499
14500 #ifdef XPATH_STREAMING
14501 /**
14502 * xmlXPathTryStreamCompile:
14503 * @ctxt: an XPath context
14504 * @str: the XPath expression
14505 *
14506 * Try to compile the XPath expression as a streamable subset.
14507 *
14508 * Returns the compiled expression or NULL if failed to compile.
14509 */
14510 static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14511 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14512 /*
14513 * Optimization: use streaming patterns when the XPath expression can
14514 * be compiled to a stream lookup
14515 */
14516 xmlPatternPtr stream;
14517 xmlXPathCompExprPtr comp;
14518 xmlDictPtr dict = NULL;
14519 const xmlChar **namespaces = NULL;
14520 xmlNsPtr ns;
14521 int i, j;
14522
14523 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14524 (!xmlStrchr(str, '@'))) {
14525 const xmlChar *tmp;
14526
14527 /*
14528 * We don't try to handle expressions using the verbose axis
14529 * specifiers ("::"), just the simplied form at this point.
14530 * Additionally, if there is no list of namespaces available and
14531 * there's a ":" in the expression, indicating a prefixed QName,
14532 * then we won't try to compile either. xmlPatterncompile() needs
14533 * to have a list of namespaces at compilation time in order to
14534 * compile prefixed name tests.
14535 */
14536 tmp = xmlStrchr(str, ':');
14537 if ((tmp != NULL) &&
14538 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14539 return(NULL);
14540
14541 if (ctxt != NULL) {
14542 dict = ctxt->dict;
14543 if (ctxt->nsNr > 0) {
14544 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14545 if (namespaces == NULL) {
14546 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14547 return(NULL);
14548 }
14549 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14550 ns = ctxt->namespaces[j];
14551 namespaces[i++] = ns->href;
14552 namespaces[i++] = ns->prefix;
14553 }
14554 namespaces[i++] = NULL;
14555 namespaces[i] = NULL;
14556 }
14557 }
14558
14559 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14560 &namespaces[0]);
14561 if (namespaces != NULL) {
14562 xmlFree((xmlChar **)namespaces);
14563 }
14564 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14565 comp = xmlXPathNewCompExpr();
14566 if (comp == NULL) {
14567 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14568 return(NULL);
14569 }
14570 comp->stream = stream;
14571 comp->dict = dict;
14572 if (comp->dict)
14573 xmlDictReference(comp->dict);
14574 return(comp);
14575 }
14576 xmlFreePattern(stream);
14577 }
14578 return(NULL);
14579 }
14580 #endif /* XPATH_STREAMING */
14581
14582 static void
xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp,xmlXPathStepOpPtr op)14583 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14584 {
14585 /*
14586 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14587 * internal representation.
14588 */
14589
14590 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14591 (op->ch1 != -1) &&
14592 (op->ch2 == -1 /* no predicate */))
14593 {
14594 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14595
14596 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14597 ((xmlXPathAxisVal) prevop->value ==
14598 AXIS_DESCENDANT_OR_SELF) &&
14599 (prevop->ch2 == -1) &&
14600 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14601 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14602 {
14603 /*
14604 * This is a "descendant-or-self::node()" without predicates.
14605 * Try to eliminate it.
14606 */
14607
14608 switch ((xmlXPathAxisVal) op->value) {
14609 case AXIS_CHILD:
14610 case AXIS_DESCENDANT:
14611 /*
14612 * Convert "descendant-or-self::node()/child::" or
14613 * "descendant-or-self::node()/descendant::" to
14614 * "descendant::"
14615 */
14616 op->ch1 = prevop->ch1;
14617 op->value = AXIS_DESCENDANT;
14618 break;
14619 case AXIS_SELF:
14620 case AXIS_DESCENDANT_OR_SELF:
14621 /*
14622 * Convert "descendant-or-self::node()/self::" or
14623 * "descendant-or-self::node()/descendant-or-self::" to
14624 * to "descendant-or-self::"
14625 */
14626 op->ch1 = prevop->ch1;
14627 op->value = AXIS_DESCENDANT_OR_SELF;
14628 break;
14629 default:
14630 break;
14631 }
14632 }
14633 }
14634
14635 /* OP_VALUE has invalid ch1. */
14636 if (op->op == XPATH_OP_VALUE)
14637 return;
14638
14639 /* Recurse */
14640 if (op->ch1 != -1)
14641 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14642 if (op->ch2 != -1)
14643 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14644 }
14645
14646 /**
14647 * xmlXPathCtxtCompile:
14648 * @ctxt: an XPath context
14649 * @str: the XPath expression
14650 *
14651 * Compile an XPath expression
14652 *
14653 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14654 * the caller has to free the object.
14655 */
14656 xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt,const xmlChar * str)14657 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14658 xmlXPathParserContextPtr pctxt;
14659 xmlXPathCompExprPtr comp;
14660
14661 #ifdef XPATH_STREAMING
14662 comp = xmlXPathTryStreamCompile(ctxt, str);
14663 if (comp != NULL)
14664 return(comp);
14665 #endif
14666
14667 xmlXPathInit();
14668
14669 pctxt = xmlXPathNewParserContext(str, ctxt);
14670 if (pctxt == NULL)
14671 return NULL;
14672 xmlXPathCompileExpr(pctxt, 1);
14673
14674 if( pctxt->error != XPATH_EXPRESSION_OK )
14675 {
14676 xmlXPathFreeParserContext(pctxt);
14677 return(NULL);
14678 }
14679
14680 if (*pctxt->cur != 0) {
14681 /*
14682 * aleksey: in some cases this line prints *second* error message
14683 * (see bug #78858) and probably this should be fixed.
14684 * However, we are not sure that all error messages are printed
14685 * out in other places. It's not critical so we leave it as-is for now
14686 */
14687 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14688 comp = NULL;
14689 } else {
14690 comp = pctxt->comp;
14691 pctxt->comp = NULL;
14692 }
14693 xmlXPathFreeParserContext(pctxt);
14694
14695 if (comp != NULL) {
14696 comp->expr = xmlStrdup(str);
14697 #ifdef DEBUG_EVAL_COUNTS
14698 comp->string = xmlStrdup(str);
14699 comp->nb = 0;
14700 #endif
14701 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14702 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14703 }
14704 }
14705 return(comp);
14706 }
14707
14708 /**
14709 * xmlXPathCompile:
14710 * @str: the XPath expression
14711 *
14712 * Compile an XPath expression
14713 *
14714 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14715 * the caller has to free the object.
14716 */
14717 xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar * str)14718 xmlXPathCompile(const xmlChar *str) {
14719 return(xmlXPathCtxtCompile(NULL, str));
14720 }
14721
14722 /**
14723 * xmlXPathCompiledEvalInternal:
14724 * @comp: the compiled XPath expression
14725 * @ctxt: the XPath context
14726 * @resObj: the resulting XPath object or NULL
14727 * @toBool: 1 if only a boolean result is requested
14728 *
14729 * Evaluate the Precompiled XPath expression in the given context.
14730 * The caller has to free @resObj.
14731 *
14732 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14733 * the caller has to free the object.
14734 */
14735 static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt,xmlXPathObjectPtr * resObjPtr,int toBool)14736 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14737 xmlXPathContextPtr ctxt,
14738 xmlXPathObjectPtr *resObjPtr,
14739 int toBool)
14740 {
14741 xmlXPathParserContextPtr pctxt;
14742 xmlXPathObjectPtr resObj;
14743 #ifndef LIBXML_THREAD_ENABLED
14744 static int reentance = 0;
14745 #endif
14746 int res;
14747
14748 CHECK_CTXT_NEG(ctxt)
14749
14750 if (comp == NULL)
14751 return(-1);
14752 xmlXPathInit();
14753
14754 #ifndef LIBXML_THREAD_ENABLED
14755 reentance++;
14756 if (reentance > 1)
14757 xmlXPathDisableOptimizer = 1;
14758 #endif
14759
14760 #ifdef DEBUG_EVAL_COUNTS
14761 comp->nb++;
14762 if ((comp->string != NULL) && (comp->nb > 100)) {
14763 fprintf(stderr, "100 x %s\n", comp->string);
14764 comp->nb = 0;
14765 }
14766 #endif
14767 pctxt = xmlXPathCompParserContext(comp, ctxt);
14768 res = xmlXPathRunEval(pctxt, toBool);
14769
14770 if (pctxt->error != XPATH_EXPRESSION_OK) {
14771 resObj = NULL;
14772 } else {
14773 resObj = valuePop(pctxt);
14774 if (resObj == NULL) {
14775 if (!toBool)
14776 xmlGenericError(xmlGenericErrorContext,
14777 "xmlXPathCompiledEval: No result on the stack.\n");
14778 } else if (pctxt->valueNr > 0) {
14779 xmlGenericError(xmlGenericErrorContext,
14780 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14781 pctxt->valueNr);
14782 }
14783 }
14784
14785 if (resObjPtr)
14786 *resObjPtr = resObj;
14787 else
14788 xmlXPathReleaseObject(ctxt, resObj);
14789
14790 pctxt->comp = NULL;
14791 xmlXPathFreeParserContext(pctxt);
14792 #ifndef LIBXML_THREAD_ENABLED
14793 reentance--;
14794 #endif
14795
14796 return(res);
14797 }
14798
14799 /**
14800 * xmlXPathCompiledEval:
14801 * @comp: the compiled XPath expression
14802 * @ctx: the XPath context
14803 *
14804 * Evaluate the Precompiled XPath expression in the given context.
14805 *
14806 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14807 * the caller has to free the object.
14808 */
14809 xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctx)14810 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14811 {
14812 xmlXPathObjectPtr res = NULL;
14813
14814 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14815 return(res);
14816 }
14817
14818 /**
14819 * xmlXPathCompiledEvalToBoolean:
14820 * @comp: the compiled XPath expression
14821 * @ctxt: the XPath context
14822 *
14823 * Applies the XPath boolean() function on the result of the given
14824 * compiled expression.
14825 *
14826 * Returns 1 if the expression evaluated to true, 0 if to false and
14827 * -1 in API and internal errors.
14828 */
14829 int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,xmlXPathContextPtr ctxt)14830 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14831 xmlXPathContextPtr ctxt)
14832 {
14833 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14834 }
14835
14836 /**
14837 * xmlXPathEvalExpr:
14838 * @ctxt: the XPath Parser context
14839 *
14840 * Parse and evaluate an XPath expression in the given context,
14841 * then push the result on the context stack
14842 */
14843 void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt)14844 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14845 #ifdef XPATH_STREAMING
14846 xmlXPathCompExprPtr comp;
14847 #endif
14848
14849 if (ctxt == NULL) return;
14850
14851 #ifdef XPATH_STREAMING
14852 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14853 if (comp != NULL) {
14854 if (ctxt->comp != NULL)
14855 xmlXPathFreeCompExpr(ctxt->comp);
14856 ctxt->comp = comp;
14857 } else
14858 #endif
14859 {
14860 xmlXPathCompileExpr(ctxt, 1);
14861 CHECK_ERROR;
14862
14863 /* Check for trailing characters. */
14864 if (*ctxt->cur != 0)
14865 XP_ERROR(XPATH_EXPR_ERROR);
14866
14867 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
14868 xmlXPathOptimizeExpression(ctxt->comp,
14869 &ctxt->comp->steps[ctxt->comp->last]);
14870 }
14871
14872 xmlXPathRunEval(ctxt, 0);
14873 }
14874
14875 /**
14876 * xmlXPathEval:
14877 * @str: the XPath expression
14878 * @ctx: the XPath context
14879 *
14880 * Evaluate the XPath Location Path in the given context.
14881 *
14882 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14883 * the caller has to free the object.
14884 */
14885 xmlXPathObjectPtr
xmlXPathEval(const xmlChar * str,xmlXPathContextPtr ctx)14886 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14887 xmlXPathParserContextPtr ctxt;
14888 xmlXPathObjectPtr res;
14889
14890 CHECK_CTXT(ctx)
14891
14892 xmlXPathInit();
14893
14894 ctxt = xmlXPathNewParserContext(str, ctx);
14895 if (ctxt == NULL)
14896 return NULL;
14897 xmlXPathEvalExpr(ctxt);
14898
14899 if (ctxt->error != XPATH_EXPRESSION_OK) {
14900 res = NULL;
14901 } else {
14902 res = valuePop(ctxt);
14903 if (res == NULL) {
14904 xmlGenericError(xmlGenericErrorContext,
14905 "xmlXPathCompiledEval: No result on the stack.\n");
14906 } else if (ctxt->valueNr > 0) {
14907 xmlGenericError(xmlGenericErrorContext,
14908 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14909 ctxt->valueNr);
14910 }
14911 }
14912
14913 xmlXPathFreeParserContext(ctxt);
14914 return(res);
14915 }
14916
14917 /**
14918 * xmlXPathSetContextNode:
14919 * @node: the node to to use as the context node
14920 * @ctx: the XPath context
14921 *
14922 * Sets 'node' as the context node. The node must be in the same
14923 * document as that associated with the context.
14924 *
14925 * Returns -1 in case of error or 0 if successful
14926 */
14927 int
xmlXPathSetContextNode(xmlNodePtr node,xmlXPathContextPtr ctx)14928 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14929 if ((node == NULL) || (ctx == NULL))
14930 return(-1);
14931
14932 if (node->doc == ctx->doc) {
14933 ctx->node = node;
14934 return(0);
14935 }
14936 return(-1);
14937 }
14938
14939 /**
14940 * xmlXPathNodeEval:
14941 * @node: the node to to use as the context node
14942 * @str: the XPath expression
14943 * @ctx: the XPath context
14944 *
14945 * Evaluate the XPath Location Path in the given context. The node 'node'
14946 * is set as the context node. The context node is not restored.
14947 *
14948 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14949 * the caller has to free the object.
14950 */
14951 xmlXPathObjectPtr
xmlXPathNodeEval(xmlNodePtr node,const xmlChar * str,xmlXPathContextPtr ctx)14952 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14953 if (str == NULL)
14954 return(NULL);
14955 if (xmlXPathSetContextNode(node, ctx) < 0)
14956 return(NULL);
14957 return(xmlXPathEval(str, ctx));
14958 }
14959
14960 /**
14961 * xmlXPathEvalExpression:
14962 * @str: the XPath expression
14963 * @ctxt: the XPath context
14964 *
14965 * Alias for xmlXPathEval().
14966 *
14967 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14968 * the caller has to free the object.
14969 */
14970 xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar * str,xmlXPathContextPtr ctxt)14971 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14972 return(xmlXPathEval(str, ctxt));
14973 }
14974
14975 /************************************************************************
14976 * *
14977 * Extra functions not pertaining to the XPath spec *
14978 * *
14979 ************************************************************************/
14980 /**
14981 * xmlXPathEscapeUriFunction:
14982 * @ctxt: the XPath Parser context
14983 * @nargs: the number of arguments
14984 *
14985 * Implement the escape-uri() XPath function
14986 * string escape-uri(string $str, bool $escape-reserved)
14987 *
14988 * This function applies the URI escaping rules defined in section 2 of [RFC
14989 * 2396] to the string supplied as $uri-part, which typically represents all
14990 * or part of a URI. The effect of the function is to replace any special
14991 * character in the string by an escape sequence of the form %xx%yy...,
14992 * where xxyy... is the hexadecimal representation of the octets used to
14993 * represent the character in UTF-8.
14994 *
14995 * The set of characters that are escaped depends on the setting of the
14996 * boolean argument $escape-reserved.
14997 *
14998 * If $escape-reserved is true, all characters are escaped other than lower
14999 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15000 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15001 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15002 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15003 * A-F).
15004 *
15005 * If $escape-reserved is false, the behavior differs in that characters
15006 * referred to in [RFC 2396] as reserved characters are not escaped. These
15007 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15008 *
15009 * [RFC 2396] does not define whether escaped URIs should use lower case or
15010 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15011 * compared using string comparison functions, this function must always use
15012 * the upper-case letters A-F.
15013 *
15014 * Generally, $escape-reserved should be set to true when escaping a string
15015 * that is to form a single part of a URI, and to false when escaping an
15016 * entire URI or URI reference.
15017 *
15018 * In the case of non-ascii characters, the string is encoded according to
15019 * utf-8 and then converted according to RFC 2396.
15020 *
15021 * Examples
15022 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15023 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15024 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15025 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15026 *
15027 */
15028 static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt,int nargs)15029 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15030 xmlXPathObjectPtr str;
15031 int escape_reserved;
15032 xmlBufPtr target;
15033 xmlChar *cptr;
15034 xmlChar escape[4];
15035
15036 CHECK_ARITY(2);
15037
15038 escape_reserved = xmlXPathPopBoolean(ctxt);
15039
15040 CAST_TO_STRING;
15041 str = valuePop(ctxt);
15042
15043 target = xmlBufCreate();
15044
15045 escape[0] = '%';
15046 escape[3] = 0;
15047
15048 if (target) {
15049 for (cptr = str->stringval; *cptr; cptr++) {
15050 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15051 (*cptr >= 'a' && *cptr <= 'z') ||
15052 (*cptr >= '0' && *cptr <= '9') ||
15053 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15054 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15055 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15056 (*cptr == '%' &&
15057 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15058 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15059 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15060 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15061 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15062 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15063 (!escape_reserved &&
15064 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15065 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15066 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15067 *cptr == ','))) {
15068 xmlBufAdd(target, cptr, 1);
15069 } else {
15070 if ((*cptr >> 4) < 10)
15071 escape[1] = '0' + (*cptr >> 4);
15072 else
15073 escape[1] = 'A' - 10 + (*cptr >> 4);
15074 if ((*cptr & 0xF) < 10)
15075 escape[2] = '0' + (*cptr & 0xF);
15076 else
15077 escape[2] = 'A' - 10 + (*cptr & 0xF);
15078
15079 xmlBufAdd(target, &escape[0], 3);
15080 }
15081 }
15082 }
15083 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15084 xmlBufContent(target)));
15085 xmlBufFree(target);
15086 xmlXPathReleaseObject(ctxt->context, str);
15087 }
15088
15089 /**
15090 * xmlXPathRegisterAllFunctions:
15091 * @ctxt: the XPath context
15092 *
15093 * Registers all default XPath functions in this context
15094 */
15095 void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)15096 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15097 {
15098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15099 xmlXPathBooleanFunction);
15100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15101 xmlXPathCeilingFunction);
15102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15103 xmlXPathCountFunction);
15104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15105 xmlXPathConcatFunction);
15106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15107 xmlXPathContainsFunction);
15108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15109 xmlXPathIdFunction);
15110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15111 xmlXPathFalseFunction);
15112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15113 xmlXPathFloorFunction);
15114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15115 xmlXPathLastFunction);
15116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15117 xmlXPathLangFunction);
15118 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15119 xmlXPathLocalNameFunction);
15120 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15121 xmlXPathNotFunction);
15122 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15123 xmlXPathNameFunction);
15124 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15125 xmlXPathNamespaceURIFunction);
15126 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15127 xmlXPathNormalizeFunction);
15128 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15129 xmlXPathNumberFunction);
15130 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15131 xmlXPathPositionFunction);
15132 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15133 xmlXPathRoundFunction);
15134 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15135 xmlXPathStringFunction);
15136 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15137 xmlXPathStringLengthFunction);
15138 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15139 xmlXPathStartsWithFunction);
15140 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15141 xmlXPathSubstringFunction);
15142 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15143 xmlXPathSubstringBeforeFunction);
15144 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15145 xmlXPathSubstringAfterFunction);
15146 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15147 xmlXPathSumFunction);
15148 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15149 xmlXPathTrueFunction);
15150 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15151 xmlXPathTranslateFunction);
15152
15153 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15154 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15155 xmlXPathEscapeUriFunction);
15156 }
15157
15158 #endif /* LIBXML_XPATH_ENABLED */
15159 #define bottom_xpath
15160 #include "elfgcchack.h"
15161