ReactOS  0.4.14-dev-49-gfb4591c
xpath.c
Go to the documentation of this file.
1 /*
2  * xpath.c: XML Path Language implementation
3  * XPath is a language for addressing parts of an XML document,
4  * designed to be used by both XSLT and XPointer
5  *
6  * Reference: W3C Recommendation 16 November 1999
7  * http://www.w3.org/TR/1999/REC-xpath-19991116
8  * Public reference:
9  * http://www.w3.org/TR/xpath
10  *
11  * See Copyright for the status of this software
12  *
13  * Author: daniel@veillard.com
14  *
15  */
16 
17 /* To avoid EBCDIC trouble when parsing on zOS */
18 #if defined(__MVS__)
19 #pragma convert("ISO8859-1")
20 #endif
21 
22 #define IN_LIBXML
23 #include "libxml.h"
24 
25 #include <limits.h>
26 #include <string.h>
27 #include <stddef.h>
28 
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_MATH_H
33 #include <math.h>
34 #endif
35 #ifdef HAVE_FLOAT_H
36 #include <float.h>
37 #endif
38 #ifdef HAVE_CTYPE_H
39 #include <ctype.h>
40 #endif
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44 
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
54 #endif
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
57 #endif
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
63 #endif
64 
65 #include "buf.h"
66 
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
69 #endif
70 
71 #define TODO \
72  xmlGenericError(xmlGenericErrorContext, \
73  "Unimplemented block at %s:%d\n", \
74  __FILE__, __LINE__);
75 
83 #define WITH_TIM_SORT
84 
85 /*
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
93 */
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
95 
96 /*
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
100 */
101 #define XP_OPTIMIZED_FILTER_FIRST
102 
103 /*
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
106 * created.
107 */
108 /* #define XP_DEBUG_OBJ_USAGE */
109 
110 /*
111  * XPATH_MAX_STEPS:
112  * when compiling an XPath expression we arbitrary limit the maximum
113  * number of step operation in the compiled expression. 1000000 is
114  * an insanely large value which should never be reached under normal
115  * circumstances
116  */
117 #define XPATH_MAX_STEPS 1000000
118 
119 /*
120  * XPATH_MAX_STACK_DEPTH:
121  * when evaluating an XPath expression we arbitrary limit the maximum
122  * number of object allowed to be pushed on the stack. 1000000 is
123  * an insanely large value which should never be reached under normal
124  * circumstances
125  */
126 #define XPATH_MAX_STACK_DEPTH 1000000
127 
128 /*
129  * XPATH_MAX_NODESET_LENGTH:
130  * when evaluating an XPath expression nodesets are created and we
131  * arbitrary limit the maximum length of those node set. 10000000 is
132  * an insanely large value which should never be reached under normal
133  * circumstances, one would first need to construct an in memory tree
134  * with more than 10 millions nodes.
135  */
136 #define XPATH_MAX_NODESET_LENGTH 10000000
137 
138 /*
139  * TODO:
140  * There are a few spots where some tests are done which depend upon ascii
141  * data. These should be enhanced for full UTF8 support (see particularly
142  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143  */
144 
145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146 
157 static int
159  int depth1, depth2;
160  int misc = 0, precedence1 = 0, precedence2 = 0;
161  xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162  xmlNodePtr cur, root;
163  ptrdiff_t l1, l2;
164 
165  if ((node1 == NULL) || (node2 == NULL))
166  return(-2);
167 
168  if (node1 == node2)
169  return(0);
170 
171  /*
172  * a couple of optimizations which will avoid computations in most cases
173  */
174  switch (node1->type) {
175  case XML_ELEMENT_NODE:
176  if (node2->type == XML_ELEMENT_NODE) {
177  if ((0 > (ptrdiff_t) node1->content) &&
178  (0 > (ptrdiff_t) node2->content) &&
179  (node1->doc == node2->doc))
180  {
181  l1 = -((ptrdiff_t) node1->content);
182  l2 = -((ptrdiff_t) node2->content);
183  if (l1 < l2)
184  return(1);
185  if (l1 > l2)
186  return(-1);
187  } else
188  goto turtle_comparison;
189  }
190  break;
191  case XML_ATTRIBUTE_NODE:
192  precedence1 = 1; /* element is owner */
193  miscNode1 = node1;
194  node1 = node1->parent;
195  misc = 1;
196  break;
197  case XML_TEXT_NODE:
199  case XML_COMMENT_NODE:
200  case XML_PI_NODE: {
201  miscNode1 = node1;
202  /*
203  * Find nearest element node.
204  */
205  if (node1->prev != NULL) {
206  do {
207  node1 = node1->prev;
208  if (node1->type == XML_ELEMENT_NODE) {
209  precedence1 = 3; /* element in prev-sibl axis */
210  break;
211  }
212  if (node1->prev == NULL) {
213  precedence1 = 2; /* element is parent */
214  /*
215  * URGENT TODO: Are there any cases, where the
216  * parent of such a node is not an element node?
217  */
218  node1 = node1->parent;
219  break;
220  }
221  } while (1);
222  } else {
223  precedence1 = 2; /* element is parent */
224  node1 = node1->parent;
225  }
226  if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
227  (0 <= (ptrdiff_t) node1->content)) {
228  /*
229  * Fallback for whatever case.
230  */
231  node1 = miscNode1;
232  precedence1 = 0;
233  } else
234  misc = 1;
235  }
236  break;
237  case XML_NAMESPACE_DECL:
238  /*
239  * TODO: why do we return 1 for namespace nodes?
240  */
241  return(1);
242  default:
243  break;
244  }
245  switch (node2->type) {
246  case XML_ELEMENT_NODE:
247  break;
248  case XML_ATTRIBUTE_NODE:
249  precedence2 = 1; /* element is owner */
250  miscNode2 = node2;
251  node2 = node2->parent;
252  misc = 1;
253  break;
254  case XML_TEXT_NODE:
256  case XML_COMMENT_NODE:
257  case XML_PI_NODE: {
258  miscNode2 = node2;
259  if (node2->prev != NULL) {
260  do {
261  node2 = node2->prev;
262  if (node2->type == XML_ELEMENT_NODE) {
263  precedence2 = 3; /* element in prev-sibl axis */
264  break;
265  }
266  if (node2->prev == NULL) {
267  precedence2 = 2; /* element is parent */
268  node2 = node2->parent;
269  break;
270  }
271  } while (1);
272  } else {
273  precedence2 = 2; /* element is parent */
274  node2 = node2->parent;
275  }
276  if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
277  (0 <= (ptrdiff_t) node2->content))
278  {
279  node2 = miscNode2;
280  precedence2 = 0;
281  } else
282  misc = 1;
283  }
284  break;
285  case XML_NAMESPACE_DECL:
286  return(1);
287  default:
288  break;
289  }
290  if (misc) {
291  if (node1 == node2) {
292  if (precedence1 == precedence2) {
293  /*
294  * The ugly case; but normally there aren't many
295  * adjacent non-element nodes around.
296  */
297  cur = miscNode2->prev;
298  while (cur != NULL) {
299  if (cur == miscNode1)
300  return(1);
301  if (cur->type == XML_ELEMENT_NODE)
302  return(-1);
303  cur = cur->prev;
304  }
305  return (-1);
306  } else {
307  /*
308  * Evaluate based on higher precedence wrt to the element.
309  * TODO: This assumes attributes are sorted before content.
310  * Is this 100% correct?
311  */
312  if (precedence1 < precedence2)
313  return(1);
314  else
315  return(-1);
316  }
317  }
318  /*
319  * Special case: One of the helper-elements is contained by the other.
320  * <foo>
321  * <node2>
322  * <node1>Text-1(precedence1 == 2)</node1>
323  * </node2>
324  * Text-6(precedence2 == 3)
325  * </foo>
326  */
327  if ((precedence2 == 3) && (precedence1 > 1)) {
328  cur = node1->parent;
329  while (cur) {
330  if (cur == node2)
331  return(1);
332  cur = cur->parent;
333  }
334  }
335  if ((precedence1 == 3) && (precedence2 > 1)) {
336  cur = node2->parent;
337  while (cur) {
338  if (cur == node1)
339  return(-1);
340  cur = cur->parent;
341  }
342  }
343  }
344 
345  /*
346  * Speedup using document order if availble.
347  */
348  if ((node1->type == XML_ELEMENT_NODE) &&
349  (node2->type == XML_ELEMENT_NODE) &&
350  (0 > (ptrdiff_t) node1->content) &&
351  (0 > (ptrdiff_t) node2->content) &&
352  (node1->doc == node2->doc)) {
353 
354  l1 = -((ptrdiff_t) node1->content);
355  l2 = -((ptrdiff_t) node2->content);
356  if (l1 < l2)
357  return(1);
358  if (l1 > l2)
359  return(-1);
360  }
361 
362 turtle_comparison:
363 
364  if (node1 == node2->prev)
365  return(1);
366  if (node1 == node2->next)
367  return(-1);
368  /*
369  * compute depth to root
370  */
371  for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372  if (cur->parent == node1)
373  return(1);
374  depth2++;
375  }
376  root = cur;
377  for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378  if (cur->parent == node2)
379  return(-1);
380  depth1++;
381  }
382  /*
383  * Distinct document (or distinct entities :-( ) case.
384  */
385  if (root != cur) {
386  return(-2);
387  }
388  /*
389  * get the nearest common ancestor.
390  */
391  while (depth1 > depth2) {
392  depth1--;
393  node1 = node1->parent;
394  }
395  while (depth2 > depth1) {
396  depth2--;
397  node2 = node2->parent;
398  }
399  while (node1->parent != node2->parent) {
400  node1 = node1->parent;
401  node2 = node2->parent;
402  /* should not happen but just in case ... */
403  if ((node1 == NULL) || (node2 == NULL))
404  return(-2);
405  }
406  /*
407  * Find who's first.
408  */
409  if (node1 == node2->prev)
410  return(1);
411  if (node1 == node2->next)
412  return(-1);
413  /*
414  * Speedup using document order if availble.
415  */
416  if ((node1->type == XML_ELEMENT_NODE) &&
417  (node2->type == XML_ELEMENT_NODE) &&
418  (0 > (ptrdiff_t) node1->content) &&
419  (0 > (ptrdiff_t) node2->content) &&
420  (node1->doc == node2->doc)) {
421 
422  l1 = -((ptrdiff_t) node1->content);
423  l2 = -((ptrdiff_t) node2->content);
424  if (l1 < l2)
425  return(1);
426  if (l1 > l2)
427  return(-1);
428  }
429 
430  for (cur = node1->next;cur != NULL;cur = cur->next)
431  if (cur == node2)
432  return(1);
433  return(-1); /* assume there is no sibling list corruption */
434 }
435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436 
437 /*
438  * Wrapper for the Timsort argorithm from timsort.h
439  */
440 #ifdef WITH_TIM_SORT
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
443 
453 static
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
457  {
458  int res = xmlXPathCmpNodesExt(x, y);
459  return res == -2 ? res : -res;
460  }
461 #else
462  static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463  {
464  int res = xmlXPathCmpNodes(x, y);
465  return res == -2 ? res : -res;
466  }
467 #endif
468 #define SORT_CMP(x, y) (wrap_cmp(x, y))
469 #include "timsort.h"
470 #endif /* WITH_TIM_SORT */
471 
472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
473 
474 /************************************************************************
475  * *
476  * Floating point stuff *
477  * *
478  ************************************************************************/
479 
480 #ifndef INFINITY
481 #define INFINITY (DBL_MAX * DBL_MAX)
482 #endif
483 
484 #ifndef NAN
485 #define NAN (INFINITY / INFINITY)
486 #endif
487 
488 double xmlXPathNAN;
489 double xmlXPathPINF;
490 double xmlXPathNINF;
491 
497 void
498 xmlXPathInit(void) {
499  xmlXPathNAN = NAN;
500  xmlXPathPINF = INFINITY;
501  xmlXPathNINF = -INFINITY;
502 }
503 
510 int
511 xmlXPathIsNaN(double val) {
512 #ifdef isnan
513  return isnan(val);
514 #else
515  return !(val == val);
516 #endif
517 }
518 
525 int
526 xmlXPathIsInf(double val) {
527 #ifdef isinf
528  return isinf(val) ? (val > 0 ? 1 : -1) : 0;
529 #else
530  if (val >= INFINITY)
531  return 1;
532  if (val <= -INFINITY)
533  return -1;
534  return 0;
535 #endif
536 }
537 
538 #endif /* SCHEMAS or XPATH */
539 
540 #ifdef LIBXML_XPATH_ENABLED
541 
542 /*
543  * TODO: when compatibility allows remove all "fake node libxslt" strings
544  * the test should just be name[0] = ' '
545  */
546 #ifdef DEBUG_XPATH_EXPRESSION
547 #define DEBUG_STEP
548 #define DEBUG_EXPR
549 #define DEBUG_EVAL_COUNTS
550 #endif
551 
552 static xmlNs xmlXPathXMLNamespaceStruct = {
553  NULL,
556  BAD_CAST "xml",
557  NULL,
558  NULL
559 };
560 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
561 #ifndef LIBXML_THREAD_ENABLED
562 /*
563  * Optimizer is disabled only when threaded apps are detected while
564  * the library ain't compiled for thread safety.
565  */
566 static int xmlXPathDisableOptimizer = 0;
567 #endif
568 
569 /************************************************************************
570  * *
571  * Error handling routines *
572  * *
573  ************************************************************************/
574 
581 #define XP_ERRORNULL(X) \
582  { xmlXPathErr(ctxt, X); return(NULL); }
583 
584 /*
585  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
586  */
587 static const char *xmlXPathErrorMessages[] = {
588  "Ok\n",
589  "Number encoding\n",
590  "Unfinished literal\n",
591  "Start of literal\n",
592  "Expected $ for variable reference\n",
593  "Undefined variable\n",
594  "Invalid predicate\n",
595  "Invalid expression\n",
596  "Missing closing curly brace\n",
597  "Unregistered function\n",
598  "Invalid operand\n",
599  "Invalid type\n",
600  "Invalid number of arguments\n",
601  "Invalid context size\n",
602  "Invalid context position\n",
603  "Memory allocation error\n",
604  "Syntax error\n",
605  "Resource error\n",
606  "Sub resource error\n",
607  "Undefined namespace prefix\n",
608  "Encoding error\n",
609  "Char out of XML range\n",
610  "Invalid or incomplete context\n",
611  "Stack usage error\n",
612  "Forbidden variable\n",
613  "?? Unknown error ??\n" /* Must be last in the list! */
614 };
615 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
616  sizeof(xmlXPathErrorMessages[0])) - 1)
617 
624 static void
625 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
626 {
627  if (ctxt != NULL) {
628  if (extra) {
629  xmlChar buf[200];
630 
631  xmlStrPrintf(buf, 200,
632  "Memory allocation failed : %s\n",
633  extra);
634  ctxt->lastError.message = (char *) xmlStrdup(buf);
635  } else {
636  ctxt->lastError.message = (char *)
637  xmlStrdup(BAD_CAST "Memory allocation failed\n");
638  }
639  ctxt->lastError.domain = XML_FROM_XPATH;
640  ctxt->lastError.code = XML_ERR_NO_MEMORY;
641  if (ctxt->error != NULL)
642  ctxt->error(ctxt->userData, &ctxt->lastError);
643  } else {
644  if (extra)
645  __xmlRaiseError(NULL, NULL, NULL,
648  extra, NULL, NULL, 0, 0,
649  "Memory allocation failed : %s\n", extra);
650  else
651  __xmlRaiseError(NULL, NULL, NULL,
654  NULL, NULL, NULL, 0, 0,
655  "Memory allocation failed\n");
656  }
657 }
658 
666 static void
667 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
668 {
669  if (ctxt == NULL)
670  xmlXPathErrMemory(NULL, extra);
671  else {
672  ctxt->error = XPATH_MEMORY_ERROR;
673  xmlXPathErrMemory(ctxt->context, extra);
674  }
675 }
676 
684 void
685 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
686 {
687  if ((error < 0) || (error > MAXERRNO))
688  error = MAXERRNO;
689  if (ctxt == NULL) {
690  __xmlRaiseError(NULL, NULL, NULL,
692  error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
693  XML_ERR_ERROR, NULL, 0,
694  NULL, NULL, NULL, 0, 0,
695  "%s", xmlXPathErrorMessages[error]);
696  return;
697  }
698  ctxt->error = error;
699  if (ctxt->context == NULL) {
700  __xmlRaiseError(NULL, NULL, NULL,
702  error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703  XML_ERR_ERROR, NULL, 0,
704  (const char *) ctxt->base, NULL, NULL,
705  ctxt->cur - ctxt->base, 0,
706  "%s", xmlXPathErrorMessages[error]);
707  return;
708  }
709 
710  /* cleanup current last error */
711  xmlResetError(&ctxt->context->lastError);
712 
713  ctxt->context->lastError.domain = XML_FROM_XPATH;
714  ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
715  XPATH_EXPRESSION_OK;
716  ctxt->context->lastError.level = XML_ERR_ERROR;
717  ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
718  ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
719  ctxt->context->lastError.node = ctxt->context->debugNode;
720  if (ctxt->context->error != NULL) {
721  ctxt->context->error(ctxt->context->userData,
722  &ctxt->context->lastError);
723  } else {
724  __xmlRaiseError(NULL, NULL, NULL,
725  NULL, ctxt->context->debugNode, XML_FROM_XPATH,
726  error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
727  XML_ERR_ERROR, NULL, 0,
728  (const char *) ctxt->base, NULL, NULL,
729  ctxt->cur - ctxt->base, 0,
730  "%s", xmlXPathErrorMessages[error]);
731  }
732 
733 }
734 
744 void
745 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
746  int line ATTRIBUTE_UNUSED, int no) {
747  xmlXPathErr(ctxt, no);
748 }
749 
750 /************************************************************************
751  * *
752  * Utilities *
753  * *
754  ************************************************************************/
755 
761 typedef struct _xmlPointerList xmlPointerList;
762 typedef xmlPointerList *xmlPointerListPtr;
763 struct _xmlPointerList {
764  void **items;
765  int number;
766  int size;
767 };
768 /*
769 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
770 * and here, we should make the functions public.
771 */
772 static int
773 xmlPointerListAddSize(xmlPointerListPtr list,
774  void *item,
775  int initialSize)
776 {
777  if (list->items == NULL) {
778  if (initialSize <= 0)
779  initialSize = 1;
780  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
781  if (list->items == NULL) {
782  xmlXPathErrMemory(NULL,
783  "xmlPointerListCreate: allocating item\n");
784  return(-1);
785  }
786  list->number = 0;
787  list->size = initialSize;
788  } else if (list->size <= list->number) {
789  if (list->size > 50000000) {
790  xmlXPathErrMemory(NULL,
791  "xmlPointerListAddSize: re-allocating item\n");
792  return(-1);
793  }
794  list->size *= 2;
795  list->items = (void **) xmlRealloc(list->items,
796  list->size * sizeof(void *));
797  if (list->items == NULL) {
798  xmlXPathErrMemory(NULL,
799  "xmlPointerListAddSize: re-allocating item\n");
800  list->size = 0;
801  return(-1);
802  }
803  }
804  list->items[list->number++] = item;
805  return(0);
806 }
807 
815 static xmlPointerListPtr
816 xmlPointerListCreate(int initialSize)
817 {
818  xmlPointerListPtr ret;
819 
820  ret = xmlMalloc(sizeof(xmlPointerList));
821  if (ret == NULL) {
822  xmlXPathErrMemory(NULL,
823  "xmlPointerListCreate: allocating item\n");
824  return (NULL);
825  }
826  memset(ret, 0, sizeof(xmlPointerList));
827  if (initialSize > 0) {
828  xmlPointerListAddSize(ret, NULL, initialSize);
829  ret->number = 0;
830  }
831  return (ret);
832 }
833 
840 static void
841 xmlPointerListFree(xmlPointerListPtr list)
842 {
843  if (list == NULL)
844  return;
845  if (list->items != NULL)
846  xmlFree(list->items);
847  xmlFree(list);
848 }
849 
850 /************************************************************************
851  * *
852  * Parser Types *
853  * *
854  ************************************************************************/
855 
856 /*
857  * Types are private:
858  */
859 
860 typedef enum {
861  XPATH_OP_END=0,
862  XPATH_OP_AND,
863  XPATH_OP_OR,
864  XPATH_OP_EQUAL,
865  XPATH_OP_CMP,
866  XPATH_OP_PLUS,
867  XPATH_OP_MULT,
868  XPATH_OP_UNION,
869  XPATH_OP_ROOT,
870  XPATH_OP_NODE,
871  XPATH_OP_COLLECT,
872  XPATH_OP_VALUE, /* 11 */
873  XPATH_OP_VARIABLE,
874  XPATH_OP_FUNCTION,
875  XPATH_OP_ARG,
876  XPATH_OP_PREDICATE,
877  XPATH_OP_FILTER, /* 16 */
878  XPATH_OP_SORT /* 17 */
879 #ifdef LIBXML_XPTR_ENABLED
880  ,XPATH_OP_RANGETO
881 #endif
882 } xmlXPathOp;
883 
884 typedef enum {
885  AXIS_ANCESTOR = 1,
886  AXIS_ANCESTOR_OR_SELF,
888  AXIS_CHILD,
889  AXIS_DESCENDANT,
890  AXIS_DESCENDANT_OR_SELF,
891  AXIS_FOLLOWING,
892  AXIS_FOLLOWING_SIBLING,
893  AXIS_NAMESPACE,
894  AXIS_PARENT,
895  AXIS_PRECEDING,
896  AXIS_PRECEDING_SIBLING,
897  AXIS_SELF
898 } xmlXPathAxisVal;
899 
900 typedef enum {
901  NODE_TEST_NONE = 0,
902  NODE_TEST_TYPE = 1,
903  NODE_TEST_PI = 2,
904  NODE_TEST_ALL = 3,
905  NODE_TEST_NS = 4,
906  NODE_TEST_NAME = 5
907 } xmlXPathTestVal;
908 
909 typedef enum {
910  NODE_TYPE_NODE = 0,
911  NODE_TYPE_COMMENT = XML_COMMENT_NODE,
912  NODE_TYPE_TEXT = XML_TEXT_NODE,
913  NODE_TYPE_PI = XML_PI_NODE
914 } xmlXPathTypeVal;
915 
916 typedef struct _xmlXPathStepOp xmlXPathStepOp;
917 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
918 struct _xmlXPathStepOp {
919  xmlXPathOp op; /* The identifier of the operation */
920  int ch1; /* First child */
921  int ch2; /* Second child */
922  int value;
923  int value2;
924  int value3;
925  void *value4;
926  void *value5;
927  xmlXPathFunction cache;
928  void *cacheURI;
929 };
930 
931 struct _xmlXPathCompExpr {
932  int nbStep; /* Number of steps in this expression */
933  int maxStep; /* Maximum number of steps allocated */
934  xmlXPathStepOp *steps; /* ops for computation of this expression */
935  int last; /* index of last step in expression */
936  xmlChar *expr; /* the expression being computed */
937  xmlDictPtr dict; /* the dictionary to use if any */
938 #ifdef DEBUG_EVAL_COUNTS
939  int nb;
940  xmlChar *string;
941 #endif
942 #ifdef XPATH_STREAMING
943  xmlPatternPtr stream;
944 #endif
945 };
946 
947 /************************************************************************
948  * *
949  * Forward declarations *
950  * *
951  ************************************************************************/
952 static void
953 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
954 static void
955 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
956 static int
957 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
958  xmlXPathStepOpPtr op, xmlNodePtr *first);
959 static int
960 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
961  xmlXPathStepOpPtr op,
962  int isPredicate);
963 static void
964 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
965 
966 /************************************************************************
967  * *
968  * Parser Type functions *
969  * *
970  ************************************************************************/
971 
979 static xmlXPathCompExprPtr
980 xmlXPathNewCompExpr(void) {
981  xmlXPathCompExprPtr cur;
982 
983  cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
984  if (cur == NULL) {
985  xmlXPathErrMemory(NULL, "allocating component\n");
986  return(NULL);
987  }
988  memset(cur, 0, sizeof(xmlXPathCompExpr));
989  cur->maxStep = 10;
990  cur->nbStep = 0;
991  cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
992  sizeof(xmlXPathStepOp));
993  if (cur->steps == NULL) {
994  xmlXPathErrMemory(NULL, "allocating steps\n");
995  xmlFree(cur);
996  return(NULL);
997  }
998  memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
999  cur->last = -1;
1000 #ifdef DEBUG_EVAL_COUNTS
1001  cur->nb = 0;
1002 #endif
1003  return(cur);
1004 }
1005 
1012 void
1013 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1014 {
1015  xmlXPathStepOpPtr op;
1016  int i;
1017 
1018  if (comp == NULL)
1019  return;
1020  if (comp->dict == NULL) {
1021  for (i = 0; i < comp->nbStep; i++) {
1022  op = &comp->steps[i];
1023  if (op->value4 != NULL) {
1024  if (op->op == XPATH_OP_VALUE)
1025  xmlXPathFreeObject(op->value4);
1026  else
1027  xmlFree(op->value4);
1028  }
1029  if (op->value5 != NULL)
1030  xmlFree(op->value5);
1031  }
1032  } else {
1033  for (i = 0; i < comp->nbStep; i++) {
1034  op = &comp->steps[i];
1035  if (op->value4 != NULL) {
1036  if (op->op == XPATH_OP_VALUE)
1037  xmlXPathFreeObject(op->value4);
1038  }
1039  }
1040  xmlDictFree(comp->dict);
1041  }
1042  if (comp->steps != NULL) {
1043  xmlFree(comp->steps);
1044  }
1045 #ifdef DEBUG_EVAL_COUNTS
1046  if (comp->string != NULL) {
1047  xmlFree(comp->string);
1048  }
1049 #endif
1050 #ifdef XPATH_STREAMING
1051  if (comp->stream != NULL) {
1052  xmlFreePatternList(comp->stream);
1053  }
1054 #endif
1055  if (comp->expr != NULL) {
1056  xmlFree(comp->expr);
1057  }
1058 
1059  xmlFree(comp);
1060 }
1061 
1078 static int
1079 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1080  xmlXPathOp op, int value,
1081  int value2, int value3, void *value4, void *value5) {
1082  if (comp->nbStep >= comp->maxStep) {
1083  xmlXPathStepOp *real;
1084 
1085  if (comp->maxStep >= XPATH_MAX_STEPS) {
1086  xmlXPathErrMemory(NULL, "adding step\n");
1087  return(-1);
1088  }
1089  comp->maxStep *= 2;
1090  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1091  comp->maxStep * sizeof(xmlXPathStepOp));
1092  if (real == NULL) {
1093  comp->maxStep /= 2;
1094  xmlXPathErrMemory(NULL, "adding step\n");
1095  return(-1);
1096  }
1097  comp->steps = real;
1098  }
1099  comp->last = comp->nbStep;
1100  comp->steps[comp->nbStep].ch1 = ch1;
1101  comp->steps[comp->nbStep].ch2 = ch2;
1102  comp->steps[comp->nbStep].op = op;
1103  comp->steps[comp->nbStep].value = value;
1104  comp->steps[comp->nbStep].value2 = value2;
1105  comp->steps[comp->nbStep].value3 = value3;
1106  if ((comp->dict != NULL) &&
1107  ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1108  (op == XPATH_OP_COLLECT))) {
1109  if (value4 != NULL) {
1110  comp->steps[comp->nbStep].value4 = (xmlChar *)
1111  (void *)xmlDictLookup(comp->dict, value4, -1);
1112  xmlFree(value4);
1113  } else
1114  comp->steps[comp->nbStep].value4 = NULL;
1115  if (value5 != NULL) {
1116  comp->steps[comp->nbStep].value5 = (xmlChar *)
1117  (void *)xmlDictLookup(comp->dict, value5, -1);
1118  xmlFree(value5);
1119  } else
1120  comp->steps[comp->nbStep].value5 = NULL;
1121  } else {
1122  comp->steps[comp->nbStep].value4 = value4;
1123  comp->steps[comp->nbStep].value5 = value5;
1124  }
1125  comp->steps[comp->nbStep].cache = NULL;
1126  return(comp->nbStep++);
1127 }
1128 
1136 static void
1137 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1138  int tmp;
1139 
1140 #ifndef LIBXML_THREAD_ENABLED
1141  /*
1142  * Since this manipulates possibly shared variables, this is
1143  * disabled if one detects that the library is used in a multithreaded
1144  * application
1145  */
1146  if (xmlXPathDisableOptimizer)
1147  return;
1148 #endif
1149 
1150  tmp = op->ch1;
1151  op->ch1 = op->ch2;
1152  op->ch2 = tmp;
1153 }
1154 
1155 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1156  xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1157  (op), (val), (val2), (val3), (val4), (val5))
1158 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1159  xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1160  (op), (val), (val2), (val3), (val4), (val5))
1161 
1162 #define PUSH_LEAVE_EXPR(op, val, val2) \
1163 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1164 
1165 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1166 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1167 
1168 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1169 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1170  (val), (val2), 0 ,NULL ,NULL)
1171 
1172 /************************************************************************
1173  * *
1174  * XPath object cache structures *
1175  * *
1176  ************************************************************************/
1177 
1178 /* #define XP_DEFAULT_CACHE_ON */
1179 
1180 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1181 
1182 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1183 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1184 struct _xmlXPathContextCache {
1185  xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1186  xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1187  xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1188  xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1189  xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1190  int maxNodeset;
1191  int maxString;
1192  int maxBoolean;
1193  int maxNumber;
1194  int maxMisc;
1195 #ifdef XP_DEBUG_OBJ_USAGE
1196  int dbgCachedAll;
1197  int dbgCachedNodeset;
1198  int dbgCachedString;
1199  int dbgCachedBool;
1200  int dbgCachedNumber;
1201  int dbgCachedPoint;
1202  int dbgCachedRange;
1203  int dbgCachedLocset;
1204  int dbgCachedUsers;
1205  int dbgCachedXSLTTree;
1206  int dbgCachedUndefined;
1207 
1208 
1209  int dbgReusedAll;
1210  int dbgReusedNodeset;
1211  int dbgReusedString;
1212  int dbgReusedBool;
1213  int dbgReusedNumber;
1214  int dbgReusedPoint;
1215  int dbgReusedRange;
1216  int dbgReusedLocset;
1217  int dbgReusedUsers;
1218  int dbgReusedXSLTTree;
1219  int dbgReusedUndefined;
1220 
1221 #endif
1222 };
1223 
1224 /************************************************************************
1225  * *
1226  * Debugging related functions *
1227  * *
1228  ************************************************************************/
1229 
1230 #define STRANGE \
1231  xmlGenericError(xmlGenericErrorContext, \
1232  "Internal error at %s:%d\n", \
1233  __FILE__, __LINE__);
1234 
1235 #ifdef LIBXML_DEBUG_ENABLED
1236 static void
1237 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1238  int i;
1239  char shift[100];
1240 
1241  for (i = 0;((i < depth) && (i < 25));i++)
1242  shift[2 * i] = shift[2 * i + 1] = ' ';
1243  shift[2 * i] = shift[2 * i + 1] = 0;
1244  if (cur == NULL) {
1245  fprintf(output, "%s", shift);
1246  fprintf(output, "Node is NULL !\n");
1247  return;
1248 
1249  }
1250 
1251  if ((cur->type == XML_DOCUMENT_NODE) ||
1252  (cur->type == XML_HTML_DOCUMENT_NODE)) {
1253  fprintf(output, "%s", shift);
1254  fprintf(output, " /\n");
1255  } else if (cur->type == XML_ATTRIBUTE_NODE)
1256  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1257  else
1258  xmlDebugDumpOneNode(output, cur, depth);
1259 }
1260 static void
1261 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1262  xmlNodePtr tmp;
1263  int i;
1264  char shift[100];
1265 
1266  for (i = 0;((i < depth) && (i < 25));i++)
1267  shift[2 * i] = shift[2 * i + 1] = ' ';
1268  shift[2 * i] = shift[2 * i + 1] = 0;
1269  if (cur == NULL) {
1270  fprintf(output, "%s", shift);
1271  fprintf(output, "Node is NULL !\n");
1272  return;
1273 
1274  }
1275 
1276  while (cur != NULL) {
1277  tmp = cur;
1278  cur = cur->next;
1279  xmlDebugDumpOneNode(output, tmp, depth);
1280  }
1281 }
1282 
1283 static void
1284 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1285  int i;
1286  char shift[100];
1287 
1288  for (i = 0;((i < depth) && (i < 25));i++)
1289  shift[2 * i] = shift[2 * i + 1] = ' ';
1290  shift[2 * i] = shift[2 * i + 1] = 0;
1291 
1292  if (cur == NULL) {
1293  fprintf(output, "%s", shift);
1294  fprintf(output, "NodeSet is NULL !\n");
1295  return;
1296 
1297  }
1298 
1299  if (cur != NULL) {
1300  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1301  for (i = 0;i < cur->nodeNr;i++) {
1302  fprintf(output, "%s", shift);
1303  fprintf(output, "%d", i + 1);
1304  xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1305  }
1306  }
1307 }
1308 
1309 static void
1310 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1311  int i;
1312  char shift[100];
1313 
1314  for (i = 0;((i < depth) && (i < 25));i++)
1315  shift[2 * i] = shift[2 * i + 1] = ' ';
1316  shift[2 * i] = shift[2 * i + 1] = 0;
1317 
1318  if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1319  fprintf(output, "%s", shift);
1320  fprintf(output, "Value Tree is NULL !\n");
1321  return;
1322 
1323  }
1324 
1325  fprintf(output, "%s", shift);
1326  fprintf(output, "%d", i + 1);
1327  xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1328 }
1329 #if defined(LIBXML_XPTR_ENABLED)
1330 static void
1331 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1332  int i;
1333  char shift[100];
1334 
1335  for (i = 0;((i < depth) && (i < 25));i++)
1336  shift[2 * i] = shift[2 * i + 1] = ' ';
1337  shift[2 * i] = shift[2 * i + 1] = 0;
1338 
1339  if (cur == NULL) {
1340  fprintf(output, "%s", shift);
1341  fprintf(output, "LocationSet is NULL !\n");
1342  return;
1343 
1344  }
1345 
1346  for (i = 0;i < cur->locNr;i++) {
1347  fprintf(output, "%s", shift);
1348  fprintf(output, "%d : ", i + 1);
1349  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1350  }
1351 }
1352 #endif /* LIBXML_XPTR_ENABLED */
1353 
1362 void
1363 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1364  int i;
1365  char shift[100];
1366 
1367  if (output == NULL) return;
1368 
1369  for (i = 0;((i < depth) && (i < 25));i++)
1370  shift[2 * i] = shift[2 * i + 1] = ' ';
1371  shift[2 * i] = shift[2 * i + 1] = 0;
1372 
1373 
1374  fprintf(output, "%s", shift);
1375 
1376  if (cur == NULL) {
1377  fprintf(output, "Object is empty (NULL)\n");
1378  return;
1379  }
1380  switch(cur->type) {
1381  case XPATH_UNDEFINED:
1382  fprintf(output, "Object is uninitialized\n");
1383  break;
1384  case XPATH_NODESET:
1385  fprintf(output, "Object is a Node Set :\n");
1386  xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1387  break;
1388  case XPATH_XSLT_TREE:
1389  fprintf(output, "Object is an XSLT value tree :\n");
1390  xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1391  break;
1392  case XPATH_BOOLEAN:
1393  fprintf(output, "Object is a Boolean : ");
1394  if (cur->boolval) fprintf(output, "true\n");
1395  else fprintf(output, "false\n");
1396  break;
1397  case XPATH_NUMBER:
1398  switch (xmlXPathIsInf(cur->floatval)) {
1399  case 1:
1400  fprintf(output, "Object is a number : Infinity\n");
1401  break;
1402  case -1:
1403  fprintf(output, "Object is a number : -Infinity\n");
1404  break;
1405  default:
1406  if (xmlXPathIsNaN(cur->floatval)) {
1407  fprintf(output, "Object is a number : NaN\n");
1408  } else if (cur->floatval == 0) {
1409  /* Omit sign for negative zero. */
1410  fprintf(output, "Object is a number : 0\n");
1411  } else {
1412  fprintf(output, "Object is a number : %0g\n", cur->floatval);
1413  }
1414  }
1415  break;
1416  case XPATH_STRING:
1417  fprintf(output, "Object is a string : ");
1418  xmlDebugDumpString(output, cur->stringval);
1419  fprintf(output, "\n");
1420  break;
1421  case XPATH_POINT:
1422  fprintf(output, "Object is a point : index %d in node", cur->index);
1423  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1424  fprintf(output, "\n");
1425  break;
1426  case XPATH_RANGE:
1427  if ((cur->user2 == NULL) ||
1428  ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1429  fprintf(output, "Object is a collapsed range :\n");
1430  fprintf(output, "%s", shift);
1431  if (cur->index >= 0)
1432  fprintf(output, "index %d in ", cur->index);
1433  fprintf(output, "node\n");
1434  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1435  depth + 1);
1436  } else {
1437  fprintf(output, "Object is a range :\n");
1438  fprintf(output, "%s", shift);
1439  fprintf(output, "From ");
1440  if (cur->index >= 0)
1441  fprintf(output, "index %d in ", cur->index);
1442  fprintf(output, "node\n");
1443  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444  depth + 1);
1445  fprintf(output, "%s", shift);
1446  fprintf(output, "To ");
1447  if (cur->index2 >= 0)
1448  fprintf(output, "index %d in ", cur->index2);
1449  fprintf(output, "node\n");
1450  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1451  depth + 1);
1452  fprintf(output, "\n");
1453  }
1454  break;
1455  case XPATH_LOCATIONSET:
1456 #if defined(LIBXML_XPTR_ENABLED)
1457  fprintf(output, "Object is a Location Set:\n");
1458  xmlXPathDebugDumpLocationSet(output,
1459  (xmlLocationSetPtr) cur->user, depth);
1460 #endif
1461  break;
1462  case XPATH_USERS:
1463  fprintf(output, "Object is user defined\n");
1464  break;
1465  }
1466 }
1467 
1468 static void
1469 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1470  xmlXPathStepOpPtr op, int depth) {
1471  int i;
1472  char shift[100];
1473 
1474  for (i = 0;((i < depth) && (i < 25));i++)
1475  shift[2 * i] = shift[2 * i + 1] = ' ';
1476  shift[2 * i] = shift[2 * i + 1] = 0;
1477 
1478  fprintf(output, "%s", shift);
1479  if (op == NULL) {
1480  fprintf(output, "Step is NULL\n");
1481  return;
1482  }
1483  switch (op->op) {
1484  case XPATH_OP_END:
1485  fprintf(output, "END"); break;
1486  case XPATH_OP_AND:
1487  fprintf(output, "AND"); break;
1488  case XPATH_OP_OR:
1489  fprintf(output, "OR"); break;
1490  case XPATH_OP_EQUAL:
1491  if (op->value)
1492  fprintf(output, "EQUAL =");
1493  else
1494  fprintf(output, "EQUAL !=");
1495  break;
1496  case XPATH_OP_CMP:
1497  if (op->value)
1498  fprintf(output, "CMP <");
1499  else
1500  fprintf(output, "CMP >");
1501  if (!op->value2)
1502  fprintf(output, "=");
1503  break;
1504  case XPATH_OP_PLUS:
1505  if (op->value == 0)
1506  fprintf(output, "PLUS -");
1507  else if (op->value == 1)
1508  fprintf(output, "PLUS +");
1509  else if (op->value == 2)
1510  fprintf(output, "PLUS unary -");
1511  else if (op->value == 3)
1512  fprintf(output, "PLUS unary - -");
1513  break;
1514  case XPATH_OP_MULT:
1515  if (op->value == 0)
1516  fprintf(output, "MULT *");
1517  else if (op->value == 1)
1518  fprintf(output, "MULT div");
1519  else
1520  fprintf(output, "MULT mod");
1521  break;
1522  case XPATH_OP_UNION:
1523  fprintf(output, "UNION"); break;
1524  case XPATH_OP_ROOT:
1525  fprintf(output, "ROOT"); break;
1526  case XPATH_OP_NODE:
1527  fprintf(output, "NODE"); break;
1528  case XPATH_OP_SORT:
1529  fprintf(output, "SORT"); break;
1530  case XPATH_OP_COLLECT: {
1531  xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1532  xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1533  xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1534  const xmlChar *prefix = op->value4;
1535  const xmlChar *name = op->value5;
1536 
1537  fprintf(output, "COLLECT ");
1538  switch (axis) {
1539  case AXIS_ANCESTOR:
1540  fprintf(output, " 'ancestors' "); break;
1541  case AXIS_ANCESTOR_OR_SELF:
1542  fprintf(output, " 'ancestors-or-self' "); break;
1543  case AXIS_ATTRIBUTE:
1544  fprintf(output, " 'attributes' "); break;
1545  case AXIS_CHILD:
1546  fprintf(output, " 'child' "); break;
1547  case AXIS_DESCENDANT:
1548  fprintf(output, " 'descendant' "); break;
1549  case AXIS_DESCENDANT_OR_SELF:
1550  fprintf(output, " 'descendant-or-self' "); break;
1551  case AXIS_FOLLOWING:
1552  fprintf(output, " 'following' "); break;
1553  case AXIS_FOLLOWING_SIBLING:
1554  fprintf(output, " 'following-siblings' "); break;
1555  case AXIS_NAMESPACE:
1556  fprintf(output, " 'namespace' "); break;
1557  case AXIS_PARENT:
1558  fprintf(output, " 'parent' "); break;
1559  case AXIS_PRECEDING:
1560  fprintf(output, " 'preceding' "); break;
1561  case AXIS_PRECEDING_SIBLING:
1562  fprintf(output, " 'preceding-sibling' "); break;
1563  case AXIS_SELF:
1564  fprintf(output, " 'self' "); break;
1565  }
1566  switch (test) {
1567  case NODE_TEST_NONE:
1568  fprintf(output, "'none' "); break;
1569  case NODE_TEST_TYPE:
1570  fprintf(output, "'type' "); break;
1571  case NODE_TEST_PI:
1572  fprintf(output, "'PI' "); break;
1573  case NODE_TEST_ALL:
1574  fprintf(output, "'all' "); break;
1575  case NODE_TEST_NS:
1576  fprintf(output, "'namespace' "); break;
1577  case NODE_TEST_NAME:
1578  fprintf(output, "'name' "); break;
1579  }
1580  switch (type) {
1581  case NODE_TYPE_NODE:
1582  fprintf(output, "'node' "); break;
1583  case NODE_TYPE_COMMENT:
1584  fprintf(output, "'comment' "); break;
1585  case NODE_TYPE_TEXT:
1586  fprintf(output, "'text' "); break;
1587  case NODE_TYPE_PI:
1588  fprintf(output, "'PI' "); break;
1589  }
1590  if (prefix != NULL)
1591  fprintf(output, "%s:", prefix);
1592  if (name != NULL)
1593  fprintf(output, "%s", (const char *) name);
1594  break;
1595 
1596  }
1597  case XPATH_OP_VALUE: {
1598  xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1599 
1600  fprintf(output, "ELEM ");
1601  xmlXPathDebugDumpObject(output, object, 0);
1602  goto finish;
1603  }
1604  case XPATH_OP_VARIABLE: {
1605  const xmlChar *prefix = op->value5;
1606  const xmlChar *name = op->value4;
1607 
1608  if (prefix != NULL)
1609  fprintf(output, "VARIABLE %s:%s", prefix, name);
1610  else
1611  fprintf(output, "VARIABLE %s", name);
1612  break;
1613  }
1614  case XPATH_OP_FUNCTION: {
1615  int nbargs = op->value;
1616  const xmlChar *prefix = op->value5;
1617  const xmlChar *name = op->value4;
1618 
1619  if (prefix != NULL)
1620  fprintf(output, "FUNCTION %s:%s(%d args)",
1621  prefix, name, nbargs);
1622  else
1623  fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1624  break;
1625  }
1626  case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1627  case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1628  case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1629 #ifdef LIBXML_XPTR_ENABLED
1630  case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1631 #endif
1632  default:
1633  fprintf(output, "UNKNOWN %d\n", op->op); return;
1634  }
1635  fprintf(output, "\n");
1636 finish:
1637  if (op->ch1 >= 0)
1638  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1639  if (op->ch2 >= 0)
1640  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1641 }
1642 
1651 void
1652 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1653  int depth) {
1654  int i;
1655  char shift[100];
1656 
1657  if ((output == NULL) || (comp == NULL)) return;
1658 
1659  for (i = 0;((i < depth) && (i < 25));i++)
1660  shift[2 * i] = shift[2 * i + 1] = ' ';
1661  shift[2 * i] = shift[2 * i + 1] = 0;
1662 
1663  fprintf(output, "%s", shift);
1664 
1665 #ifdef XPATH_STREAMING
1666  if (comp->stream) {
1667  fprintf(output, "Streaming Expression\n");
1668  } else
1669 #endif
1670  {
1671  fprintf(output, "Compiled Expression : %d elements\n",
1672  comp->nbStep);
1673  i = comp->last;
1674  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1675  }
1676 }
1677 
1678 #ifdef XP_DEBUG_OBJ_USAGE
1679 
1680 /*
1681 * XPath object usage related debugging variables.
1682 */
1683 static int xmlXPathDebugObjCounterUndefined = 0;
1684 static int xmlXPathDebugObjCounterNodeset = 0;
1685 static int xmlXPathDebugObjCounterBool = 0;
1686 static int xmlXPathDebugObjCounterNumber = 0;
1687 static int xmlXPathDebugObjCounterString = 0;
1688 static int xmlXPathDebugObjCounterPoint = 0;
1689 static int xmlXPathDebugObjCounterRange = 0;
1690 static int xmlXPathDebugObjCounterLocset = 0;
1691 static int xmlXPathDebugObjCounterUsers = 0;
1692 static int xmlXPathDebugObjCounterXSLTTree = 0;
1693 static int xmlXPathDebugObjCounterAll = 0;
1694 
1695 static int xmlXPathDebugObjTotalUndefined = 0;
1696 static int xmlXPathDebugObjTotalNodeset = 0;
1697 static int xmlXPathDebugObjTotalBool = 0;
1698 static int xmlXPathDebugObjTotalNumber = 0;
1699 static int xmlXPathDebugObjTotalString = 0;
1700 static int xmlXPathDebugObjTotalPoint = 0;
1701 static int xmlXPathDebugObjTotalRange = 0;
1702 static int xmlXPathDebugObjTotalLocset = 0;
1703 static int xmlXPathDebugObjTotalUsers = 0;
1704 static int xmlXPathDebugObjTotalXSLTTree = 0;
1705 static int xmlXPathDebugObjTotalAll = 0;
1706 
1707 static int xmlXPathDebugObjMaxUndefined = 0;
1708 static int xmlXPathDebugObjMaxNodeset = 0;
1709 static int xmlXPathDebugObjMaxBool = 0;
1710 static int xmlXPathDebugObjMaxNumber = 0;
1711 static int xmlXPathDebugObjMaxString = 0;
1712 static int xmlXPathDebugObjMaxPoint = 0;
1713 static int xmlXPathDebugObjMaxRange = 0;
1714 static int xmlXPathDebugObjMaxLocset = 0;
1715 static int xmlXPathDebugObjMaxUsers = 0;
1716 static int xmlXPathDebugObjMaxXSLTTree = 0;
1717 static int xmlXPathDebugObjMaxAll = 0;
1718 
1719 /* REVISIT TODO: Make this static when committing */
1720 static void
1721 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1722 {
1723  if (ctxt != NULL) {
1724  if (ctxt->cache != NULL) {
1725  xmlXPathContextCachePtr cache =
1726  (xmlXPathContextCachePtr) ctxt->cache;
1727 
1728  cache->dbgCachedAll = 0;
1729  cache->dbgCachedNodeset = 0;
1730  cache->dbgCachedString = 0;
1731  cache->dbgCachedBool = 0;
1732  cache->dbgCachedNumber = 0;
1733  cache->dbgCachedPoint = 0;
1734  cache->dbgCachedRange = 0;
1735  cache->dbgCachedLocset = 0;
1736  cache->dbgCachedUsers = 0;
1737  cache->dbgCachedXSLTTree = 0;
1738  cache->dbgCachedUndefined = 0;
1739 
1740  cache->dbgReusedAll = 0;
1741  cache->dbgReusedNodeset = 0;
1742  cache->dbgReusedString = 0;
1743  cache->dbgReusedBool = 0;
1744  cache->dbgReusedNumber = 0;
1745  cache->dbgReusedPoint = 0;
1746  cache->dbgReusedRange = 0;
1747  cache->dbgReusedLocset = 0;
1748  cache->dbgReusedUsers = 0;
1749  cache->dbgReusedXSLTTree = 0;
1750  cache->dbgReusedUndefined = 0;
1751  }
1752  }
1753 
1754  xmlXPathDebugObjCounterUndefined = 0;
1755  xmlXPathDebugObjCounterNodeset = 0;
1756  xmlXPathDebugObjCounterBool = 0;
1757  xmlXPathDebugObjCounterNumber = 0;
1758  xmlXPathDebugObjCounterString = 0;
1759  xmlXPathDebugObjCounterPoint = 0;
1760  xmlXPathDebugObjCounterRange = 0;
1761  xmlXPathDebugObjCounterLocset = 0;
1762  xmlXPathDebugObjCounterUsers = 0;
1763  xmlXPathDebugObjCounterXSLTTree = 0;
1764  xmlXPathDebugObjCounterAll = 0;
1765 
1766  xmlXPathDebugObjTotalUndefined = 0;
1767  xmlXPathDebugObjTotalNodeset = 0;
1768  xmlXPathDebugObjTotalBool = 0;
1769  xmlXPathDebugObjTotalNumber = 0;
1770  xmlXPathDebugObjTotalString = 0;
1771  xmlXPathDebugObjTotalPoint = 0;
1772  xmlXPathDebugObjTotalRange = 0;
1773  xmlXPathDebugObjTotalLocset = 0;
1774  xmlXPathDebugObjTotalUsers = 0;
1775  xmlXPathDebugObjTotalXSLTTree = 0;
1776  xmlXPathDebugObjTotalAll = 0;
1777 
1778  xmlXPathDebugObjMaxUndefined = 0;
1779  xmlXPathDebugObjMaxNodeset = 0;
1780  xmlXPathDebugObjMaxBool = 0;
1781  xmlXPathDebugObjMaxNumber = 0;
1782  xmlXPathDebugObjMaxString = 0;
1783  xmlXPathDebugObjMaxPoint = 0;
1784  xmlXPathDebugObjMaxRange = 0;
1785  xmlXPathDebugObjMaxLocset = 0;
1786  xmlXPathDebugObjMaxUsers = 0;
1787  xmlXPathDebugObjMaxXSLTTree = 0;
1788  xmlXPathDebugObjMaxAll = 0;
1789 
1790 }
1791 
1792 static void
1793 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1794  xmlXPathObjectType objType)
1795 {
1796  int isCached = 0;
1797 
1798  if (ctxt != NULL) {
1799  if (ctxt->cache != NULL) {
1800  xmlXPathContextCachePtr cache =
1801  (xmlXPathContextCachePtr) ctxt->cache;
1802 
1803  isCached = 1;
1804 
1805  cache->dbgReusedAll++;
1806  switch (objType) {
1807  case XPATH_UNDEFINED:
1808  cache->dbgReusedUndefined++;
1809  break;
1810  case XPATH_NODESET:
1811  cache->dbgReusedNodeset++;
1812  break;
1813  case XPATH_BOOLEAN:
1814  cache->dbgReusedBool++;
1815  break;
1816  case XPATH_NUMBER:
1817  cache->dbgReusedNumber++;
1818  break;
1819  case XPATH_STRING:
1820  cache->dbgReusedString++;
1821  break;
1822  case XPATH_POINT:
1823  cache->dbgReusedPoint++;
1824  break;
1825  case XPATH_RANGE:
1826  cache->dbgReusedRange++;
1827  break;
1828  case XPATH_LOCATIONSET:
1829  cache->dbgReusedLocset++;
1830  break;
1831  case XPATH_USERS:
1832  cache->dbgReusedUsers++;
1833  break;
1834  case XPATH_XSLT_TREE:
1835  cache->dbgReusedXSLTTree++;
1836  break;
1837  default:
1838  break;
1839  }
1840  }
1841  }
1842 
1843  switch (objType) {
1844  case XPATH_UNDEFINED:
1845  if (! isCached)
1846  xmlXPathDebugObjTotalUndefined++;
1847  xmlXPathDebugObjCounterUndefined++;
1848  if (xmlXPathDebugObjCounterUndefined >
1849  xmlXPathDebugObjMaxUndefined)
1850  xmlXPathDebugObjMaxUndefined =
1851  xmlXPathDebugObjCounterUndefined;
1852  break;
1853  case XPATH_NODESET:
1854  if (! isCached)
1855  xmlXPathDebugObjTotalNodeset++;
1856  xmlXPathDebugObjCounterNodeset++;
1857  if (xmlXPathDebugObjCounterNodeset >
1858  xmlXPathDebugObjMaxNodeset)
1859  xmlXPathDebugObjMaxNodeset =
1860  xmlXPathDebugObjCounterNodeset;
1861  break;
1862  case XPATH_BOOLEAN:
1863  if (! isCached)
1864  xmlXPathDebugObjTotalBool++;
1865  xmlXPathDebugObjCounterBool++;
1866  if (xmlXPathDebugObjCounterBool >
1867  xmlXPathDebugObjMaxBool)
1868  xmlXPathDebugObjMaxBool =
1869  xmlXPathDebugObjCounterBool;
1870  break;
1871  case XPATH_NUMBER:
1872  if (! isCached)
1873  xmlXPathDebugObjTotalNumber++;
1874  xmlXPathDebugObjCounterNumber++;
1875  if (xmlXPathDebugObjCounterNumber >
1876  xmlXPathDebugObjMaxNumber)
1877  xmlXPathDebugObjMaxNumber =
1878  xmlXPathDebugObjCounterNumber;
1879  break;
1880  case XPATH_STRING:
1881  if (! isCached)
1882  xmlXPathDebugObjTotalString++;
1883  xmlXPathDebugObjCounterString++;
1884  if (xmlXPathDebugObjCounterString >
1885  xmlXPathDebugObjMaxString)
1886  xmlXPathDebugObjMaxString =
1887  xmlXPathDebugObjCounterString;
1888  break;
1889  case XPATH_POINT:
1890  if (! isCached)
1891  xmlXPathDebugObjTotalPoint++;
1892  xmlXPathDebugObjCounterPoint++;
1893  if (xmlXPathDebugObjCounterPoint >
1894  xmlXPathDebugObjMaxPoint)
1895  xmlXPathDebugObjMaxPoint =
1896  xmlXPathDebugObjCounterPoint;
1897  break;
1898  case XPATH_RANGE:
1899  if (! isCached)
1900  xmlXPathDebugObjTotalRange++;
1901  xmlXPathDebugObjCounterRange++;
1902  if (xmlXPathDebugObjCounterRange >
1903  xmlXPathDebugObjMaxRange)
1904  xmlXPathDebugObjMaxRange =
1905  xmlXPathDebugObjCounterRange;
1906  break;
1907  case XPATH_LOCATIONSET:
1908  if (! isCached)
1909  xmlXPathDebugObjTotalLocset++;
1910  xmlXPathDebugObjCounterLocset++;
1911  if (xmlXPathDebugObjCounterLocset >
1912  xmlXPathDebugObjMaxLocset)
1913  xmlXPathDebugObjMaxLocset =
1914  xmlXPathDebugObjCounterLocset;
1915  break;
1916  case XPATH_USERS:
1917  if (! isCached)
1918  xmlXPathDebugObjTotalUsers++;
1919  xmlXPathDebugObjCounterUsers++;
1920  if (xmlXPathDebugObjCounterUsers >
1921  xmlXPathDebugObjMaxUsers)
1922  xmlXPathDebugObjMaxUsers =
1923  xmlXPathDebugObjCounterUsers;
1924  break;
1925  case XPATH_XSLT_TREE:
1926  if (! isCached)
1927  xmlXPathDebugObjTotalXSLTTree++;
1928  xmlXPathDebugObjCounterXSLTTree++;
1929  if (xmlXPathDebugObjCounterXSLTTree >
1930  xmlXPathDebugObjMaxXSLTTree)
1931  xmlXPathDebugObjMaxXSLTTree =
1932  xmlXPathDebugObjCounterXSLTTree;
1933  break;
1934  default:
1935  break;
1936  }
1937  if (! isCached)
1938  xmlXPathDebugObjTotalAll++;
1939  xmlXPathDebugObjCounterAll++;
1940  if (xmlXPathDebugObjCounterAll >
1941  xmlXPathDebugObjMaxAll)
1942  xmlXPathDebugObjMaxAll =
1943  xmlXPathDebugObjCounterAll;
1944 }
1945 
1946 static void
1947 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1948  xmlXPathObjectType objType)
1949 {
1950  int isCached = 0;
1951 
1952  if (ctxt != NULL) {
1953  if (ctxt->cache != NULL) {
1954  xmlXPathContextCachePtr cache =
1955  (xmlXPathContextCachePtr) ctxt->cache;
1956 
1957  isCached = 1;
1958 
1959  cache->dbgCachedAll++;
1960  switch (objType) {
1961  case XPATH_UNDEFINED:
1962  cache->dbgCachedUndefined++;
1963  break;
1964  case XPATH_NODESET:
1965  cache->dbgCachedNodeset++;
1966  break;
1967  case XPATH_BOOLEAN:
1968  cache->dbgCachedBool++;
1969  break;
1970  case XPATH_NUMBER:
1971  cache->dbgCachedNumber++;
1972  break;
1973  case XPATH_STRING:
1974  cache->dbgCachedString++;
1975  break;
1976  case XPATH_POINT:
1977  cache->dbgCachedPoint++;
1978  break;
1979  case XPATH_RANGE:
1980  cache->dbgCachedRange++;
1981  break;
1982  case XPATH_LOCATIONSET:
1983  cache->dbgCachedLocset++;
1984  break;
1985  case XPATH_USERS:
1986  cache->dbgCachedUsers++;
1987  break;
1988  case XPATH_XSLT_TREE:
1989  cache->dbgCachedXSLTTree++;
1990  break;
1991  default:
1992  break;
1993  }
1994 
1995  }
1996  }
1997  switch (objType) {
1998  case XPATH_UNDEFINED:
1999  xmlXPathDebugObjCounterUndefined--;
2000  break;
2001  case XPATH_NODESET:
2002  xmlXPathDebugObjCounterNodeset--;
2003  break;
2004  case XPATH_BOOLEAN:
2005  xmlXPathDebugObjCounterBool--;
2006  break;
2007  case XPATH_NUMBER:
2008  xmlXPathDebugObjCounterNumber--;
2009  break;
2010  case XPATH_STRING:
2011  xmlXPathDebugObjCounterString--;
2012  break;
2013  case XPATH_POINT:
2014  xmlXPathDebugObjCounterPoint--;
2015  break;
2016  case XPATH_RANGE:
2017  xmlXPathDebugObjCounterRange--;
2018  break;
2019  case XPATH_LOCATIONSET:
2020  xmlXPathDebugObjCounterLocset--;
2021  break;
2022  case XPATH_USERS:
2023  xmlXPathDebugObjCounterUsers--;
2024  break;
2025  case XPATH_XSLT_TREE:
2026  xmlXPathDebugObjCounterXSLTTree--;
2027  break;
2028  default:
2029  break;
2030  }
2031  xmlXPathDebugObjCounterAll--;
2032 }
2033 
2034 /* REVISIT TODO: Make this static when committing */
2035 static void
2036 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2037 {
2038  int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2039  reqXSLTTree, reqUndefined;
2040  int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2041  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2042  int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2043  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2044  int leftObjs = xmlXPathDebugObjCounterAll;
2045 
2046  reqAll = xmlXPathDebugObjTotalAll;
2047  reqNodeset = xmlXPathDebugObjTotalNodeset;
2048  reqString = xmlXPathDebugObjTotalString;
2049  reqBool = xmlXPathDebugObjTotalBool;
2050  reqNumber = xmlXPathDebugObjTotalNumber;
2051  reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2052  reqUndefined = xmlXPathDebugObjTotalUndefined;
2053 
2054  printf("# XPath object usage:\n");
2055 
2056  if (ctxt != NULL) {
2057  if (ctxt->cache != NULL) {
2058  xmlXPathContextCachePtr cache =
2059  (xmlXPathContextCachePtr) ctxt->cache;
2060 
2061  reAll = cache->dbgReusedAll;
2062  reqAll += reAll;
2063  reNodeset = cache->dbgReusedNodeset;
2064  reqNodeset += reNodeset;
2065  reString = cache->dbgReusedString;
2066  reqString += reString;
2067  reBool = cache->dbgReusedBool;
2068  reqBool += reBool;
2069  reNumber = cache->dbgReusedNumber;
2070  reqNumber += reNumber;
2071  reXSLTTree = cache->dbgReusedXSLTTree;
2072  reqXSLTTree += reXSLTTree;
2073  reUndefined = cache->dbgReusedUndefined;
2074  reqUndefined += reUndefined;
2075 
2076  caAll = cache->dbgCachedAll;
2077  caBool = cache->dbgCachedBool;
2078  caNodeset = cache->dbgCachedNodeset;
2079  caString = cache->dbgCachedString;
2080  caNumber = cache->dbgCachedNumber;
2081  caXSLTTree = cache->dbgCachedXSLTTree;
2082  caUndefined = cache->dbgCachedUndefined;
2083 
2084  if (cache->nodesetObjs)
2085  leftObjs -= cache->nodesetObjs->number;
2086  if (cache->stringObjs)
2087  leftObjs -= cache->stringObjs->number;
2088  if (cache->booleanObjs)
2089  leftObjs -= cache->booleanObjs->number;
2090  if (cache->numberObjs)
2091  leftObjs -= cache->numberObjs->number;
2092  if (cache->miscObjs)
2093  leftObjs -= cache->miscObjs->number;
2094  }
2095  }
2096 
2097  printf("# all\n");
2098  printf("# total : %d\n", reqAll);
2099  printf("# left : %d\n", leftObjs);
2100  printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2101  printf("# reused : %d\n", reAll);
2102  printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2103 
2104  printf("# node-sets\n");
2105  printf("# total : %d\n", reqNodeset);
2106  printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2107  printf("# reused : %d\n", reNodeset);
2108  printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2109 
2110  printf("# strings\n");
2111  printf("# total : %d\n", reqString);
2112  printf("# created: %d\n", xmlXPathDebugObjTotalString);
2113  printf("# reused : %d\n", reString);
2114  printf("# max : %d\n", xmlXPathDebugObjMaxString);
2115 
2116  printf("# booleans\n");
2117  printf("# total : %d\n", reqBool);
2118  printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2119  printf("# reused : %d\n", reBool);
2120  printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2121 
2122  printf("# numbers\n");
2123  printf("# total : %d\n", reqNumber);
2124  printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2125  printf("# reused : %d\n", reNumber);
2126  printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2127 
2128  printf("# XSLT result tree fragments\n");
2129  printf("# total : %d\n", reqXSLTTree);
2130  printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2131  printf("# reused : %d\n", reXSLTTree);
2132  printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2133 
2134  printf("# undefined\n");
2135  printf("# total : %d\n", reqUndefined);
2136  printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2137  printf("# reused : %d\n", reUndefined);
2138  printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2139 
2140 }
2141 
2142 #endif /* XP_DEBUG_OBJ_USAGE */
2143 
2144 #endif /* LIBXML_DEBUG_ENABLED */
2145 
2146 /************************************************************************
2147  * *
2148  * XPath object caching *
2149  * *
2150  ************************************************************************/
2151 
2159 static xmlXPathContextCachePtr
2160 xmlXPathNewCache(void)
2161 {
2162  xmlXPathContextCachePtr ret;
2163 
2164  ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2165  if (ret == NULL) {
2166  xmlXPathErrMemory(NULL, "creating object cache\n");
2167  return(NULL);
2168  }
2169  memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2170  ret->maxNodeset = 100;
2171  ret->maxString = 100;
2172  ret->maxBoolean = 100;
2173  ret->maxNumber = 100;
2174  ret->maxMisc = 100;
2175  return(ret);
2176 }
2177 
2178 static void
2179 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2180 {
2181  int i;
2182  xmlXPathObjectPtr obj;
2183 
2184  if (list == NULL)
2185  return;
2186 
2187  for (i = 0; i < list->number; i++) {
2188  obj = list->items[i];
2189  /*
2190  * Note that it is already assured that we don't need to
2191  * look out for namespace nodes in the node-set.
2192  */
2193  if (obj->nodesetval != NULL) {
2194  if (obj->nodesetval->nodeTab != NULL)
2195  xmlFree(obj->nodesetval->nodeTab);
2196  xmlFree(obj->nodesetval);
2197  }
2198  xmlFree(obj);
2199 #ifdef XP_DEBUG_OBJ_USAGE
2200  xmlXPathDebugObjCounterAll--;
2201 #endif
2202  }
2203  xmlPointerListFree(list);
2204 }
2205 
2206 static void
2207 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2208 {
2209  if (cache == NULL)
2210  return;
2211  if (cache->nodesetObjs)
2212  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2213  if (cache->stringObjs)
2214  xmlXPathCacheFreeObjectList(cache->stringObjs);
2215  if (cache->booleanObjs)
2216  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2217  if (cache->numberObjs)
2218  xmlXPathCacheFreeObjectList(cache->numberObjs);
2219  if (cache->miscObjs)
2220  xmlXPathCacheFreeObjectList(cache->miscObjs);
2221  xmlFree(cache);
2222 }
2223 
2246 int
2247 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2248  int active,
2249  int value,
2250  int options)
2251 {
2252  if (ctxt == NULL)
2253  return(-1);
2254  if (active) {
2255  xmlXPathContextCachePtr cache;
2256 
2257  if (ctxt->cache == NULL) {
2258  ctxt->cache = xmlXPathNewCache();
2259  if (ctxt->cache == NULL)
2260  return(-1);
2261  }
2262  cache = (xmlXPathContextCachePtr) ctxt->cache;
2263  if (options == 0) {
2264  if (value < 0)
2265  value = 100;
2266  cache->maxNodeset = value;
2267  cache->maxString = value;
2268  cache->maxNumber = value;
2269  cache->maxBoolean = value;
2270  cache->maxMisc = value;
2271  }
2272  } else if (ctxt->cache != NULL) {
2273  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2274  ctxt->cache = NULL;
2275  }
2276  return(0);
2277 }
2278 
2289 static xmlXPathObjectPtr
2290 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2291 {
2292  if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2293  xmlXPathContextCachePtr cache =
2294  (xmlXPathContextCachePtr) ctxt->cache;
2295 
2296  if ((cache->miscObjs != NULL) &&
2297  (cache->miscObjs->number != 0))
2298  {
2299  xmlXPathObjectPtr ret;
2300 
2301  ret = (xmlXPathObjectPtr)
2302  cache->miscObjs->items[--cache->miscObjs->number];
2303  ret->type = XPATH_NODESET;
2304  ret->nodesetval = val;
2305 #ifdef XP_DEBUG_OBJ_USAGE
2306  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2307 #endif
2308  return(ret);
2309  }
2310  }
2311 
2312  return(xmlXPathWrapNodeSet(val));
2313 
2314 }
2315 
2326 static xmlXPathObjectPtr
2327 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2328 {
2329  if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2330  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2331 
2332  if ((cache->stringObjs != NULL) &&
2333  (cache->stringObjs->number != 0))
2334  {
2335 
2336  xmlXPathObjectPtr ret;
2337 
2338  ret = (xmlXPathObjectPtr)
2339  cache->stringObjs->items[--cache->stringObjs->number];
2340  ret->type = XPATH_STRING;
2341  ret->stringval = val;
2342 #ifdef XP_DEBUG_OBJ_USAGE
2343  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2344 #endif
2345  return(ret);
2346  } else if ((cache->miscObjs != NULL) &&
2347  (cache->miscObjs->number != 0))
2348  {
2349  xmlXPathObjectPtr ret;
2350  /*
2351  * Fallback to misc-cache.
2352  */
2353  ret = (xmlXPathObjectPtr)
2354  cache->miscObjs->items[--cache->miscObjs->number];
2355 
2356  ret->type = XPATH_STRING;
2357  ret->stringval = val;
2358 #ifdef XP_DEBUG_OBJ_USAGE
2359  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2360 #endif
2361  return(ret);
2362  }
2363  }
2364  return(xmlXPathWrapString(val));
2365 }
2366 
2378 static xmlXPathObjectPtr
2379 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2380 {
2381  if ((ctxt != NULL) && (ctxt->cache)) {
2382  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2383 
2384  if ((cache->nodesetObjs != NULL) &&
2385  (cache->nodesetObjs->number != 0))
2386  {
2387  xmlXPathObjectPtr ret;
2388  /*
2389  * Use the nodset-cache.
2390  */
2391  ret = (xmlXPathObjectPtr)
2392  cache->nodesetObjs->items[--cache->nodesetObjs->number];
2393  ret->type = XPATH_NODESET;
2394  ret->boolval = 0;
2395  if (val) {
2396  if ((ret->nodesetval->nodeMax == 0) ||
2397  (val->type == XML_NAMESPACE_DECL))
2398  {
2399  xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2400  } else {
2401  ret->nodesetval->nodeTab[0] = val;
2402  ret->nodesetval->nodeNr = 1;
2403  }
2404  }
2405 #ifdef XP_DEBUG_OBJ_USAGE
2406  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2407 #endif
2408  return(ret);
2409  } else if ((cache->miscObjs != NULL) &&
2410  (cache->miscObjs->number != 0))
2411  {
2412  xmlXPathObjectPtr ret;
2413  /*
2414  * Fallback to misc-cache.
2415  */
2416 
2417  ret = (xmlXPathObjectPtr)
2418  cache->miscObjs->items[--cache->miscObjs->number];
2419 
2420  ret->type = XPATH_NODESET;
2421  ret->boolval = 0;
2422  ret->nodesetval = xmlXPathNodeSetCreate(val);
2423  if (ret->nodesetval == NULL) {
2424  ctxt->lastError.domain = XML_FROM_XPATH;
2425  ctxt->lastError.code = XML_ERR_NO_MEMORY;
2426  return(NULL);
2427  }
2428 #ifdef XP_DEBUG_OBJ_USAGE
2429  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2430 #endif
2431  return(ret);
2432  }
2433  }
2434  return(xmlXPathNewNodeSet(val));
2435 }
2436 
2447 static xmlXPathObjectPtr
2448 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2449 {
2450  if ((ctxt != NULL) && (ctxt->cache)) {
2451  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2452 
2453  if ((cache->stringObjs != NULL) &&
2454  (cache->stringObjs->number != 0))
2455  {
2456  xmlXPathObjectPtr ret;
2457 
2458  ret = (xmlXPathObjectPtr)
2459  cache->stringObjs->items[--cache->stringObjs->number];
2460 
2461  ret->type = XPATH_STRING;
2462  ret->stringval = xmlStrdup(BAD_CAST val);
2463 #ifdef XP_DEBUG_OBJ_USAGE
2464  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2465 #endif
2466  return(ret);
2467  } else if ((cache->miscObjs != NULL) &&
2468  (cache->miscObjs->number != 0))
2469  {
2470  xmlXPathObjectPtr ret;
2471 
2472  ret = (xmlXPathObjectPtr)
2473  cache->miscObjs->items[--cache->miscObjs->number];
2474 
2475  ret->type = XPATH_STRING;
2476  ret->stringval = xmlStrdup(BAD_CAST val);
2477 #ifdef XP_DEBUG_OBJ_USAGE
2478  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2479 #endif
2480  return(ret);
2481  }
2482  }
2483  return(xmlXPathNewCString(val));
2484 }
2485 
2496 static xmlXPathObjectPtr
2497 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2498 {
2499  if ((ctxt != NULL) && (ctxt->cache)) {
2500  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2501 
2502  if ((cache->stringObjs != NULL) &&
2503  (cache->stringObjs->number != 0))
2504  {
2505  xmlXPathObjectPtr ret;
2506 
2507  ret = (xmlXPathObjectPtr)
2508  cache->stringObjs->items[--cache->stringObjs->number];
2509  ret->type = XPATH_STRING;
2510  if (val != NULL)
2511  ret->stringval = xmlStrdup(val);
2512  else
2513  ret->stringval = xmlStrdup((const xmlChar *)"");
2514 #ifdef XP_DEBUG_OBJ_USAGE
2515  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516 #endif
2517  return(ret);
2518  } else if ((cache->miscObjs != NULL) &&
2519  (cache->miscObjs->number != 0))
2520  {
2521  xmlXPathObjectPtr ret;
2522 
2523  ret = (xmlXPathObjectPtr)
2524  cache->miscObjs->items[--cache->miscObjs->number];
2525 
2526  ret->type = XPATH_STRING;
2527  if (val != NULL)
2528  ret->stringval = xmlStrdup(val);
2529  else
2530  ret->stringval = xmlStrdup((const xmlChar *)"");
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533 #endif
2534  return(ret);
2535  }
2536  }
2537  return(xmlXPathNewString(val));
2538 }
2539 
2550 static xmlXPathObjectPtr
2551 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2552 {
2553  if ((ctxt != NULL) && (ctxt->cache)) {
2554  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2555 
2556  if ((cache->booleanObjs != NULL) &&
2557  (cache->booleanObjs->number != 0))
2558  {
2559  xmlXPathObjectPtr ret;
2560 
2561  ret = (xmlXPathObjectPtr)
2562  cache->booleanObjs->items[--cache->booleanObjs->number];
2563  ret->type = XPATH_BOOLEAN;
2564  ret->boolval = (val != 0);
2565 #ifdef XP_DEBUG_OBJ_USAGE
2566  xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2567 #endif
2568  return(ret);
2569  } else if ((cache->miscObjs != NULL) &&
2570  (cache->miscObjs->number != 0))
2571  {
2572  xmlXPathObjectPtr ret;
2573 
2574  ret = (xmlXPathObjectPtr)
2575  cache->miscObjs->items[--cache->miscObjs->number];
2576 
2577  ret->type = XPATH_BOOLEAN;
2578  ret->boolval = (val != 0);
2579 #ifdef XP_DEBUG_OBJ_USAGE
2580  xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2581 #endif
2582  return(ret);
2583  }
2584  }
2585  return(xmlXPathNewBoolean(val));
2586 }
2587 
2598 static xmlXPathObjectPtr
2599 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2600 {
2601  if ((ctxt != NULL) && (ctxt->cache)) {
2602  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2603 
2604  if ((cache->numberObjs != NULL) &&
2605  (cache->numberObjs->number != 0))
2606  {
2607  xmlXPathObjectPtr ret;
2608 
2609  ret = (xmlXPathObjectPtr)
2610  cache->numberObjs->items[--cache->numberObjs->number];
2611  ret->type = XPATH_NUMBER;
2612  ret->floatval = val;
2613 #ifdef XP_DEBUG_OBJ_USAGE
2614  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2615 #endif
2616  return(ret);
2617  } else if ((cache->miscObjs != NULL) &&
2618  (cache->miscObjs->number != 0))
2619  {
2620  xmlXPathObjectPtr ret;
2621 
2622  ret = (xmlXPathObjectPtr)
2623  cache->miscObjs->items[--cache->miscObjs->number];
2624 
2625  ret->type = XPATH_NUMBER;
2626  ret->floatval = val;
2627 #ifdef XP_DEBUG_OBJ_USAGE
2628  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2629 #endif
2630  return(ret);
2631  }
2632  }
2633  return(xmlXPathNewFloat(val));
2634 }
2635 
2648 static xmlXPathObjectPtr
2649 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2650  xmlChar *res = NULL;
2651 
2652  if (val == NULL)
2653  return(xmlXPathCacheNewCString(ctxt, ""));
2654 
2655  switch (val->type) {
2656  case XPATH_UNDEFINED:
2657 #ifdef DEBUG_EXPR
2658  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2659 #endif
2660  break;
2661  case XPATH_NODESET:
2662  case XPATH_XSLT_TREE:
2663  res = xmlXPathCastNodeSetToString(val->nodesetval);
2664  break;
2665  case XPATH_STRING:
2666  return(val);
2667  case XPATH_BOOLEAN:
2668  res = xmlXPathCastBooleanToString(val->boolval);
2669  break;
2670  case XPATH_NUMBER:
2671  res = xmlXPathCastNumberToString(val->floatval);
2672  break;
2673  case XPATH_USERS:
2674  case XPATH_POINT:
2675  case XPATH_RANGE:
2676  case XPATH_LOCATIONSET:
2677  TODO;
2678  break;
2679  }
2680  xmlXPathReleaseObject(ctxt, val);
2681  if (res == NULL)
2682  return(xmlXPathCacheNewCString(ctxt, ""));
2683  return(xmlXPathCacheWrapString(ctxt, res));
2684 }
2685 
2696 static xmlXPathObjectPtr
2697 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2698 {
2699  if (val == NULL)
2700  return(NULL);
2701 
2702  if (XP_HAS_CACHE(ctxt)) {
2703  switch (val->type) {
2704  case XPATH_NODESET:
2705  return(xmlXPathCacheWrapNodeSet(ctxt,
2706  xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2707  case XPATH_STRING:
2708  return(xmlXPathCacheNewString(ctxt, val->stringval));
2709  case XPATH_BOOLEAN:
2710  return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2711  case XPATH_NUMBER:
2712  return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2713  default:
2714  break;
2715  }
2716  }
2717  return(xmlXPathObjectCopy(val));
2718 }
2719 
2731 static xmlXPathObjectPtr
2732 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2733  xmlXPathObjectPtr ret;
2734 
2735  if (val == NULL)
2736  return(xmlXPathCacheNewBoolean(ctxt, 0));
2737  if (val->type == XPATH_BOOLEAN)
2738  return(val);
2739  ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2740  xmlXPathReleaseObject(ctxt, val);
2741  return(ret);
2742 }
2743 
2755 static xmlXPathObjectPtr
2756 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2757  xmlXPathObjectPtr ret;
2758 
2759  if (val == NULL)
2760  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2761  if (val->type == XPATH_NUMBER)
2762  return(val);
2763  ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2764  xmlXPathReleaseObject(ctxt, val);
2765  return(ret);
2766 }
2767 
2768 /************************************************************************
2769  * *
2770  * Parser stacks related functions and macros *
2771  * *
2772  ************************************************************************/
2773 
2782 static int
2783 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2784  int ret;
2785 
2786  if (ctxt == NULL)
2787  return(0);
2788  ret = ctxt->valueFrame;
2789  ctxt->valueFrame = ctxt->valueNr;
2790  return(ret);
2791 }
2792 
2800 static void
2801 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2802  if (ctxt == NULL)
2803  return;
2804  if (ctxt->valueNr < ctxt->valueFrame) {
2805  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2806  }
2807  ctxt->valueFrame = frame;
2808 }
2809 
2818 xmlXPathObjectPtr
2819 valuePop(xmlXPathParserContextPtr ctxt)
2820 {
2821  xmlXPathObjectPtr ret;
2822 
2823  if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2824  return (NULL);
2825 
2826  if (ctxt->valueNr <= ctxt->valueFrame) {
2827  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2828  return (NULL);
2829  }
2830 
2831  ctxt->valueNr--;
2832  if (ctxt->valueNr > 0)
2833  ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834  else
2835  ctxt->value = NULL;
2836  ret = ctxt->valueTab[ctxt->valueNr];
2837  ctxt->valueTab[ctxt->valueNr] = NULL;
2838  return (ret);
2839 }
2849 int
2850 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2851 {
2852  if ((ctxt == NULL) || (value == NULL)) return(-1);
2853  if (ctxt->valueNr >= ctxt->valueMax) {
2854  xmlXPathObjectPtr *tmp;
2855 
2856  if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2857  xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2858  ctxt->error = XPATH_MEMORY_ERROR;
2859  return (0);
2860  }
2861  tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2862  2 * ctxt->valueMax *
2863  sizeof(ctxt->valueTab[0]));
2864  if (tmp == NULL) {
2865  xmlXPathErrMemory(NULL, "pushing value\n");
2866  ctxt->error = XPATH_MEMORY_ERROR;
2867  return (0);
2868  }
2869  ctxt->valueMax *= 2;
2870  ctxt->valueTab = tmp;
2871  }
2872  ctxt->valueTab[ctxt->valueNr] = value;
2873  ctxt->value = value;
2874  return (ctxt->valueNr++);
2875 }
2876 
2886 int
2887 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2888  xmlXPathObjectPtr obj;
2889  int ret;
2890 
2891  obj = valuePop(ctxt);
2892  if (obj == NULL) {
2893  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2894  return(0);
2895  }
2896  if (obj->type != XPATH_BOOLEAN)
2897  ret = xmlXPathCastToBoolean(obj);
2898  else
2899  ret = obj->boolval;
2900  xmlXPathReleaseObject(ctxt->context, obj);
2901  return(ret);
2902 }
2903 
2913 double
2914 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2915  xmlXPathObjectPtr obj;
2916  double ret;
2917 
2918  obj = valuePop(ctxt);
2919  if (obj == NULL) {
2920  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2921  return(0);
2922  }
2923  if (obj->type != XPATH_NUMBER)
2924  ret = xmlXPathCastToNumber(obj);
2925  else
2926  ret = obj->floatval;
2927  xmlXPathReleaseObject(ctxt->context, obj);
2928  return(ret);
2929 }
2930 
2940 xmlChar *
2941 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2942  xmlXPathObjectPtr obj;
2943  xmlChar * ret;
2944 
2945  obj = valuePop(ctxt);
2946  if (obj == NULL) {
2947  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2948  return(NULL);
2949  }
2950  ret = xmlXPathCastToString(obj); /* this does required strdup */
2951  /* TODO: needs refactoring somewhere else */
2952  if (obj->stringval == ret)
2953  obj->stringval = NULL;
2954  xmlXPathReleaseObject(ctxt->context, obj);
2955  return(ret);
2956 }
2957 
2967 xmlNodeSetPtr
2968 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2969  xmlXPathObjectPtr obj;
2970  xmlNodeSetPtr ret;
2971 
2972  if (ctxt == NULL) return(NULL);
2973  if (ctxt->value == NULL) {
2974  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2975  return(NULL);
2976  }
2977  if (!xmlXPathStackIsNodeSet(ctxt)) {
2978  xmlXPathSetTypeError(ctxt);
2979  return(NULL);
2980  }
2981  obj = valuePop(ctxt);
2982  ret = obj->nodesetval;
2983 #if 0
2984  /* to fix memory leak of not clearing obj->user */
2985  if (obj->boolval && obj->user != NULL)
2986  xmlFreeNodeList((xmlNodePtr) obj->user);
2987 #endif
2988  obj->nodesetval = NULL;
2989  xmlXPathReleaseObject(ctxt->context, obj);
2990  return(ret);
2991 }
2992 
3002 void *
3003 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3004  xmlXPathObjectPtr obj;
3005  void * ret;
3006 
3007  if ((ctxt == NULL) || (ctxt->value == NULL)) {
3008  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3009  return(NULL);
3010  }
3011  if (ctxt->value->type != XPATH_USERS) {
3012  xmlXPathSetTypeError(ctxt);
3013  return(NULL);
3014  }
3015  obj = valuePop(ctxt);
3016  ret = obj->user;
3017  obj->user = NULL;
3018  xmlXPathReleaseObject(ctxt->context, obj);
3019  return(ret);
3020 }
3021 
3022 /*
3023  * Macros for accessing the content. Those should be used only by the parser,
3024  * and not exported.
3025  *
3026  * Dirty macros, i.e. one need to make assumption on the context to use them
3027  *
3028  * CUR_PTR return the current pointer to the xmlChar to be parsed.
3029  * CUR returns the current xmlChar value, i.e. a 8 bit value
3030  * in ISO-Latin or UTF-8.
3031  * This should be used internally by the parser
3032  * only to compare to ASCII values otherwise it would break when
3033  * running with UTF-8 encoding.
3034  * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3035  * to compare on ASCII based substring.
3036  * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3037  * strings within the parser.
3038  * CURRENT Returns the current char value, with the full decoding of
3039  * UTF-8 if we are using this mode. It returns an int.
3040  * NEXT Skip to the next character, this does the proper decoding
3041  * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3042  * It returns the pointer to the current xmlChar.
3043  */
3044 
3045 #define CUR (*ctxt->cur)
3046 #define SKIP(val) ctxt->cur += (val)
3047 #define NXT(val) ctxt->cur[(val)]
3048 #define CUR_PTR ctxt->cur
3049 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3050 
3051 #define COPY_BUF(l,b,i,v) \
3052  if (l == 1) b[i++] = (xmlChar) v; \
3053  else i += xmlCopyChar(l,&b[i],v)
3054 
3055 #define NEXTL(l) ctxt->cur += l
3056 
3057 #define SKIP_BLANKS \
3058  while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3059 
3060 #define CURRENT (*ctxt->cur)
3061 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3062 
3063 
3064 #ifndef DBL_DIG
3065 #define DBL_DIG 16
3066 #endif
3067 #ifndef DBL_EPSILON
3068 #define DBL_EPSILON 1E-9
3069 #endif
3070 
3071 #define UPPER_DOUBLE 1E9
3072 #define LOWER_DOUBLE 1E-5
3073 #define LOWER_DOUBLE_EXP 5
3074 
3075 #define INTEGER_DIGITS DBL_DIG
3076 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3077 #define EXPONENT_DIGITS (3 + 2)
3078 
3087 static void
3088 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3089 {
3090  switch (xmlXPathIsInf(number)) {
3091  case 1:
3092  if (buffersize > (int)sizeof("Infinity"))
3093  snprintf(buffer, buffersize, "Infinity");
3094  break;
3095  case -1:
3096  if (buffersize > (int)sizeof("-Infinity"))
3097  snprintf(buffer, buffersize, "-Infinity");
3098  break;
3099  default:
3100  if (xmlXPathIsNaN(number)) {
3101  if (buffersize > (int)sizeof("NaN"))
3102  snprintf(buffer, buffersize, "NaN");
3103  } else if (number == 0) {
3104  /* Omit sign for negative zero. */
3105  snprintf(buffer, buffersize, "0");
3106  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3107  (number == (int) number)) {
3108  char work[30];
3109  char *ptr, *cur;
3110  int value = (int) number;
3111 
3112  ptr = &buffer[0];
3113  if (value == 0) {
3114  *ptr++ = '0';
3115  } else {
3116  snprintf(work, 29, "%d", value);
3117  cur = &work[0];
3118  while ((*cur) && (ptr - buffer < buffersize)) {
3119  *ptr++ = *cur++;
3120  }
3121  }
3122  if (ptr - buffer < buffersize) {
3123  *ptr = 0;
3124  } else if (buffersize > 0) {
3125  ptr--;
3126  *ptr = 0;
3127  }
3128  } else {
3129  /*
3130  For the dimension of work,
3131  DBL_DIG is number of significant digits
3132  EXPONENT is only needed for "scientific notation"
3133  3 is sign, decimal point, and terminating zero
3134  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3135  Note that this dimension is slightly (a few characters)
3136  larger than actually necessary.
3137  */
3138  char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3139  int integer_place, fraction_place;
3140  char *ptr;
3141  char *after_fraction;
3142  double absolute_value;
3143  int size;
3144 
3145  absolute_value = fabs(number);
3146 
3147  /*
3148  * First choose format - scientific or regular floating point.
3149  * In either case, result is in work, and after_fraction points
3150  * just past the fractional part.
3151  */
3152  if ( ((absolute_value > UPPER_DOUBLE) ||
3153  (absolute_value < LOWER_DOUBLE)) &&
3154  (absolute_value != 0.0) ) {
3155  /* Use scientific notation */
3156  integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3157  fraction_place = DBL_DIG - 1;
3158  size = snprintf(work, sizeof(work),"%*.*e",
3159  integer_place, fraction_place, number);
3160  while ((size > 0) && (work[size] != 'e')) size--;
3161 
3162  }
3163  else {
3164  /* Use regular notation */
3165  if (absolute_value > 0.0) {
3166  integer_place = (int)log10(absolute_value);
3167  if (integer_place > 0)
3168  fraction_place = DBL_DIG - integer_place - 1;
3169  else
3170  fraction_place = DBL_DIG - integer_place;
3171  } else {
3172  fraction_place = 1;
3173  }
3174  size = snprintf(work, sizeof(work), "%0.*f",
3175  fraction_place, number);
3176  }
3177 
3178  /* Remove leading spaces sometimes inserted by snprintf */
3179  while (work[0] == ' ') {
3180  for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3181  size--;
3182  }
3183 
3184  /* Remove fractional trailing zeroes */
3185  after_fraction = work + size;
3186  ptr = after_fraction;
3187  while (*(--ptr) == '0')
3188  ;
3189  if (*ptr != '.')
3190  ptr++;
3191  while ((*ptr++ = *after_fraction++) != 0);
3192 
3193  /* Finally copy result back to caller */
3194  size = strlen(work) + 1;
3195  if (size > buffersize) {
3196  work[buffersize - 1] = 0;
3197  size = buffersize;
3198  }
3199  memmove(buffer, work, size);
3200  }
3201  break;
3202  }
3203 }
3204 
3205 
3206 /************************************************************************
3207  * *
3208  * Routines to handle NodeSets *
3209  * *
3210  ************************************************************************/
3211 
3225 long
3226 xmlXPathOrderDocElems(xmlDocPtr doc) {
3227  ptrdiff_t count = 0;
3228  xmlNodePtr cur;
3229 
3230  if (doc == NULL)
3231  return(-1);
3232  cur = doc->children;
3233  while (cur != NULL) {
3234  if (cur->type == XML_ELEMENT_NODE) {
3235  cur->content = (void *) (-(++count));
3236  if (cur->children != NULL) {
3237  cur = cur->children;
3238  continue;
3239  }
3240  }
3241  if (cur->next != NULL) {
3242  cur = cur->next;
3243  continue;
3244  }
3245  do {
3246  cur = cur->parent;
3247  if (cur == NULL)
3248  break;
3249  if (cur == (xmlNodePtr) doc) {
3250  cur = NULL;
3251  break;
3252  }
3253  if (cur->next != NULL) {
3254  cur = cur->next;
3255  break;
3256  }
3257  } while (cur != NULL);
3258  }
3259  return((long) count);
3260 }
3261 
3272 int
3273 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3274  int depth1, depth2;
3275  int attr1 = 0, attr2 = 0;
3276  xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3277  xmlNodePtr cur, root;
3278 
3279  if ((node1 == NULL) || (node2 == NULL))
3280  return(-2);
3281  /*
3282  * a couple of optimizations which will avoid computations in most cases
3283  */
3284  if (node1 == node2) /* trivial case */
3285  return(0);
3286  if (node1->type == XML_ATTRIBUTE_NODE) {
3287  attr1 = 1;
3288  attrNode1 = node1;
3289  node1 = node1->parent;
3290  }
3291  if (node2->type == XML_ATTRIBUTE_NODE) {
3292  attr2 = 1;
3293  attrNode2 = node2;
3294  node2 = node2->parent;
3295  }
3296  if (node1 == node2) {
3297  if (attr1 == attr2) {
3298  /* not required, but we keep attributes in order */
3299  if (attr1 != 0) {
3300  cur = attrNode2->prev;
3301  while (cur != NULL) {
3302  if (cur == attrNode1)
3303  return (1);
3304  cur = cur->prev;
3305  }
3306  return (-1);
3307  }
3308  return(0);
3309  }
3310  if (attr2 == 1)
3311  return(1);
3312  return(-1);
3313  }
3314  if ((node1->type == XML_NAMESPACE_DECL) ||
3315  (node2->type == XML_NAMESPACE_DECL))
3316  return(1);
3317  if (node1 == node2->prev)
3318  return(1);
3319  if (node1 == node2->next)
3320  return(-1);
3321 
3322  /*
3323  * Speedup using document order if availble.
3324  */
3325  if ((node1->type == XML_ELEMENT_NODE) &&
3326  (node2->type == XML_ELEMENT_NODE) &&
3327  (0 > (ptrdiff_t) node1->content) &&
3328  (0 > (ptrdiff_t) node2->content) &&
3329  (node1->doc == node2->doc)) {
3330  ptrdiff_t l1, l2;
3331 
3332  l1 = -((ptrdiff_t) node1->content);
3333  l2 = -((ptrdiff_t) node2->content);
3334  if (l1 < l2)
3335  return(1);
3336  if (l1 > l2)
3337  return(-1);
3338  }
3339 
3340  /*
3341  * compute depth to root
3342  */
3343  for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3344  if (cur->parent == node1)
3345  return(1);
3346  depth2++;
3347  }
3348  root = cur;
3349  for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3350  if (cur->parent == node2)
3351  return(-1);
3352  depth1++;
3353  }
3354  /*
3355  * Distinct document (or distinct entities :-( ) case.
3356  */
3357  if (root != cur) {
3358  return(-2);
3359  }
3360  /*
3361  * get the nearest common ancestor.
3362  */
3363  while (depth1 > depth2) {
3364  depth1--;
3365  node1 = node1->parent;
3366  }
3367  while (depth2 > depth1) {
3368  depth2--;
3369  node2 = node2->parent;
3370  }
3371  while (node1->parent != node2->parent) {
3372  node1 = node1->parent;
3373  node2 = node2->parent;
3374  /* should not happen but just in case ... */
3375  if ((node1 == NULL) || (node2 == NULL))
3376  return(-2);
3377  }
3378  /*
3379  * Find who's first.
3380  */
3381  if (node1 == node2->prev)
3382  return(1);
3383  if (node1 == node2->next)
3384  return(-1);
3385  /*
3386  * Speedup using document order if availble.
3387  */
3388  if ((node1->type == XML_ELEMENT_NODE) &&
3389  (node2->type == XML_ELEMENT_NODE) &&
3390  (0 > (ptrdiff_t) node1->content) &&
3391  (0 > (ptrdiff_t) node2->content) &&
3392  (node1->doc == node2->doc)) {
3393  ptrdiff_t l1, l2;
3394 
3395  l1 = -((ptrdiff_t) node1->content);
3396  l2 = -((ptrdiff_t) node2->content);
3397  if (l1 < l2)
3398  return(1);
3399  if (l1 > l2)
3400  return(-1);
3401  }
3402 
3403  for (cur = node1->next;cur != NULL;cur = cur->next)
3404  if (cur == node2)
3405  return(1);
3406  return(-1); /* assume there is no sibling list corruption */
3407 }
3408 
3415 void
3416 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3417 #ifndef WITH_TIM_SORT
3418  int i, j, incr, len;
3419  xmlNodePtr tmp;
3420 #endif
3421 
3422  if (set == NULL)
3423  return;
3424 
3425 #ifndef WITH_TIM_SORT
3426  /*
3427  * Use the old Shell's sort implementation to sort the node-set
3428  * Timsort ought to be quite faster
3429  */
3430  len = set->nodeNr;
3431  for (incr = len / 2; incr > 0; incr /= 2) {
3432  for (i = incr; i < len; i++) {
3433  j = i - incr;
3434  while (j >= 0) {
3435 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3436  if (xmlXPathCmpNodesExt(set->nodeTab[j],
3437  set->nodeTab[j + incr]) == -1)
3438 #else
3439  if (xmlXPathCmpNodes(set->nodeTab[j],
3440  set->nodeTab[j + incr]) == -1)
3441 #endif
3442  {
3443  tmp = set->nodeTab[j];
3444  set->nodeTab[j] = set->nodeTab[j + incr];
3445  set->nodeTab[j + incr] = tmp;
3446  j -= incr;
3447  } else
3448  break;
3449  }
3450  }
3451  }
3452 #else /* WITH_TIM_SORT */
3453  libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3454 #endif /* WITH_TIM_SORT */
3455 }
3456 
3457 #define XML_NODESET_DEFAULT 10
3458 
3469 static xmlNodePtr
3470 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3471  xmlNsPtr cur;
3472 
3473  if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3474  return(NULL);
3475  if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3476  return((xmlNodePtr) ns);
3477 
3478  /*
3479  * Allocate a new Namespace and fill the fields.
3480  */
3481  cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3482  if (cur == NULL) {
3483  xmlXPathErrMemory(NULL, "duplicating namespace\n");
3484  return(NULL);
3485  }
3486  memset(cur, 0, sizeof(xmlNs));
3487  cur->type = XML_NAMESPACE_DECL;
3488  if (ns->href != NULL)
3489  cur->href = xmlStrdup(ns->href);
3490  if (ns->prefix != NULL)
3491  cur->prefix = xmlStrdup(ns->prefix);
3492  cur->next = (xmlNsPtr) node;
3493  return((xmlNodePtr) cur);
3494 }
3495 
3504 void
3505 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3506  if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3507  return;
3508 
3509  if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3510  if (ns->href != NULL)
3511  xmlFree((xmlChar *)ns->href);
3512  if (ns->prefix != NULL)
3513  xmlFree((xmlChar *)ns->prefix);
3514  xmlFree(ns);
3515  }
3516 }
3517 
3526 xmlNodeSetPtr
3527 xmlXPathNodeSetCreate(xmlNodePtr val) {
3528  xmlNodeSetPtr ret;
3529 
3530  ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3531  if (ret == NULL) {
3532  xmlXPathErrMemory(NULL, "creating nodeset\n");
3533  return(NULL);
3534  }
3535  memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3536  if (val != NULL) {
3537  ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3538  sizeof(xmlNodePtr));
3539  if (ret->nodeTab == NULL) {
3540  xmlXPathErrMemory(NULL, "creating nodeset\n");
3541  xmlFree(ret);
3542  return(NULL);
3543  }
3544  memset(ret->nodeTab, 0 ,
3545  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3546  ret->nodeMax = XML_NODESET_DEFAULT;
3547  if (val->type == XML_NAMESPACE_DECL) {
3548  xmlNsPtr ns = (xmlNsPtr) val;
3549 
3550  ret->nodeTab[ret->nodeNr++] =
3551  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3552  } else
3553  ret->nodeTab[ret->nodeNr++] = val;
3554  }
3555  return(ret);
3556 }
3557 
3566 static xmlNodeSetPtr
3567 xmlXPathNodeSetCreateSize(int size) {
3568  xmlNodeSetPtr ret;
3569 
3570  ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3571  if (ret == NULL) {
3572  xmlXPathErrMemory(NULL, "creating nodeset\n");
3573  return(NULL);
3574  }
3575  memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3576  if (size < XML_NODESET_DEFAULT)
3577  size = XML_NODESET_DEFAULT;
3578  ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3579  if (ret->nodeTab == NULL) {
3580  xmlXPathErrMemory(NULL, "creating nodeset\n");
3581  xmlFree(ret);
3582  return(NULL);
3583  }
3584  memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3585  ret->nodeMax = size;
3586  return(ret);
3587 }
3588 
3598 int
3599 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3600  int i;
3601 
3602  if ((cur == NULL) || (val == NULL)) return(0);
3603  if (val->type == XML_NAMESPACE_DECL) {
3604  for (i = 0; i < cur->nodeNr; i++) {
3605  if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3606  xmlNsPtr ns1, ns2;
3607 
3608  ns1 = (xmlNsPtr) val;
3609  ns2 = (xmlNsPtr) cur->nodeTab[i];
3610  if (ns1 == ns2)
3611  return(1);
3612  if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3613  (xmlStrEqual(ns1->prefix, ns2->prefix)))
3614  return(1);
3615  }
3616  }
3617  } else {
3618  for (i = 0; i < cur->nodeNr; i++) {
3619  if (cur->nodeTab[i] == val)
3620  return(1);
3621  }
3622  }
3623  return(0);
3624 }
3625 
3636 int
3637 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3638  int i;
3639 
3640 
3641  if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3642  (ns->type != XML_NAMESPACE_DECL) ||
3643  (node->type != XML_ELEMENT_NODE))
3644  return(-1);
3645 
3646  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3647  /*
3648  * prevent duplicates
3649  */
3650  for (i = 0;i < cur->nodeNr;i++) {
3651  if ((cur->nodeTab[i] != NULL) &&
3652  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3653  (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3654  (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3655  return(0);
3656  }
3657 
3658  /*
3659  * grow the nodeTab if needed
3660  */
3661  if (cur->nodeMax == 0) {
3662  cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663  sizeof(xmlNodePtr));
3664  if (cur->nodeTab == NULL) {
3665  xmlXPathErrMemory(NULL, "growing nodeset\n");
3666  return(-1);
3667  }
3668  memset(cur->nodeTab, 0 ,
3669  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670  cur->nodeMax = XML_NODESET_DEFAULT;
3671  } else if (cur->nodeNr == cur->nodeMax) {
3672  xmlNodePtr *temp;
3673 
3674  if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3675  xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3676  return(-1);
3677  }
3678  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3679  sizeof(xmlNodePtr));
3680  if (temp == NULL) {
3681  xmlXPathErrMemory(NULL, "growing nodeset\n");
3682  return(-1);
3683  }
3684  cur->nodeMax *= 2;
3685  cur->nodeTab = temp;
3686  }
3687  cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3688  return(0);
3689 }
3690 
3700 int
3701 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3702  int i;
3703 
3704  if ((cur == NULL) || (val == NULL)) return(-1);
3705 
3706  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3707  /*
3708  * prevent duplicates
3709  */
3710  for (i = 0;i < cur->nodeNr;i++)
3711  if (cur->nodeTab[i] == val) return(0);
3712 
3713  /*
3714  * grow the nodeTab if needed
3715  */
3716  if (cur->nodeMax == 0) {
3717  cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3718  sizeof(xmlNodePtr));
3719  if (cur->nodeTab == NULL) {
3720  xmlXPathErrMemory(NULL, "growing nodeset\n");
3721  return(-1);
3722  }
3723  memset(cur->nodeTab, 0 ,
3724  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3725  cur->nodeMax = XML_NODESET_DEFAULT;
3726  } else if (cur->nodeNr == cur->nodeMax) {
3727  xmlNodePtr *temp;
3728 
3729  if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3730  xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3731  return(-1);
3732  }
3733  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3734  sizeof(xmlNodePtr));
3735  if (temp == NULL) {
3736  xmlXPathErrMemory(NULL, "growing nodeset\n");
3737  return(-1);
3738  }
3739  cur->nodeMax *= 2;
3740  cur->nodeTab = temp;
3741  }
3742  if (val->type == XML_NAMESPACE_DECL) {
3743  xmlNsPtr ns = (xmlNsPtr) val;
3744 
3745  cur->nodeTab[cur->nodeNr++] =
3746  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3747  } else
3748  cur->nodeTab[cur->nodeNr++] = val;
3749  return(0);
3750 }
3751 
3762 int
3763 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3764  if ((cur == NULL) || (val == NULL)) return(-1);
3765 
3766  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3767  /*
3768  * grow the nodeTab if needed
3769  */
3770  if (cur->nodeMax == 0) {
3771  cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3772  sizeof(xmlNodePtr));
3773  if (cur->nodeTab == NULL) {
3774  xmlXPathErrMemory(NULL, "growing nodeset\n");
3775  return(-1);
3776  }
3777  memset(cur->nodeTab, 0 ,
3778  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3779  cur->nodeMax = XML_NODESET_DEFAULT;
3780  } else if (cur->nodeNr == cur->nodeMax) {
3781  xmlNodePtr *temp;
3782 
3783  if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3784  xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3785  return(-1);
3786  }
3787  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3788  sizeof(xmlNodePtr));
3789  if (temp == NULL) {
3790  xmlXPathErrMemory(NULL, "growing nodeset\n");
3791  return(-1);
3792  }
3793  cur->nodeTab = temp;
3794  cur->nodeMax *= 2;
3795  }
3796  if (val->type == XML_NAMESPACE_DECL) {
3797  xmlNsPtr ns = (xmlNsPtr) val;
3798 
3799  cur->nodeTab[cur->nodeNr++] =
3800  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3801  } else
3802  cur->nodeTab[cur->nodeNr++] = val;
3803  return(0);
3804 }
3805 
3816 xmlNodeSetPtr
3817 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3818  int i, j, initNr, skip;
3819  xmlNodePtr n1, n2;
3820 
3821  if (val2 == NULL) return(val1);
3822  if (val1 == NULL) {
3823  val1 = xmlXPathNodeSetCreate(NULL);
3824  if (val1 == NULL)
3825  return (NULL);
3826 #if 0
3827  /*
3828  * TODO: The optimization won't work in every case, since
3829  * those nasty namespace nodes need to be added with
3830  * xmlXPathNodeSetDupNs() to the set; thus a pure
3831  * memcpy is not possible.
3832  * If there was a flag on the nodesetval, indicating that
3833  * some temporary nodes are in, that would be helpfull.
3834  */
3835  /*
3836  * Optimization: Create an equally sized node-set
3837  * and memcpy the content.
3838  */
3839  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3840  if (val1 == NULL)
3841  return(NULL);
3842  if (val2->nodeNr != 0) {
3843  if (val2->nodeNr == 1)
3844  *(val1->nodeTab) = *(val2->nodeTab);
3845  else {
3846  memcpy(val1->nodeTab, val2->nodeTab,
3847  val2->nodeNr * sizeof(xmlNodePtr));
3848  }
3849  val1->nodeNr = val2->nodeNr;
3850  }
3851  return(val1);
3852 #endif
3853  }
3854 
3855  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3856  initNr = val1->nodeNr;
3857 
3858  for (i = 0;i < val2->nodeNr;i++) {
3859  n2 = val2->nodeTab[i];
3860  /*
3861  * check against duplicates
3862  */
3863  skip = 0;
3864  for (j = 0; j < initNr; j++) {
3865  n1 = val1->nodeTab[j];
3866  if (n1 == n2) {
3867  skip = 1;
3868  break;
3869  } else if ((n1->type == XML_NAMESPACE_DECL) &&
3870  (n2->type == XML_NAMESPACE_DECL)) {
3871  if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3872  (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3873  ((xmlNsPtr) n2)->prefix)))
3874  {
3875  skip = 1;
3876  break;
3877  }
3878  }
3879  }
3880  if (skip)
3881  continue;
3882 
3883  /*
3884  * grow the nodeTab if needed
3885  */
3886  if (val1->nodeMax == 0) {
3887  val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3888  sizeof(xmlNodePtr));
3889  if (val1->nodeTab == NULL) {
3890  xmlXPathErrMemory(NULL, "merging nodeset\n");
3891  return(NULL);
3892  }
3893  memset(val1->nodeTab, 0 ,
3894  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3895  val1->nodeMax = XML_NODESET_DEFAULT;
3896  } else if (val1->nodeNr == val1->nodeMax) {
3897  xmlNodePtr *temp;
3898 
3899  if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3900  xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3901  return(NULL);
3902  }
3903  temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3904  sizeof(xmlNodePtr));
3905  if (temp == NULL) {
3906  xmlXPathErrMemory(NULL, "merging nodeset\n");
3907  return(NULL);
3908  }
3909  val1->nodeTab = temp;
3910  val1->nodeMax *= 2;
3911  }
3912  if (n2->type == XML_NAMESPACE_DECL) {
3913  xmlNsPtr ns = (xmlNsPtr) n2;
3914 
3915  val1->nodeTab[val1->nodeNr++] =
3916  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3917  } else
3918  val1->nodeTab[val1->nodeNr++] = n2;
3919  }
3920 
3921  return(val1);
3922 }
3923 
3924 
3937 static xmlNodeSetPtr
3938 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3939  int hasNullEntries)
3940 {
3941  if ((set1 == NULL) && (hasNullEntries == 0)) {
3942  /*
3943  * Note that doing a memcpy of the list, namespace nodes are
3944  * just assigned to set1, since set2 is cleared anyway.
3945  */
3946  set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3947  if (set1 == NULL)
3948  return(NULL);
3949  if (set2->nodeNr != 0) {
3950  memcpy(set1->nodeTab, set2->nodeTab,
3951  set2->nodeNr * sizeof(xmlNodePtr));
3952  set1->nodeNr = set2->nodeNr;
3953  }
3954  } else {
3955  int i, j, initNbSet1;
3956  xmlNodePtr n1, n2;
3957 
3958  if (set1 == NULL)
3959  set1 = xmlXPathNodeSetCreate(NULL);
3960  if (set1 == NULL)
3961  return (NULL);
3962 
3963  initNbSet1 = set1->nodeNr;
3964  for (i = 0;i < set2->nodeNr;i++) {
3965  n2 = set2->nodeTab[i];
3966  /*
3967  * Skip NULLed entries.
3968  */
3969  if (n2 == NULL)
3970  continue;
3971  /*
3972  * Skip duplicates.
3973  */
3974  for (j = 0; j < initNbSet1; j++) {
3975  n1 = set1->nodeTab[j];
3976  if (n1 == n2) {
3977  goto skip_node;
3978  } else if ((n1->type == XML_NAMESPACE_DECL) &&
3979  (n2->type == XML_NAMESPACE_DECL))
3980  {
3981  if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3982  (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3983  ((xmlNsPtr) n2)->prefix)))
3984  {
3985  /*
3986  * Free the namespace node.
3987  */
3988  set2->nodeTab[i] = NULL;
3989  xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3990  goto skip_node;
3991  }
3992  }
3993  }
3994  /*
3995  * grow the nodeTab if needed
3996  */
3997  if (set1->nodeMax == 0) {
3998  set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3999  XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4000  if (set1->nodeTab == NULL) {
4001  xmlXPathErrMemory(NULL, "merging nodeset\n");
4002  return(NULL);
4003  }
4004  memset(set1->nodeTab, 0,
4005  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4006  set1->nodeMax = XML_NODESET_DEFAULT;
4007  } else if (set1->nodeNr >= set1->nodeMax) {
4008  xmlNodePtr *temp;
4009 
4010  if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4011  xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4012  return(NULL);
4013  }
4014  temp = (xmlNodePtr *) xmlRealloc(
4015  set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4016  if (temp == NULL) {
4017  xmlXPathErrMemory(NULL, "merging nodeset\n");
4018  return(NULL);
4019  }
4020  set1->nodeTab = temp;
4021  set1->nodeMax *= 2;
4022  }
4023  set1->nodeTab[set1->nodeNr++] = n2;
4024 skip_node:
4025  {}
4026  }
4027  }
4028  set2->nodeNr = 0;
4029  return(set1);
4030 }
4031 
4044 static xmlNodeSetPtr
4045 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4046  int hasNullEntries)
4047 {
4048  if (set2 == NULL)
4049  return(set1);
4050  if ((set1 == NULL) && (hasNullEntries == 0)) {
4051  /*
4052  * Note that doing a memcpy of the list, namespace nodes are
4053  * just assigned to set1, since set2 is cleared anyway.
4054  */
4055  set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4056  if (set1 == NULL)
4057  return(NULL);
4058  if (set2->nodeNr != 0) {
4059  memcpy(set1->nodeTab, set2->nodeTab,
4060  set2->nodeNr * sizeof(xmlNodePtr));
4061  set1->nodeNr = set2->nodeNr;
4062  }
4063  } else {
4064  int i;
4065  xmlNodePtr n2;
4066 
4067  if (set1 == NULL)
4068  set1 = xmlXPathNodeSetCreate(NULL);
4069  if (set1 == NULL)
4070  return (NULL);
4071 
4072  for (i = 0;i < set2->nodeNr;i++) {
4073  n2 = set2->nodeTab[i];
4074  /*
4075  * Skip NULLed entries.
4076  */
4077  if (n2 == NULL)
4078  continue;
4079  if (set1->nodeMax == 0) {
4080  set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4081  XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4082  if (set1->nodeTab == NULL) {
4083  xmlXPathErrMemory(NULL, "merging nodeset\n");
4084  return(NULL);
4085  }
4086  memset(set1->nodeTab, 0,
4087  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4088  set1->nodeMax = XML_NODESET_DEFAULT;
4089  } else if (set1->nodeNr >= set1->nodeMax) {
4090  xmlNodePtr *temp;
4091 
4092  if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4093  xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4094  return(NULL);
4095  }
4096  temp = (xmlNodePtr *) xmlRealloc(
4097  set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4098  if (temp == NULL) {
4099  xmlXPathErrMemory(NULL, "merging nodeset\n");
4100  return(NULL);
4101  }
4102  set1->nodeTab = temp;
4103  set1->nodeMax *= 2;
4104  }
4105  set1->nodeTab[set1->nodeNr++] = n2;
4106  }
4107  }
4108  set2->nodeNr = 0;
4109  return(set1);
4110 }
4111 
4119 void
4120 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4121  int i;
4122 
4123  if (cur == NULL) return;
4124  if (val == NULL) return;
4125 
4126  /*
4127  * find node in nodeTab
4128  */
4129  for (i = 0;i < cur->nodeNr;i++)
4130  if (cur->nodeTab[i] == val) break;
4131 
4132  if (i >= cur->nodeNr) { /* not found */
4133 #ifdef DEBUG
4135  "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4136  val->name);
4137 #endif
4138  return;
4139  }
4140  if ((cur->nodeTab[i] != NULL) &&
4141  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4142  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4143  cur->nodeNr--;
4144  for (;i < cur->nodeNr;i++)
4145  cur->nodeTab[i] = cur->nodeTab[i + 1];
4146  cur->nodeTab[cur->nodeNr] = NULL;
4147 }
4148 
4156 void
4157 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4158  if (cur == NULL) return;
4159  if (val >= cur->nodeNr) return;
4160  if ((cur->nodeTab[val] != NULL) &&
4161  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4162  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4163  cur->nodeNr--;
4164  for (;val < cur->nodeNr;val++)
4165  cur->nodeTab[val] = cur->nodeTab[val + 1];
4166  cur->nodeTab[cur->nodeNr] = NULL;
4167 }
4168 
4175 void
4176 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4177  if (obj == NULL) return;
4178  if (obj->nodeTab != NULL) {
4179  int i;
4180 
4181  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4182  for (i = 0;i < obj->nodeNr;i++)
4183  if ((obj->nodeTab[i] != NULL) &&
4184  (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4185  xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4186  xmlFree(obj->nodeTab);
4187  }
4188  xmlFree(obj);
4189 }
4190 
4200 static void
4201 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4202 {
4203  if ((set == NULL) || (pos >= set->nodeNr))
4204  return;
4205  else if ((hasNsNodes)) {
4206  int i;
4207  xmlNodePtr node;
4208 
4209  for (i = pos; i < set->nodeNr; i++) {
4210  node = set->nodeTab[i];
4211  if ((node != NULL) &&
4212  (node->type == XML_NAMESPACE_DECL))
4213  xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4214  }
4215  }
4216  set->nodeNr = pos;
4217 }
4218 
4227 static void
4228 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4229 {
4230  xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4231 }
4232 
4241 static void
4242 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4243 {
4244  int i;
4245  xmlNodePtr node;
4246 
4247  if ((set == NULL) || (set->nodeNr <= 1))
4248  return;
4249  for (i = 0; i < set->nodeNr - 1; i++) {
4250  node = set->nodeTab[i];
4251  if ((node != NULL) &&
4252  (node->type == XML_NAMESPACE_DECL))
4253  xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4254  }
4255  set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4256  set->nodeNr = 1;
4257 }
4258 
4266 static void
4267 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4268  int i;
4269 
4270  if (obj == NULL) return;
4271 
4272  if (obj->nodeTab != NULL) {
4273  for (i = 0;i < obj->nodeNr;i++) {
4274  if (obj->nodeTab[i] != NULL) {
4275  if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4276  xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4277  } else {
4278  xmlFreeNodeList(obj->nodeTab[i]);
4279  }
4280  }
4281  }
4282  xmlFree(obj->nodeTab);
4283  }
4284  xmlFree(obj);
4285 }
4286 
4287 #if defined(DEBUG) || defined(DEBUG_STEP)
4288 
4295 void
4296 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4297  int i;
4298 
4300  if (obj == NULL) {
4301  fprintf(output, "NodeSet == NULL !\n");
4302  return;
4303  }
4304  if (obj->nodeNr == 0) {
4305  fprintf(output, "NodeSet is empty\n");
4306  return;
4307  }
4308  if (obj->nodeTab == NULL) {
4309  fprintf(output, " nodeTab == NULL !\n");
4310  return;
4311  }
4312  for (i = 0; i < obj->nodeNr; i++) {
4313  if (obj->nodeTab[i] == NULL) {
4314  fprintf(output, " NULL !\n");
4315  return;
4316  }
4317  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4318  (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4319  fprintf(output, " /");
4320  else if (obj->nodeTab[i]->name == NULL)
4321  fprintf(output, " noname!");
4322  else fprintf(output, " %s", obj->nodeTab[i]->name);
4323  }
4324  fprintf(output, "\n");
4325 }
4326 #endif
4327 
4337 xmlXPathObjectPtr
4338 xmlXPathNewNodeSet(xmlNodePtr val) {
4339  xmlXPathObjectPtr ret;
4340 
4341  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4342  if (ret == NULL) {
4343  xmlXPathErrMemory(NULL, "creating nodeset\n");
4344  return(NULL);
4345  }
4346  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4347  ret->type = XPATH_NODESET;
4348  ret->boolval = 0;
4349  ret->nodesetval = xmlXPathNodeSetCreate(val);
4350  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4351 #ifdef XP_DEBUG_OBJ_USAGE
4352  xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4353 #endif
4354  return(ret);
4355 }
4356 
4366 xmlXPathObjectPtr
4367 xmlXPathNewValueTree(xmlNodePtr val) {
4368  xmlXPathObjectPtr ret;
4369 
4370  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4371  if (ret == NULL) {
4372  xmlXPathErrMemory(NULL, "creating result value tree\n");
4373  return(NULL);
4374  }
4375  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4376  ret->type = XPATH_XSLT_TREE;
4377  ret->boolval = 1;
4378  ret->user = (void *) val;
4379  ret->nodesetval = xmlXPathNodeSetCreate(val);
4380 #ifdef XP_DEBUG_OBJ_USAGE
4381  xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4382 #endif
4383  return(ret);
4384 }
4385 
4395 xmlXPathObjectPtr
4396 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4397 {
4398  xmlXPathObjectPtr ret;
4399  int i;
4400 
4401  if (val == NULL)
4402  ret = NULL;
4403  else if (val->nodeTab == NULL)
4404  ret = xmlXPathNewNodeSet(NULL);
4405  else {
4406  ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4407  if (ret) {
4408  for (i = 1; i < val->nodeNr; ++i) {
4409  if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4410  < 0) break;
4411  }
4412  }
4413  }
4414 
4415  return (ret);
4416 }
4417 
4426 xmlXPathObjectPtr
4427 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4428  xmlXPathObjectPtr ret;
4429 
4430  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4431  if (ret == NULL) {
4432  xmlXPathErrMemory(NULL, "creating node set object\n");
4433  return(NULL);
4434  }
4435  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4436  ret->type = XPATH_NODESET;
4437  ret->nodesetval = val;
4438 #ifdef XP_DEBUG_OBJ_USAGE
4439  xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4440 #endif
4441  return(ret);
4442 }
4443 
4451 void
4452 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4453  if (obj == NULL) return;
4454 #ifdef XP_DEBUG_OBJ_USAGE
4455  xmlXPathDebugObjUsageReleased(NULL, obj->type);
4456 #endif
4457  xmlFree(obj);
4458 }
4459 
4471 xmlNodeSetPtr
4472 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4473  xmlNodeSetPtr ret;
4474  int i, l1;
4475  xmlNodePtr cur;
4476 
4477  if (xmlXPathNodeSetIsEmpty(nodes2))
4478  return(nodes1);
4479 
4480  ret = xmlXPathNodeSetCreate(NULL);
4481  if (xmlXPathNodeSetIsEmpty(nodes1))
4482  return(ret);
4483 
4484  l1 = xmlXPathNodeSetGetLength(nodes1);
4485 
4486  for (i = 0; i < l1; i++) {
4487  cur = xmlXPathNodeSetItem(nodes1, i);
4488  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4489  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4490  break;
4491  }
4492  }
4493  return(ret);
4494 }
4495 
4507 xmlNodeSetPtr
4508 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4509  xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4510  int i, l1;
4511  xmlNodePtr cur;
4512 
4513  if (ret == NULL)
4514  return(ret);
4515  if (xmlXPathNodeSetIsEmpty(nodes1))
4516  return(ret);
4517  if (xmlXPathNodeSetIsEmpty(nodes2))
4518  return(ret);
4519 
4520  l1 = xmlXPathNodeSetGetLength(nodes1);
4521 
4522  for (i = 0; i < l1; i++) {
4523  cur = xmlXPathNodeSetItem(nodes1, i);
4524  if (xmlXPathNodeSetContains(nodes2, cur)) {
4525  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4526  break;
4527  }
4528  }
4529  return(ret);
4530 }
4531 
4542 xmlNodeSetPtr
4543 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4544  xmlNodeSetPtr ret;
4546  int i, l;
4547  xmlChar * strval;
4548  xmlNodePtr cur;
4549 
4550  if (xmlXPathNodeSetIsEmpty(nodes))
4551  return(nodes);
4552 
4553  ret = xmlXPathNodeSetCreate(NULL);
4554  if (ret == NULL)
4555  return(ret);
4556  l = xmlXPathNodeSetGetLength(nodes);
4557  hash = xmlHashCreate (l);
4558  for (i = 0; i < l; i++) {
4559  cur = xmlXPathNodeSetItem(nodes, i);
4560  strval = xmlXPathCastNodeToString(cur);
4561  if (xmlHashLookup(hash, strval) == NULL) {
4563  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4564  break;
4565  } else {
4566  xmlFree(strval);
4567  }
4568  }
4570  return(ret);
4571 }
4572 
4585 xmlNodeSetPtr
4586 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4587  if (xmlXPathNodeSetIsEmpty(nodes))
4588  return(nodes);
4589 
4590  xmlXPathNodeSetSort(nodes);
4591  return(xmlXPathDistinctSorted(nodes));
4592 }
4593 
4605 int
4606 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4607  int i, l;
4608  xmlNodePtr cur;
4609 
4610  if (xmlXPathNodeSetIsEmpty(nodes1) ||
4611  xmlXPathNodeSetIsEmpty(nodes2))
4612  return(0);
4613 
4614  l = xmlXPathNodeSetGetLength(nodes1);
4615  for (i = 0; i < l; i++) {
4616  cur = xmlXPathNodeSetItem(nodes1, i);
4617  if (xmlXPathNodeSetContains(nodes2, cur))
4618  return(1);
4619  }
4620  return(0);
4621 }
4622 
4635 xmlNodeSetPtr
4636 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4637  int i, l;
4638  xmlNodePtr cur;
4639  xmlNodeSetPtr ret;
4640 
4641  if (node == NULL)
4642  return(nodes);
4643 
4644  ret = xmlXPathNodeSetCreate(NULL);
4645  if (ret == NULL)
4646  return(ret);
4647  if (xmlXPathNodeSetIsEmpty(nodes) ||
4648  (!xmlXPathNodeSetContains(nodes, node)))
4649  return(ret);
4650 
4651  l = xmlXPathNodeSetGetLength(nodes);
4652  for (i = 0; i < l; i++) {
4653  cur = xmlXPathNodeSetItem(nodes, i);
4654  if (cur == node)
4655  break;
4656  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4657  break;
4658  }
4659  return(ret);
4660 }
4661 
4676 xmlNodeSetPtr
4677 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4678  xmlXPathNodeSetSort(nodes);
4679  return(xmlXPathNodeLeadingSorted(nodes, node));
4680 }
4681 
4694 xmlNodeSetPtr
4695 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4696  if (xmlXPathNodeSetIsEmpty(nodes2))
4697  return(nodes1);
4698  return(xmlXPathNodeLeadingSorted(nodes1,
4699  xmlXPathNodeSetItem(nodes2, 1)));
4700 }
4701 
4716 xmlNodeSetPtr
4717 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4718  if (xmlXPathNodeSetIsEmpty(nodes2))
4719  return(nodes1);
4720  if (xmlXPathNodeSetIsEmpty(nodes1))
4721  return(xmlXPathNodeSetCreate(NULL));
4722  xmlXPathNodeSetSort(nodes1);
4723  xmlXPathNodeSetSort(nodes2);
4724  return(xmlXPathNodeLeadingSorted(nodes1,
4725  xmlXPathNodeSetItem(nodes2, 1)));
4726 }
4727 
4740 xmlNodeSetPtr
4741 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4742  int i, l;
4743  xmlNodePtr cur;
4744  xmlNodeSetPtr ret;
4745 
4746  if (node == NULL)
4747  return(nodes);
4748 
4749  ret = xmlXPathNodeSetCreate(NULL);
4750  if (ret == NULL)
4751  return(ret);
4752  if (xmlXPathNodeSetIsEmpty(nodes) ||
4753  (!xmlXPathNodeSetContains(nodes, node)))
4754  return(ret);
4755 
4756  l = xmlXPathNodeSetGetLength(nodes);
4757  for (i = l - 1; i >= 0; i--) {
4758  cur = xmlXPathNodeSetItem(nodes, i);
4759  if (cur == node)
4760  break;
4761  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4762  break;
4763  }
4764  xmlXPathNodeSetSort(ret); /* bug 413451 */
4765  return(ret);
4766 }
4767 
4782 xmlNodeSetPtr
4783 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4784  xmlXPathNodeSetSort(nodes);
4785  return(xmlXPathNodeTrailingSorted(nodes, node));
4786 }
4787 
4800 xmlNodeSetPtr
4801 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4802  if (xmlXPathNodeSetIsEmpty(nodes2))
4803  return(nodes1);
4804  return(xmlXPathNodeTrailingSorted(nodes1,
4805  xmlXPathNodeSetItem(nodes2, 0)));
4806 }
4807 
4822 xmlNodeSetPtr
4823 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4824  if (xmlXPathNodeSetIsEmpty(nodes2))
4825  return(nodes1);
4826  if (xmlXPathNodeSetIsEmpty(nodes1))
4827  return(xmlXPathNodeSetCreate(NULL));
4828  xmlXPathNodeSetSort(nodes1);
4829  xmlXPathNodeSetSort(nodes2);
4830  return(xmlXPathNodeTrailingSorted(nodes1,
4831  xmlXPathNodeSetItem(nodes2, 0)));
4832 }
4833 
4834 /************************************************************************
4835  * *
4836  * Routines to handle extra functions *
4837  * *
4838  ************************************************************************/
4839 
4850 int
4851 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4852  xmlXPathFunction f) {
4853  return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4854 }
4855 
4867 int
4868 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4869  const xmlChar *ns_uri, xmlXPathFunction f) {
4870  if (ctxt == NULL)
4871  return(-1);
4872  if (name == NULL)
4873  return(-1);
4874 
4875  if (ctxt->funcHash == NULL)
4876  ctxt->funcHash = xmlHashCreate(0);
4877  if (ctxt->funcHash == NULL)
4878  return(-1);
4879  if (f == NULL)
4880  return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4882  return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4884 }
4885 
4894 void
4895 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4896  xmlXPathFuncLookupFunc f,
4897  void *funcCtxt) {
4898  if (ctxt == NULL)
4899  return;
4900  ctxt->funcLookupFunc = f;
4901  ctxt->funcLookupData = funcCtxt;
4902 }
4903 
4914 xmlXPathFunction
4915 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4916  if (ctxt == NULL)
4917  return (NULL);
4918 
4919  if (ctxt->funcLookupFunc != NULL) {
4920  xmlXPathFunction ret;
4921  xmlXPathFuncLookupFunc f;
4922 
4923  f = ctxt->funcLookupFunc;
4924  ret = f(ctxt->funcLookupData, name, NULL);
4925  if (ret != NULL)
4926  return(ret);
4927  }
4928  return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4929 }
4930 
4942 xmlXPathFunction
4943 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4944  const xmlChar *ns_uri) {
4945  xmlXPathFunction ret;
4946 
4947  if (ctxt == NULL)
4948  return(NULL);
4949  if (name == NULL)
4950  return(NULL);
4951 
4952  if (ctxt->funcLookupFunc != NULL) {
4953  xmlXPathFuncLookupFunc f;
4954 
4955  f = ctxt->funcLookupFunc;
4956  ret = f(ctxt->funcLookupData, name, ns_uri);
4957  if (ret != NULL)
4958  return(ret);
4959  }
4960 
4961  if (ctxt->funcHash == NULL)
4962  return(NULL);
4963 
4965  ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4967  return(ret);
4968 }
4969 
4976 void
4977 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4978  if (ctxt == NULL)
4979  return;
4980 
4981  xmlHashFree(ctxt->funcHash, NULL);
4982  ctxt->funcHash = NULL;
4983 }
4984 
4985 /************************************************************************
4986  * *
4987  * Routines to handle Variables *
4988  * *
4989  ************************************************************************/
4990 
5002 int
5003 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5004  xmlXPathObjectPtr value) {
5005  return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5006 }
5007 
5020 int
5021 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5022  const xmlChar *ns_uri,
5023  xmlXPathObjectPtr value) {
5024  if (ctxt == NULL)
5025  return(-1);
5026  if (name == NULL)
5027  return(-1);
5028 
5029  if (ctxt->varHash == NULL)
5030  ctxt->varHash = xmlHashCreate(0);
5031  if (ctxt->varHash == NULL)
5032  return(-1);
5033  if (value == NULL)
5034  return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5035  xmlXPathFreeObjectEntry));
5036  return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5037  (void *) value, xmlXPathFreeObjectEntry));
5038 }
5039 
5048 void
5049 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5050  xmlXPathVariableLookupFunc f, void *data) {
5051  if (ctxt == NULL)
5052  return;
5053  ctxt->varLookupFunc = f;
5054  ctxt->varLookupData = data;
5055 }
5056 
5067 xmlXPathObjectPtr
5068 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5069  if (ctxt == NULL)
5070  return(NULL);
5071 
5072  if (ctxt->varLookupFunc != NULL) {
5073  xmlXPathObjectPtr ret;
5074 
5075  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5076  (ctxt->varLookupData, name, NULL);
5077  return(ret);
5078  }
5079  return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5080 }
5081 
5093 xmlXPathObjectPtr
5094 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5095  const xmlChar *ns_uri) {
5096  if (ctxt == NULL)
5097  return(NULL);
5098 
5099  if (ctxt->varLookupFunc != NULL) {
5100  xmlXPathObjectPtr ret;
5101 
5102  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5103  (ctxt->varLookupData, name, ns_uri);
5104  if (ret != NULL) return(ret);
5105  }
5106 
5107  if (ctxt->varHash == NULL)
5108  return(NULL);
5109  if (name == NULL)
5110  return(NULL);
5111 
5112  return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5113  xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5114 }
5115 
5122 void
5123 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5124  if (ctxt == NULL)
5125  return;
5126 
5127  xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5128  ctxt->varHash = NULL;
5129 }
5130 
5142 int
5143 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5144  const xmlChar *ns_uri) {
5145  if (ctxt == NULL)
5146  return(-1);
5147  if (prefix == NULL)
5148  return(-1);
5149  if (prefix[0] == 0)
5150  return(-1);
5151 
5152  if (ctxt->nsHash == NULL)
5153  ctxt->nsHash = xmlHashCreate(10);
5154  if (ctxt->nsHash == NULL)
5155  return(-1);
5156  if (ns_uri == NULL)
5157  return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5159  return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5161 }
5162 
5173 const xmlChar *
5174 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5175  if (ctxt == NULL)
5176  return(NULL);
5177  if (prefix == NULL)
5178  return(NULL);
5179 
5180 #ifdef XML_XML_NAMESPACE
5181  if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5182  return(XML_XML_NAMESPACE);
5183 #endif
5184 
5185  if (ctxt->namespaces != NULL) {
5186  int i;
5187 
5188  for (i = 0;i < ctxt->nsNr;i++) {
5189  if ((ctxt->namespaces[i] != NULL) &&
5190  (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5191  return(ctxt->namespaces[i]->href);
5192  }
5193  }
5194 
5195  return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5196 }
5197 
5204 void
5205 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5206  if (ctxt == NULL)
5207  return;
5208 
5209  xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5210  ctxt->nsHash = NULL;
5211 }
5212 
5213 /************************************************************************
5214  * *
5215  * Routines to handle Values *
5216  * *
5217  ************************************************************************/
5218 
5219 /* Allocations are terrible, one needs to optimize all this !!! */
5220 
5229 xmlXPathObjectPtr
5230 xmlXPathNewFloat(double val) {
5231  xmlXPathObjectPtr ret;
5232 
5233  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5234  if (ret == NULL) {
5235  xmlXPathErrMemory(NULL, "creating float object\n");
5236  return(NULL);
5237  }
5238  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5239  ret->type = XPATH_NUMBER;
5240  ret->floatval = val;
5241 #ifdef XP_DEBUG_OBJ_USAGE
5242  xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5243 #endif
5244  return(ret);
5245 }
5246 
5255 xmlXPathObjectPtr
5256 xmlXPathNewBoolean(int val) {
5257  xmlXPathObjectPtr ret;
5258 
5259  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5260  if (ret == NULL) {
5261  xmlXPathErrMemory(NULL, "creating boolean object\n");
5262  return(NULL);
5263  }
5264  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5265  ret->type = XPATH_BOOLEAN;
5266  ret->boolval = (val != 0);
5267 #ifdef XP_DEBUG_OBJ_USAGE
5268  xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5269 #endif
5270  return(ret);
5271 }
5272 
5281 xmlXPathObjectPtr
5282 xmlXPathNewString(const xmlChar *val) {
5283  xmlXPathObjectPtr ret;
5284 
5285  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5286  if (ret == NULL) {
5287  xmlXPathErrMemory(NULL, "creating string object\n");
5288  return(NULL);
5289  }
5290  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5291  ret->type = XPATH_STRING;
5292  if (val != NULL)
5293  ret->stringval = xmlStrdup(val);
5294  else
5295  ret->stringval = xmlStrdup((const xmlChar *)"");
5296 #ifdef XP_DEBUG_OBJ_USAGE
5297  xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5298 #endif
5299  return(ret);
5300 }
5301 
5310 xmlXPathObjectPtr
5311 xmlXPathWrapString (xmlChar *val) {
5312  xmlXPathObjectPtr ret;
5313 
5314  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5315  if (ret == NULL) {
5316  xmlXPathErrMemory(NULL, "creating string object\n");
5317  return(NULL);
5318  }
5319  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5320  ret->type = XPATH_STRING;
5321  ret->stringval = val;
5322 #ifdef XP_DEBUG_OBJ_USAGE
5323  xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5324 #endif
5325  return(ret);
5326 }
5327 
5336 xmlXPathObjectPtr
5337 xmlXPathNewCString(const char *val) {
5338  xmlXPathObjectPtr ret;
5339 
5340  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5341  if (ret == NULL) {
5342  xmlXPathErrMemory(NULL, "creating string object\n");
5343  return(NULL);
5344  }
5345  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5346  ret->type = XPATH_STRING;
5347  ret->stringval = xmlStrdup(BAD_CAST val);
5348 #ifdef XP_DEBUG_OBJ_USAGE
5349  xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5350 #endif
5351  return(ret);
5352 }
5353 
5362 xmlXPathObjectPtr
5363 xmlXPathWrapCString (char * val) {
5364  return(xmlXPathWrapString((xmlChar *)(val)));
5365 }
5366 
5375 xmlXPathObjectPtr
5376 xmlXPathWrapExternal (void *val) {
5377  xmlXPathObjectPtr ret;
5378 
5379  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5380  if (ret == NULL) {
5381  xmlXPathErrMemory(NULL, "creating user object\n");
5382  return(NULL);
5383  }
5384  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5385  ret->type = XPATH_USERS;
5386  ret->user = val;
5387 #ifdef XP_DEBUG_OBJ_USAGE
5388  xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5389 #endif
5390  return(ret);
5391 }
5392 
5401 xmlXPathObjectPtr
5402 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5403  xmlXPathObjectPtr ret;
5404 
5405  if (val == NULL)
5406  return(NULL);
5407 
5408  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5409  if (ret == NULL) {
5410  xmlXPathErrMemory(NULL, "copying object\n");
5411  return(NULL);
5412  }
5413  memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5414 #ifdef XP_DEBUG_OBJ_USAGE
5415  xmlXPathDebugObjUsageRequested(NULL, val->type);
5416 #endif
5417  switch (val->type) {
5418  case XPATH_BOOLEAN:
5419  case XPATH_NUMBER:
5420  case XPATH_POINT:
5421  case XPATH_RANGE:
5422  break;
5423  case XPATH_STRING:
5424  ret->stringval = xmlStrdup(val->stringval);
5425  break;
5426  case XPATH_XSLT_TREE:
5427 #if 0
5428 /*
5429  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5430  this previous handling is no longer correct, and can cause some serious
5431  problems (ref. bug 145547)
5432 */
5433  if ((val->nodesetval != NULL) &&
5434  (val->nodesetval->nodeTab != NULL)) {
5435  xmlNodePtr cur, tmp;
5436  xmlDocPtr top;
5437 
5438  ret->boolval = 1;
5439  top = xmlNewDoc(NULL);
5440  top->name = (char *)
5441  xmlStrdup(val->nodesetval->nodeTab[0]->name);
5442  ret->user = top;
5443  if (top != NULL) {
5444  top->doc = top;
5445  cur = val->nodesetval->nodeTab[0]->children;
5446  while (cur != NULL) {
5447  tmp = xmlDocCopyNode(cur, top, 1);
5448  xmlAddChild((xmlNodePtr) top, tmp);
5449  cur = cur->next;
5450  }
5451  }
5452 
5453  ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5454  } else
5455  ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5456  /* Deallocate the copied tree value */
5457  break;
5458 #endif
5459  case XPATH_NODESET:
5460  ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5461  /* Do not deallocate the copied tree value */
5462  ret->boolval = 0;
5463  break;
5464  case XPATH_LOCATIONSET:
5465 #ifdef LIBXML_XPTR_ENABLED
5466  {
5467  xmlLocationSetPtr loc = val->user;
5468  ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5469  break;
5470  }
5471 #endif
5472  case XPATH_USERS:
5473  ret->user = val->user;
5474  break;
5475  case XPATH_UNDEFINED:
5477  "xmlXPathObjectCopy: unsupported type %d\n",
5478  val->type);
5479  break;
5480  }
5481  return(ret);
5482 }
5483 
5490 void
5491 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5492  if (obj == NULL) return;
5493  if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5494  if (obj->boolval) {
5495 #if 0
5496  if (obj->user != NULL) {
5497  xmlXPathFreeNodeSet(obj->nodesetval);
5498  xmlFreeNodeList((xmlNodePtr) obj->user);
5499  } else
5500 #endif
5501  obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5502  if (obj->nodesetval != NULL)
5503  xmlXPathFreeValueTree(obj->nodesetval);
5504  } else {
5505  if (obj->nodesetval != NULL)
5506  xmlXPathFreeNodeSet(obj->nodesetval);
5507  }
5508 #ifdef LIBXML_XPTR_ENABLED
5509  } else if (obj->type == XPATH_LOCATIONSET) {
5510  if (obj->user != NULL)
5511  xmlXPtrFreeLocationSet(obj->user);
5512 #endif
5513  } else if (obj->type == XPATH_STRING) {
5514  if (obj->stringval != NULL)
5515  xmlFree(obj->stringval);
5516  }
5517 #ifdef XP_DEBUG_OBJ_USAGE
5518  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5519 #endif
5520  xmlFree(obj);
5521 }
5522 
5523 static void
5524 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5525  xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5526 }
5527 
5535 static void
5536 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5537 {
5538 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5539  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5540  if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5541 
5542 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5543 
5544  if (obj == NULL)
5545  return;
5546  if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5547  xmlXPathFreeObject(obj);
5548  } else {
5549  xmlXPathContextCachePtr cache =
5550  (xmlXPathContextCachePtr) ctxt->cache;
5551 
5552  switch (obj->type) {
5553  case XPATH_NODESET:
5554  case XPATH_XSLT_TREE:
5555  if (obj->nodesetval != NULL) {
5556  if (obj->boolval) {
5557  /*
5558  * It looks like the @boolval is used for
5559  * evaluation if this an XSLT Result Tree Fragment.
5560  * TODO: Check if this assumption is correct.
5561  */
5562  obj->type = XPATH_XSLT_TREE; /* just for debugging */
5563  xmlXPathFreeValueTree(obj->nodesetval);
5564  obj->nodesetval = NULL;
5565  } else if ((obj->nodesetval->nodeMax <= 40) &&
5566  (XP_CACHE_WANTS(cache->nodesetObjs,
5567  cache->maxNodeset)))
5568  {
5569  XP_CACHE_ADD(cache->nodesetObjs, obj);
5570  goto obj_cached;
5571  } else {
5572  xmlXPathFreeNodeSet(obj->nodesetval);
5573  obj->nodesetval = NULL;
5574  }
5575  }
5576  break;
5577  case XPATH_STRING:
5578  if (obj->stringval != NULL)
5579  xmlFree(obj->stringval);
5580 
5581  if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5582  XP_CACHE_ADD(cache->stringObjs, obj);
5583  goto obj_cached;
5584  }
5585  break;
5586  case XPATH_BOOLEAN:
5587  if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5588  XP_CACHE_ADD(cache->booleanObjs, obj);
5589  goto obj_cached;
5590  }
5591  break;
5592  case XPATH_NUMBER:
5593  if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5594  XP_CACHE_ADD(cache->numberObjs, obj);
5595  goto obj_cached;
5596  }
5597  break;
5598 #ifdef LIBXML_XPTR_ENABLED
5599  case XPATH_LOCATIONSET:
5600  if (obj->user != NULL) {
5601  xmlXPtrFreeLocationSet(obj->user);
5602  }
5603  goto free_obj;
5604 #endif
5605  default:
5606  goto free_obj;
5607  }
5608 
5609  /*
5610  * Fallback to adding to the misc-objects slot.
5611  */
5612  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5613  XP_CACHE_ADD(cache->miscObjs, obj);
5614  } else
5615  goto free_obj;
5616 
5617 obj_cached:
5618 
5619 #ifdef XP_DEBUG_OBJ_USAGE
5620  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5621 #endif
5622 
5623  if (obj->nodesetval != NULL) {
5624  xmlNodeSetPtr tmpset = obj->nodesetval;
5625 
5626  /*
5627  * TODO: Due to those nasty ns-nodes, we need to traverse
5628  * the list and free the ns-nodes.
5629  * URGENT TODO: Check if it's actually slowing things down.
5630  * Maybe we shouldn't try to preserve the list.
5631  */
5632  if (tmpset->nodeNr > 1) {
5633  int i;
5634  xmlNodePtr node;
5635 
5636  for (i = 0; i < tmpset->nodeNr; i++) {
5637  node = tmpset->nodeTab[i];
5638  if ((node != NULL) &&
5639  (node->type == XML_NAMESPACE_DECL))
5640  {
5641  xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5642  }
5643  }
5644  } else if (tmpset->nodeNr == 1) {
5645  if ((tmpset->nodeTab[0] != NULL) &&
5646  (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5647  xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5648  }
5649  tmpset->nodeNr = 0;
5650  memset(obj, 0, sizeof(xmlXPathObject));
5651  obj->nodesetval = tmpset;
5652  } else
5653  memset(obj, 0, sizeof(xmlXPathObject));
5654 
5655  return;
5656 
5657 free_obj:
5658  /*
5659  * Cache is full; free the object.
5660  */
5661  if (obj->nodesetval != NULL)
5662  xmlXPathFreeNodeSet(obj->nodesetval);
5663 #ifdef XP_DEBUG_OBJ_USAGE
5664  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5665 #endif
5666  xmlFree(obj);
5667  }
5668  return;
5669 }
5670 
5671 
5672 /************************************************************************
5673  * *
5674  * Type Casting Routines *
5675  * *
5676  ************************************************************************/
5677 
5686 xmlChar *
5687 xmlXPathCastBooleanToString (int val) {
5688  xmlChar *ret;
5689  if (val)
5690  ret = xmlStrdup((const xmlChar *) "true");
5691  else
5692  ret = xmlStrdup((const xmlChar *) "false");
5693  return(ret);
5694 }
5695 
5704 xmlChar *
5705 xmlXPathCastNumberToString (double val) {
5706  xmlChar *ret;
5707  switch (xmlXPathIsInf(val)) {
5708  case 1:
5709  ret = xmlStrdup((const xmlChar *) "Infinity");
5710  break;
5711  case -1:
5712  ret = xmlStrdup((const xmlChar *) "-Infinity");
5713  break;
5714  default:
5715  if (xmlXPathIsNaN(val)) {
5716  ret = xmlStrdup((const xmlChar *) "NaN");
5717  } else if (val == 0) {
5718  /* Omit sign for negative zero. */
5719  ret = xmlStrdup((const xmlChar *) "0");
5720  } else {
5721  /* could be improved */
5722  char buf[100];
5723  xmlXPathFormatNumber(val, buf, 99);
5724  buf[99] = 0;
5725  ret = xmlStrdup((const xmlChar *) buf);
5726  }
5727  }
5728  return(ret);
5729 }
5730 
5739 xmlChar *
5740 xmlXPathCastNodeToString (xmlNodePtr node) {
5741 xmlChar *ret;
5742  if ((ret = xmlNodeGetContent(node)) == NULL)
5743  ret = xmlStrdup((const xmlChar *) "");
5744  return(ret);
5745 }
5746 
5755 xmlChar *
5756 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5757  if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5758  return(xmlStrdup((const xmlChar *) ""));
5759 
5760  if (ns->nodeNr > 1)
5761  xmlXPathNodeSetSort(ns);
5762  return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5763 }
5764 
5774 xmlChar *
5775 xmlXPathCastToString(xmlXPathObjectPtr val) {
5776  xmlChar *ret = NULL;
5777 
5778  if (val == NULL)
5779  return(xmlStrdup((const xmlChar *) ""));
5780  switch (val->type) {
5781  case XPATH_UNDEFINED:
5782 #ifdef DEBUG_EXPR
5783  xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5784 #endif
5785  ret = xmlStrdup((const xmlChar *) "");
5786  break;
5787  case XPATH_NODESET:
5788  case XPATH_XSLT_TREE:
5789  ret = xmlXPathCastNodeSetToString(val->nodesetval);
5790  break;
5791  case XPATH_STRING:
5792  return(xmlStrdup(val->stringval));
5793  case XPATH_BOOLEAN:
5794  ret = xmlXPathCastBooleanToString(val->boolval);
5795  break;
5796  case XPATH_NUMBER: {
5797  ret = xmlXPathCastNumberToString(val->floatval);
5798  break;
5799  }
5800  case XPATH_USERS:
5801  case XPATH_POINT:
5802  case XPATH_RANGE:
5803  case XPATH_LOCATIONSET:
5804  TODO
5805  ret = xmlStrdup((const xmlChar *) "");
5806  break;
5807  }
5808  return(ret);
5809 }
5810 
5820 xmlXPathObjectPtr
5821 xmlXPathConvertString(xmlXPathObjectPtr val) {
5822  xmlChar *res = NULL;
5823 
5824  if (val == NULL)
5825  return(xmlXPathNewCString(""));
5826 
5827  switch (val->type) {
5828  case XPATH_UNDEFINED:
5829 #ifdef DEBUG_EXPR
5830  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5831 #endif
5832  break;
5833  case XPATH_NODESET:
5834  case XPATH_XSLT_TREE:
5835  res = xmlXPathCastNodeSetToString(val->nodesetval);
5836  break;
5837  case XPATH_STRING:
5838  return(val);
5839  case XPATH_BOOLEAN:
5840  res = xmlXPathCastBooleanToString(val->boolval);
5841  break;
5842  case XPATH_NUMBER:
5843  res = xmlXPathCastNumberToString(val->floatval);
5844  break;
5845  case XPATH_USERS:
5846  case XPATH_POINT:
5847  case XPATH_RANGE:
5848  case XPATH_LOCATIONSET:
5849  TODO;
5850  break;
5851  }
5852  xmlXPathFreeObject(val);
5853  if (res == NULL)
5854  return(xmlXPathNewCString(""));
5855  return(xmlXPathWrapString(res));
5856 }
5857 
5866 double
5867 xmlXPathCastBooleanToNumber(int val) {
5868  if (val)
5869  return(1.0);
5870  return(0.0);
5871 }
5872 
5881 double
5882 xmlXPathCastStringToNumber(const xmlChar * val) {
5883  return(xmlXPathStringEvalNumber(val));
5884 }
5885 
5894 double
5895 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5896  xmlChar *strval;
5897  double ret;
5898 
5899  if (node == NULL)
5900  return(NAN);
5901  strval = xmlXPathCastNodeToString(node);
5902  if (strval == NULL)
5903  return(NAN);
5904  ret = xmlXPathCastStringToNumber(strval);
5905  xmlFree(strval);
5906 
5907  return(ret);
5908 }
5909 
5918 double
5919 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5920  xmlChar *str;
5921  double ret;
5922 
5923  if (ns == NULL)
5924  return(NAN);
5925  str = xmlXPathCastNodeSetToString(ns);
5926  ret = xmlXPathCastStringToNumber(str);
5927  xmlFree(str);
5928  return(ret);
5929 }
5930 
5939 double
5940 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5941  double ret = 0.0;
5942 
5943  if (val == NULL)
5944  return(NAN);
5945  switch (val->type) {
5946  case XPATH_UNDEFINED:
5947 #ifdef DEGUB_EXPR
5948  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5949 #endif
5950  ret = NAN;
5951  break;
5952  case XPATH_NODESET:
5953  case XPATH_XSLT_TREE:
5954  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5955  break;
5956  case XPATH_STRING:
5957  ret = xmlXPathCastStringToNumber(val->stringval);
5958  break;
5959  case XPATH_NUMBER:
5960  ret = val->floatval;
5961  break;
5962  case XPATH_BOOLEAN:
5963  ret = xmlXPathCastBooleanToNumber(val->boolval);
5964  break;
5965  case XPATH_USERS:
5966  case XPATH_POINT:
5967  case XPATH_RANGE:
5968  case XPATH_LOCATIONSET:
5969  TODO;
5970  ret = NAN;
5971  break;
5972  }
5973  return(ret);
5974 }
5975 
5985 xmlXPathObjectPtr
5986 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5987  xmlXPathObjectPtr ret;
5988 
5989  if (val == NULL)
5990  return(xmlXPathNewFloat(0.0));
5991  if (val->type == XPATH_NUMBER)
5992  return(val);
5993  ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5994  xmlXPathFreeObject(val);
5995  return(ret);
5996 }
5997 
6006 int
6007 xmlXPathCastNumberToBoolean (double val) {
6008  if (xmlXPathIsNaN(val) || (val == 0.0))
6009  return(0);
6010  return(1);
6011 }
6012 
6021 int
6022 xmlXPathCastStringToBoolean (const xmlChar *val) {
6023  if ((val == NULL) || (xmlStrlen(val) == 0))
6024  return(0);
6025  return(1);
6026 }
6027 
6036 int
6037 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6038  if ((ns == NULL) || (ns->nodeNr == 0))
6039  return(0);
6040  return(1);
6041 }
6042 
6051 int
6052 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6053  int ret = 0;
6054 
6055  if (val == NULL)
6056  return(0);
6057  switch (val->type) {
6058  case XPATH_UNDEFINED:
6059 #ifdef DEBUG_EXPR
6060  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6061 #endif
6062  ret = 0;
6063  break;
6064  case XPATH_NODESET:
6065  case XPATH_XSLT_TREE:
6066  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6067  break;
6068  case XPATH_STRING:
6069  ret = xmlXPathCastStringToBoolean(val->stringval);
6070  break;
6071  case XPATH_NUMBER:
6072  ret = xmlXPathCastNumberToBoolean(val->floatval);
6073  break;
6074  case XPATH_BOOLEAN:
6075  ret = val->boolval;
6076  break;
6077  case XPATH_USERS:
6078  case XPATH_POINT:
6079  case XPATH_RANGE:
6080  case XPATH_LOCATIONSET:
6081  TODO;
6082  ret = 0;
6083  break;
6084  }
6085  return(ret);
6086 }
6087 
6088 
6098 xmlXPathObjectPtr
6099 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6100  xmlXPathObjectPtr ret;
6101 
6102  if (val == NULL)
6103  return(xmlXPathNewBoolean(0));
6104  if (val->type == XPATH_BOOLEAN)
6105  return(val);
6106  ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6107  xmlXPathFreeObject(val);
6108  return(ret);
6109 }
6110 
6111 /************************************************************************
6112  * *
6113  * Routines to handle XPath contexts *
6114  * *
6115  ************************************************************************/
6116 
6125 xmlXPathContextPtr
6126 xmlXPathNewContext(xmlDocPtr doc) {
6127  xmlXPathContextPtr ret;
6128 
6129  ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6130  if (ret == NULL) {
6131  xmlXPathErrMemory(NULL, "creating context\n");
6132  return(NULL);
6133  }
6134  memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6135  ret->doc = doc;
6136  ret->node = NULL;
6137 
6138  ret->varHash = NULL;
6139 
6140  ret->nb_types = 0;
6141  ret->max_types = 0;
6142  ret->types = NULL;
6143 
6144  ret->funcHash = xmlHashCreate(0);
6145 
6146  ret->nb_axis = 0;
6147  ret->max_axis = 0;
6148  ret->axis = NULL;
6149 
6150  ret->nsHash = NULL;
6151  ret->user = NULL;
6152 
6153  ret->contextSize = -1;
6154  ret->proximityPosition = -1;
6155 
6156 #ifdef XP_DEFAULT_CACHE_ON
6157  if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6158  xmlXPathFreeContext(ret);
6159  return(NULL);
6160  }
6161 #endif
6162 
6163  xmlXPathRegisterAllFunctions(ret);
6164 
6165  return(ret);
6166 }
6167 
6174 void
6175 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6176  if (ctxt == NULL) return;
6177 
6178  if (ctxt->cache != NULL)
6179  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6180  xmlXPathRegisteredNsCleanup(ctxt);
6181  xmlXPathRegisteredFuncsCleanup(ctxt);
6182  xmlXPathRegisteredVariablesCleanup(ctxt);
6183  xmlResetError(&ctxt->lastError);
6184  xmlFree(ctxt);
6185 }
6186 
6187 /************************************************************************
6188  * *
6189  * Routines to handle XPath parser contexts *
6190  * *
6191  ************************************************************************/
6192 
6193 #define CHECK_CTXT(ctxt) \
6194  if (ctxt == NULL) { \
6195  __xmlRaiseError(NULL, NULL, NULL, \
6196  NULL, NULL, XML_FROM_XPATH, \
6197  XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6198  __FILE__, __LINE__, \
6199  NULL, NULL, NULL, 0, 0, \
6200  "NULL context pointer\n"); \
6201  return(NULL); \
6202  } \
6203 
6204 #define CHECK_CTXT_NEG(ctxt) \
6205  if (ctxt == NULL) { \
6206  __xmlRaiseError(NULL, NULL, NULL, \
6207  NULL, NULL, XML_FROM_XPATH, \
6208  XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6209  __FILE__, __LINE__, \
6210  NULL, NULL, NULL, 0, 0, \
6211  "NULL context pointer\n"); \
6212  return(-1); \
6213  } \
6214 
6215 
6216 #define CHECK_CONTEXT(ctxt) \
6217  if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6218  (ctxt->doc->children == NULL)) { \
6219  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6220  return(NULL); \
6221  }
6222 
6223 
6233 xmlXPathParserContextPtr
6234 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6235  xmlXPathParserContextPtr ret;
6236 
6237  ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6238  if (ret == NULL) {
6239  xmlXPathErrMemory(ctxt, "creating parser context\n");
6240  return(NULL);
6241  }
6242  memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6243  ret->cur = ret->base = str;
6244  ret->context = ctxt;
6245 
6246  ret->comp = xmlXPathNewCompExpr();
6247  if (ret->comp == NULL) {
6248  xmlFree(ret->valueTab);
6249  xmlFree(ret);
6250  return(NULL);
6251  }
6252  if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6253  ret->comp->dict = ctxt->dict;
6254  xmlDictReference(ret->comp->dict);
6255  }
6256 
6257  return(ret);
6258 }
6259 
6269 static xmlXPathParserContextPtr
6270 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6271  xmlXPathParserContextPtr ret;
6272 
6273  ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6274  if (ret == NULL) {
6275  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6276  return(NULL);
6277  }
6278  memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6279 
6280  /* Allocate the value stack */
6281  ret->valueTab = (xmlXPathObjectPtr *)
6282  xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6283  if (ret->valueTab == NULL) {
6284  xmlFree(ret);
6285  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6286  return(NULL);
6287  }
6288  ret->valueNr = 0;
6289  ret->valueMax = 10;
6290  ret->value = NULL;
6291  ret->valueFrame = 0;
6292 
6293  ret->context = ctxt;
6294  ret->comp = comp;
6295 
6296  return(ret);
6297 }
6298 
6305 void
6306 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6307  int i;
6308 
6309  if (ctxt->valueTab != NULL) {
6310  for (i = 0; i < ctxt->valueNr; i++) {
6311  if (ctxt->context)
6312  xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6313  else
6314  xmlXPathFreeObject(ctxt->valueTab[i]);
6315  }
6316  xmlFree(ctxt->valueTab);
6317  }
6318  if (ctxt->comp != NULL) {
6319 #ifdef XPATH_STREAMING
6320  if (ctxt->comp->stream != NULL) {
6321  xmlFreePatternList(ctxt->comp->stream);
6322  ctxt->comp->stream = NULL;
6323  }
6324 #endif
6325  xmlXPathFreeCompExpr(ctxt->comp);
6326  }
6327  xmlFree(ctxt);
6328 }
6329 
6330 /************************************************************************
6331  * *
6332  * The implicit core function library *
6333  * *
6334  ************************************************************************/
6335 
6345 static unsigned int
6346 xmlXPathNodeValHash(xmlNodePtr node) {
6347  int len = 2;
6348  const xmlChar * string = NULL;
6349  xmlNodePtr tmp = NULL;
6350  unsigned int ret = 0;
6351 
6352  if (node == NULL)
6353  return(0);
6354 
6355  if (node->type == XML_DOCUMENT_NODE) {
6357  if (tmp == NULL)
6358  node = node->children;
6359  else
6360  node = tmp;
6361 
6362  if (node == NULL)
6363  return(0);
6364  }
6365 
6366  switch (node->type) {
6367  case XML_COMMENT_NODE:
6368  case XML_PI_NODE:
6370  case XML_TEXT_NODE:
6371  string = node->content;
6372  if (string == NULL)
6373  return(0);
6374  if (string[0] == 0)
6375  return(0);
6376  return(((unsigned int) string[0]) +
6377  (((unsigned int) string[1]) << 8));
6378  case XML_NAMESPACE_DECL:
6379  string = ((xmlNsPtr)node)->href;
6380  if (string == NULL)
6381  return(0);
6382  if (string[0] == 0)
6383  return(0);
6384  return(((unsigned int) string[0]) +
6385  (((unsigned int) string[1]) << 8));
6386  case XML_ATTRIBUTE_NODE:
6387  tmp = ((xmlAttrPtr) node)->children;
6388  break;
6389  case XML_ELEMENT_NODE:
6390  tmp = node->children;
6391  break;
6392  default:
6393  return(0);
6394  }
6395  while (tmp != NULL) {
6396  switch (tmp->type) {
6398  case XML_TEXT_NODE:
6399  string = tmp->content;
6400  break;
6401  default:
6402  string = NULL;
6403  break;
6404  }
6405  if ((string != NULL) && (string[0] != 0)) {
6406  if (len == 1) {
6407  return(ret + (((unsigned int) string[0]) << 8));
6408  }
6409  if (string[1] == 0) {
6410  len = 1;
6411  ret = (unsigned int) string[0];
6412  } else {
6413  return(((unsigned int) string[0]) +
6414  (((unsigned int) string[1]) << 8));
6415  }
6416  }
6417  /*
6418  * Skip to next node
6419  */
6420  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6421  if (tmp->children->type != XML_ENTITY_DECL) {
6422  tmp = tmp->children;
6423  continue;
6424  }
6425  }
6426  if (tmp == node)
6427  break;
6428 
6429  if (tmp->next != NULL) {
6430  tmp = tmp->next;
6431  continue;
6432  }
6433 
6434  do {
6435  tmp = tmp->parent;
6436  if (tmp == NULL)
6437  break;
6438  if (tmp == node) {
6439  tmp = NULL;
6440  break;
6441  }
6442  if (tmp->next != NULL) {
6443  tmp = tmp->next;
6444  break;
6445  }
6446  } while (tmp != NULL);
6447  }
6448  return(ret);
6449 }
6450 
6460 static unsigned int
6461 xmlXPathStringHash(const xmlChar * string) {
6462  if (string == NULL)
6463  return((unsigned int) 0);
6464  if (string[0] == 0)
6465  return(0);
6466  return(((unsigned int) string[0]) +
6467  (((unsigned int) string[1]) << 8));
6468 }
6469 
6492 static int
6493 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6494  xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6495  int i, ret = 0;
6496  xmlNodeSetPtr ns;
6497  xmlChar *str2;
6498 
6499  if ((f == NULL) || (arg == NULL) ||
6500  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6501  xmlXPathReleaseObject(ctxt->context, arg);
6502  xmlXPathReleaseObject(ctxt->context, f);
6503  return(0);
6504  }
6505  ns = arg->nodesetval;
6506  if (ns != NULL) {
6507  for (i = 0;i < ns->nodeNr;i++) {
6508  str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6509  if (str2 != NULL) {
6510  valuePush(ctxt,
6511  xmlXPathCacheNewString(ctxt->context, str2));
6512  xmlFree(str2);
6513  xmlXPathNumberFunction(ctxt, 1);
6514  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6515  ret = xmlXPathCompareValues(ctxt, inf, strict);
6516  if (ret)
6517  break;
6518  }
6519  }
6520  }
6521  xmlXPathReleaseObject(ctxt->context, arg);
6522  xmlXPathReleaseObject(ctxt->context, f);
6523  return(ret);
6524 }
6525 
6547 static int
6548 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6549  xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6550  int i, ret = 0;
6551  xmlNodeSetPtr ns;
6552  xmlChar *str2;
6553 
6554  if ((s == NULL) || (arg == NULL) ||
6555  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6556  xmlXPathReleaseObject(ctxt->context, arg);
6557  xmlXPathReleaseObject(ctxt->context, s);
6558  return(0);
6559  }
6560  ns = arg->nodesetval;
6561  if (ns != NULL) {
6562  for (i = 0;i < ns->nodeNr;i++) {
6563  str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6564  if (str2 != NULL) {
6565  valuePush(ctxt,
6566  xmlXPathCacheNewString(ctxt->context, str2));
6567  xmlFree(str2);
6568  valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6569  ret = xmlXPathCompareValues(ctxt, inf, strict);
6570  if (ret)
6571  break;
6572  }
6573  }
6574  }
6575  xmlXPathReleaseObject(ctxt->context, arg);
6576  xmlXPathReleaseObject(ctxt->context, s);
6577  return(ret);
6578 }
6579 
6608 static int
6609 xmlXPathCompareNodeSets(int inf, int strict,
6610  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6611  int i, j, init = 0;
6612  double val1;
6613  double *values2;
6614  int ret = 0;
6615  xmlNodeSetPtr ns1;
6616  xmlNodeSetPtr ns2;
6617 
6618  if ((arg1 == NULL) ||
6619  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6620  xmlXPathFreeObject(arg2);
6621  return(0);
6622  }
6623  if ((arg2 == NULL) ||
6624  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6625  xmlXPathFreeObject(arg1);
6626  xmlXPathFreeObject(arg2);
6627  return(0);
6628  }
6629 
6630  ns1 = arg1->nodesetval;
6631  ns2 = arg2->nodesetval;
6632 
6633  if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6634  xmlXPathFreeObject(arg1);
6635  xmlXPathFreeObject(arg2);
6636  return(0);
6637  }
6638  if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6639  xmlXPathFreeObject(arg1);
6640  xmlXPathFreeObject(arg2);
6641  return(0);
6642  }
6643 
6644  values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6645  if (values2 == NULL) {
6646  xmlXPathErrMemory(NULL, "comparing nodesets\n");
6647  xmlXPathFreeObject(arg1);
6648  xmlXPathFreeObject(arg2);
6649  return(0);
6650  }
6651  for (i = 0;i < ns1->nodeNr;i++) {
6652  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6653  if (xmlXPathIsNaN(val1))
6654  continue;
6655  for (j = 0;