ReactOS  0.4.15-dev-3207-ga415bd4
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  * XPATH_MAX_RECRUSION_DEPTH:
140  * Maximum amount of nested functions calls when parsing or evaluating
141  * expressions
142  */
143 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
144 #define XPATH_MAX_RECURSION_DEPTH 500
145 #else
146 #define XPATH_MAX_RECURSION_DEPTH 5000
147 #endif
148 
149 /*
150  * TODO:
151  * There are a few spots where some tests are done which depend upon ascii
152  * data. These should be enhanced for full UTF8 support (see particularly
153  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
154  */
155 
156 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157 
168 static int
170  int depth1, depth2;
171  int misc = 0, precedence1 = 0, precedence2 = 0;
172  xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
174  ptrdiff_t l1, l2;
175 
176  if ((node1 == NULL) || (node2 == NULL))
177  return(-2);
178 
179  if (node1 == node2)
180  return(0);
181 
182  /*
183  * a couple of optimizations which will avoid computations in most cases
184  */
185  switch (node1->type) {
186  case XML_ELEMENT_NODE:
187  if (node2->type == XML_ELEMENT_NODE) {
188  if ((0 > (ptrdiff_t) node1->content) &&
189  (0 > (ptrdiff_t) node2->content) &&
190  (node1->doc == node2->doc))
191  {
192  l1 = -((ptrdiff_t) node1->content);
193  l2 = -((ptrdiff_t) node2->content);
194  if (l1 < l2)
195  return(1);
196  if (l1 > l2)
197  return(-1);
198  } else
199  goto turtle_comparison;
200  }
201  break;
202  case XML_ATTRIBUTE_NODE:
203  precedence1 = 1; /* element is owner */
204  miscNode1 = node1;
205  node1 = node1->parent;
206  misc = 1;
207  break;
208  case XML_TEXT_NODE:
210  case XML_COMMENT_NODE:
211  case XML_PI_NODE: {
212  miscNode1 = node1;
213  /*
214  * Find nearest element node.
215  */
216  if (node1->prev != NULL) {
217  do {
218  node1 = node1->prev;
219  if (node1->type == XML_ELEMENT_NODE) {
220  precedence1 = 3; /* element in prev-sibl axis */
221  break;
222  }
223  if (node1->prev == NULL) {
224  precedence1 = 2; /* element is parent */
225  /*
226  * URGENT TODO: Are there any cases, where the
227  * parent of such a node is not an element node?
228  */
229  node1 = node1->parent;
230  break;
231  }
232  } while (1);
233  } else {
234  precedence1 = 2; /* element is parent */
235  node1 = node1->parent;
236  }
237  if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
238  (0 <= (ptrdiff_t) node1->content)) {
239  /*
240  * Fallback for whatever case.
241  */
242  node1 = miscNode1;
243  precedence1 = 0;
244  } else
245  misc = 1;
246  }
247  break;
248  case XML_NAMESPACE_DECL:
249  /*
250  * TODO: why do we return 1 for namespace nodes?
251  */
252  return(1);
253  default:
254  break;
255  }
256  switch (node2->type) {
257  case XML_ELEMENT_NODE:
258  break;
259  case XML_ATTRIBUTE_NODE:
260  precedence2 = 1; /* element is owner */
261  miscNode2 = node2;
262  node2 = node2->parent;
263  misc = 1;
264  break;
265  case XML_TEXT_NODE:
267  case XML_COMMENT_NODE:
268  case XML_PI_NODE: {
269  miscNode2 = node2;
270  if (node2->prev != NULL) {
271  do {
272  node2 = node2->prev;
273  if (node2->type == XML_ELEMENT_NODE) {
274  precedence2 = 3; /* element in prev-sibl axis */
275  break;
276  }
277  if (node2->prev == NULL) {
278  precedence2 = 2; /* element is parent */
279  node2 = node2->parent;
280  break;
281  }
282  } while (1);
283  } else {
284  precedence2 = 2; /* element is parent */
285  node2 = node2->parent;
286  }
287  if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
288  (0 <= (ptrdiff_t) node2->content))
289  {
290  node2 = miscNode2;
291  precedence2 = 0;
292  } else
293  misc = 1;
294  }
295  break;
296  case XML_NAMESPACE_DECL:
297  return(1);
298  default:
299  break;
300  }
301  if (misc) {
302  if (node1 == node2) {
303  if (precedence1 == precedence2) {
304  /*
305  * The ugly case; but normally there aren't many
306  * adjacent non-element nodes around.
307  */
308  cur = miscNode2->prev;
309  while (cur != NULL) {
310  if (cur == miscNode1)
311  return(1);
312  if (cur->type == XML_ELEMENT_NODE)
313  return(-1);
314  cur = cur->prev;
315  }
316  return (-1);
317  } else {
318  /*
319  * Evaluate based on higher precedence wrt to the element.
320  * TODO: This assumes attributes are sorted before content.
321  * Is this 100% correct?
322  */
323  if (precedence1 < precedence2)
324  return(1);
325  else
326  return(-1);
327  }
328  }
329  /*
330  * Special case: One of the helper-elements is contained by the other.
331  * <foo>
332  * <node2>
333  * <node1>Text-1(precedence1 == 2)</node1>
334  * </node2>
335  * Text-6(precedence2 == 3)
336  * </foo>
337  */
338  if ((precedence2 == 3) && (precedence1 > 1)) {
339  cur = node1->parent;
340  while (cur) {
341  if (cur == node2)
342  return(1);
343  cur = cur->parent;
344  }
345  }
346  if ((precedence1 == 3) && (precedence2 > 1)) {
347  cur = node2->parent;
348  while (cur) {
349  if (cur == node1)
350  return(-1);
351  cur = cur->parent;
352  }
353  }
354  }
355 
356  /*
357  * Speedup using document order if available.
358  */
359  if ((node1->type == XML_ELEMENT_NODE) &&
360  (node2->type == XML_ELEMENT_NODE) &&
361  (0 > (ptrdiff_t) node1->content) &&
362  (0 > (ptrdiff_t) node2->content) &&
363  (node1->doc == node2->doc)) {
364 
365  l1 = -((ptrdiff_t) node1->content);
366  l2 = -((ptrdiff_t) node2->content);
367  if (l1 < l2)
368  return(1);
369  if (l1 > l2)
370  return(-1);
371  }
372 
373 turtle_comparison:
374 
375  if (node1 == node2->prev)
376  return(1);
377  if (node1 == node2->next)
378  return(-1);
379  /*
380  * compute depth to root
381  */
382  for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
383  if (cur->parent == node1)
384  return(1);
385  depth2++;
386  }
387  root = cur;
388  for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
389  if (cur->parent == node2)
390  return(-1);
391  depth1++;
392  }
393  /*
394  * Distinct document (or distinct entities :-( ) case.
395  */
396  if (root != cur) {
397  return(-2);
398  }
399  /*
400  * get the nearest common ancestor.
401  */
402  while (depth1 > depth2) {
403  depth1--;
404  node1 = node1->parent;
405  }
406  while (depth2 > depth1) {
407  depth2--;
408  node2 = node2->parent;
409  }
410  while (node1->parent != node2->parent) {
411  node1 = node1->parent;
412  node2 = node2->parent;
413  /* should not happen but just in case ... */
414  if ((node1 == NULL) || (node2 == NULL))
415  return(-2);
416  }
417  /*
418  * Find who's first.
419  */
420  if (node1 == node2->prev)
421  return(1);
422  if (node1 == node2->next)
423  return(-1);
424  /*
425  * Speedup using document order if available.
426  */
427  if ((node1->type == XML_ELEMENT_NODE) &&
428  (node2->type == XML_ELEMENT_NODE) &&
429  (0 > (ptrdiff_t) node1->content) &&
430  (0 > (ptrdiff_t) node2->content) &&
431  (node1->doc == node2->doc)) {
432 
433  l1 = -((ptrdiff_t) node1->content);
434  l2 = -((ptrdiff_t) node2->content);
435  if (l1 < l2)
436  return(1);
437  if (l1 > l2)
438  return(-1);
439  }
440 
441  for (cur = node1->next;cur != NULL;cur = cur->next)
442  if (cur == node2)
443  return(1);
444  return(-1); /* assume there is no sibling list corruption */
445 }
446 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
447 
448 /*
449  * Wrapper for the Timsort algorithm from timsort.h
450  */
451 #ifdef WITH_TIM_SORT
452 #define SORT_NAME libxml_domnode
453 #define SORT_TYPE xmlNodePtr
454 
464 static
466 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
468  {
469  int res = xmlXPathCmpNodesExt(x, y);
470  return res == -2 ? res : -res;
471  }
472 #else
473  static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
474  {
475  int res = xmlXPathCmpNodes(x, y);
476  return res == -2 ? res : -res;
477  }
478 #endif
479 #define SORT_CMP(x, y) (wrap_cmp(x, y))
480 #include "timsort.h"
481 #endif /* WITH_TIM_SORT */
482 
483 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
484 
485 /************************************************************************
486  * *
487  * Floating point stuff *
488  * *
489  ************************************************************************/
490 
491 double xmlXPathNAN;
492 double xmlXPathPINF;
493 double xmlXPathNINF;
494 
500 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
501 void
502 xmlXPathInit(void) {
503  /* MSVC doesn't allow division by zero in constant expressions. */
504  double zero = 0.0;
505  xmlXPathNAN = 0.0 / zero;
506  xmlXPathPINF = 1.0 / zero;
507  xmlXPathNINF = -xmlXPathPINF;
508 }
509 
516 int
517 xmlXPathIsNaN(double val) {
518 #ifdef isnan
519  return isnan(val);
520 #else
521  return !(val == val);
522 #endif
523 }
524 
531 int
532 xmlXPathIsInf(double val) {
533 #ifdef isinf
534  return isinf(val) ? (val > 0 ? 1 : -1) : 0;
535 #else
536  if (val >= xmlXPathPINF)
537  return 1;
538  if (val <= -xmlXPathPINF)
539  return -1;
540  return 0;
541 #endif
542 }
543 
544 #endif /* SCHEMAS or XPATH */
545 
546 #ifdef LIBXML_XPATH_ENABLED
547 
548 /*
549  * TODO: when compatibility allows remove all "fake node libxslt" strings
550  * the test should just be name[0] = ' '
551  */
552 #ifdef DEBUG_XPATH_EXPRESSION
553 #define DEBUG_STEP
554 #define DEBUG_EXPR
555 #define DEBUG_EVAL_COUNTS
556 #endif
557 
558 static xmlNs xmlXPathXMLNamespaceStruct = {
559  NULL,
562  BAD_CAST "xml",
563  NULL,
564  NULL
565 };
566 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
567 #ifndef LIBXML_THREAD_ENABLED
568 /*
569  * Optimizer is disabled only when threaded apps are detected while
570  * the library ain't compiled for thread safety.
571  */
572 static int xmlXPathDisableOptimizer = 0;
573 #endif
574 
575 /************************************************************************
576  * *
577  * Error handling routines *
578  * *
579  ************************************************************************/
580 
587 #define XP_ERRORNULL(X) \
588  { xmlXPathErr(ctxt, X); return(NULL); }
589 
590 /*
591  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
592  */
593 static const char *xmlXPathErrorMessages[] = {
594  "Ok\n",
595  "Number encoding\n",
596  "Unfinished literal\n",
597  "Start of literal\n",
598  "Expected $ for variable reference\n",
599  "Undefined variable\n",
600  "Invalid predicate\n",
601  "Invalid expression\n",
602  "Missing closing curly brace\n",
603  "Unregistered function\n",
604  "Invalid operand\n",
605  "Invalid type\n",
606  "Invalid number of arguments\n",
607  "Invalid context size\n",
608  "Invalid context position\n",
609  "Memory allocation error\n",
610  "Syntax error\n",
611  "Resource error\n",
612  "Sub resource error\n",
613  "Undefined namespace prefix\n",
614  "Encoding error\n",
615  "Char out of XML range\n",
616  "Invalid or incomplete context\n",
617  "Stack usage error\n",
618  "Forbidden variable\n",
619  "Operation limit exceeded\n",
620  "Recursion limit exceeded\n",
621  "?? Unknown error ??\n" /* Must be last in the list! */
622 };
623 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
624  sizeof(xmlXPathErrorMessages[0])) - 1)
625 
632 static void
633 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
634 {
635  if (ctxt != NULL) {
636  xmlResetError(&ctxt->lastError);
637  if (extra) {
638  xmlChar buf[200];
639 
640  xmlStrPrintf(buf, 200,
641  "Memory allocation failed : %s\n",
642  extra);
643  ctxt->lastError.message = (char *) xmlStrdup(buf);
644  } else {
645  ctxt->lastError.message = (char *)
646  xmlStrdup(BAD_CAST "Memory allocation failed\n");
647  }
648  ctxt->lastError.domain = XML_FROM_XPATH;
649  ctxt->lastError.code = XML_ERR_NO_MEMORY;
650  if (ctxt->error != NULL)
651  ctxt->error(ctxt->userData, &ctxt->lastError);
652  } else {
653  if (extra)
654  __xmlRaiseError(NULL, NULL, NULL,
657  extra, NULL, NULL, 0, 0,
658  "Memory allocation failed : %s\n", extra);
659  else
660  __xmlRaiseError(NULL, NULL, NULL,
663  NULL, NULL, NULL, 0, 0,
664  "Memory allocation failed\n");
665  }
666 }
667 
675 static void
676 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
677 {
678  if (ctxt == NULL)
679  xmlXPathErrMemory(NULL, extra);
680  else {
681  ctxt->error = XPATH_MEMORY_ERROR;
682  xmlXPathErrMemory(ctxt->context, extra);
683  }
684 }
685 
693 void
694 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
695 {
696  if ((error < 0) || (error > MAXERRNO))
697  error = MAXERRNO;
698  if (ctxt == NULL) {
699  __xmlRaiseError(NULL, NULL, NULL,
701  error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702  XML_ERR_ERROR, NULL, 0,
703  NULL, NULL, NULL, 0, 0,
704  "%s", xmlXPathErrorMessages[error]);
705  return;
706  }
707  ctxt->error = error;
708  if (ctxt->context == NULL) {
709  __xmlRaiseError(NULL, NULL, NULL,
711  error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
712  XML_ERR_ERROR, NULL, 0,
713  (const char *) ctxt->base, NULL, NULL,
714  ctxt->cur - ctxt->base, 0,
715  "%s", xmlXPathErrorMessages[error]);
716  return;
717  }
718 
719  /* cleanup current last error */
720  xmlResetError(&ctxt->context->lastError);
721 
722  ctxt->context->lastError.domain = XML_FROM_XPATH;
723  ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
724  XPATH_EXPRESSION_OK;
725  ctxt->context->lastError.level = XML_ERR_ERROR;
726  ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
727  ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
728  ctxt->context->lastError.node = ctxt->context->debugNode;
729  if (ctxt->context->error != NULL) {
730  ctxt->context->error(ctxt->context->userData,
731  &ctxt->context->lastError);
732  } else {
733  __xmlRaiseError(NULL, NULL, NULL,
734  NULL, ctxt->context->debugNode, XML_FROM_XPATH,
735  error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
736  XML_ERR_ERROR, NULL, 0,
737  (const char *) ctxt->base, NULL, NULL,
738  ctxt->cur - ctxt->base, 0,
739  "%s", xmlXPathErrorMessages[error]);
740  }
741 
742 }
743 
753 void
754 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
755  int line ATTRIBUTE_UNUSED, int no) {
756  xmlXPathErr(ctxt, no);
757 }
758 
767 static int
768 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
769  xmlXPathContextPtr xpctxt = ctxt->context;
770 
771  if ((opCount > xpctxt->opLimit) ||
772  (xpctxt->opCount > xpctxt->opLimit - opCount)) {
773  xpctxt->opCount = xpctxt->opLimit;
774  xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
775  return(-1);
776  }
777 
778  xpctxt->opCount += opCount;
779  return(0);
780 }
781 
782 #define OP_LIMIT_EXCEEDED(ctxt, n) \
783  ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
784 
785 /************************************************************************
786  * *
787  * Utilities *
788  * *
789  ************************************************************************/
790 
796 typedef struct _xmlPointerList xmlPointerList;
797 typedef xmlPointerList *xmlPointerListPtr;
798 struct _xmlPointerList {
799  void **items;
800  int number;
801  int size;
802 };
803 /*
804 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
805 * and here, we should make the functions public.
806 */
807 static int
808 xmlPointerListAddSize(xmlPointerListPtr list,
809  void *item,
810  int initialSize)
811 {
812  if (list->items == NULL) {
813  if (initialSize <= 0)
814  initialSize = 1;
815  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
816  if (list->items == NULL) {
817  xmlXPathErrMemory(NULL,
818  "xmlPointerListCreate: allocating item\n");
819  return(-1);
820  }
821  list->number = 0;
822  list->size = initialSize;
823  } else if (list->size <= list->number) {
824  if (list->size > 50000000) {
825  xmlXPathErrMemory(NULL,
826  "xmlPointerListAddSize: re-allocating item\n");
827  return(-1);
828  }
829  list->size *= 2;
830  list->items = (void **) xmlRealloc(list->items,
831  list->size * sizeof(void *));
832  if (list->items == NULL) {
833  xmlXPathErrMemory(NULL,
834  "xmlPointerListAddSize: re-allocating item\n");
835  list->size = 0;
836  return(-1);
837  }
838  }
839  list->items[list->number++] = item;
840  return(0);
841 }
842 
850 static xmlPointerListPtr
851 xmlPointerListCreate(int initialSize)
852 {
853  xmlPointerListPtr ret;
854 
855  ret = xmlMalloc(sizeof(xmlPointerList));
856  if (ret == NULL) {
857  xmlXPathErrMemory(NULL,
858  "xmlPointerListCreate: allocating item\n");
859  return (NULL);
860  }
861  memset(ret, 0, sizeof(xmlPointerList));
862  if (initialSize > 0) {
863  xmlPointerListAddSize(ret, NULL, initialSize);
864  ret->number = 0;
865  }
866  return (ret);
867 }
868 
875 static void
876 xmlPointerListFree(xmlPointerListPtr list)
877 {
878  if (list == NULL)
879  return;
880  if (list->items != NULL)
881  xmlFree(list->items);
882  xmlFree(list);
883 }
884 
885 /************************************************************************
886  * *
887  * Parser Types *
888  * *
889  ************************************************************************/
890 
891 /*
892  * Types are private:
893  */
894 
895 typedef enum {
896  XPATH_OP_END=0,
897  XPATH_OP_AND,
898  XPATH_OP_OR,
899  XPATH_OP_EQUAL,
900  XPATH_OP_CMP,
901  XPATH_OP_PLUS,
902  XPATH_OP_MULT,
903  XPATH_OP_UNION,
904  XPATH_OP_ROOT,
905  XPATH_OP_NODE,
906  XPATH_OP_COLLECT,
907  XPATH_OP_VALUE, /* 11 */
908  XPATH_OP_VARIABLE,
909  XPATH_OP_FUNCTION,
910  XPATH_OP_ARG,
911  XPATH_OP_PREDICATE,
912  XPATH_OP_FILTER, /* 16 */
913  XPATH_OP_SORT /* 17 */
914 #ifdef LIBXML_XPTR_ENABLED
915  ,XPATH_OP_RANGETO
916 #endif
917 } xmlXPathOp;
918 
919 typedef enum {
920  AXIS_ANCESTOR = 1,
921  AXIS_ANCESTOR_OR_SELF,
923  AXIS_CHILD,
924  AXIS_DESCENDANT,
925  AXIS_DESCENDANT_OR_SELF,
926  AXIS_FOLLOWING,
927  AXIS_FOLLOWING_SIBLING,
928  AXIS_NAMESPACE,
929  AXIS_PARENT,
930  AXIS_PRECEDING,
931  AXIS_PRECEDING_SIBLING,
932  AXIS_SELF
933 } xmlXPathAxisVal;
934 
935 typedef enum {
936  NODE_TEST_NONE = 0,
937  NODE_TEST_TYPE = 1,
938  NODE_TEST_PI = 2,
939  NODE_TEST_ALL = 3,
940  NODE_TEST_NS = 4,
941  NODE_TEST_NAME = 5
942 } xmlXPathTestVal;
943 
944 typedef enum {
945  NODE_TYPE_NODE = 0,
946  NODE_TYPE_COMMENT = XML_COMMENT_NODE,
947  NODE_TYPE_TEXT = XML_TEXT_NODE,
948  NODE_TYPE_PI = XML_PI_NODE
949 } xmlXPathTypeVal;
950 
951 typedef struct _xmlXPathStepOp xmlXPathStepOp;
952 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
953 struct _xmlXPathStepOp {
954  xmlXPathOp op; /* The identifier of the operation */
955  int ch1; /* First child */
956  int ch2; /* Second child */
957  int value;
958  int value2;
959  int value3;
960  void *value4;
961  void *value5;
962  xmlXPathFunction cache;
963  void *cacheURI;
964 };
965 
966 struct _xmlXPathCompExpr {
967  int nbStep; /* Number of steps in this expression */
968  int maxStep; /* Maximum number of steps allocated */
969  xmlXPathStepOp *steps; /* ops for computation of this expression */
970  int last; /* index of last step in expression */
971  xmlChar *expr; /* the expression being computed */
972  xmlDictPtr dict; /* the dictionary to use if any */
973 #ifdef DEBUG_EVAL_COUNTS
974  int nb;
975  xmlChar *string;
976 #endif
977 #ifdef XPATH_STREAMING
978  xmlPatternPtr stream;
979 #endif
980 };
981 
982 /************************************************************************
983  * *
984  * Forward declarations *
985  * *
986  ************************************************************************/
987 static void
988 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
989 static void
990 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
991 static int
992 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
993  xmlXPathStepOpPtr op, xmlNodePtr *first);
994 static int
995 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
996  xmlXPathStepOpPtr op,
997  int isPredicate);
998 static void
999 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1000 
1001 /************************************************************************
1002  * *
1003  * Parser Type functions *
1004  * *
1005  ************************************************************************/
1006 
1014 static xmlXPathCompExprPtr
1015 xmlXPathNewCompExpr(void) {
1016  xmlXPathCompExprPtr cur;
1017 
1018  cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1019  if (cur == NULL) {
1020  xmlXPathErrMemory(NULL, "allocating component\n");
1021  return(NULL);
1022  }
1023  memset(cur, 0, sizeof(xmlXPathCompExpr));
1024  cur->maxStep = 10;
1025  cur->nbStep = 0;
1026  cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1027  sizeof(xmlXPathStepOp));
1028  if (cur->steps == NULL) {
1029  xmlXPathErrMemory(NULL, "allocating steps\n");
1030  xmlFree(cur);
1031  return(NULL);
1032  }
1033  memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1034  cur->last = -1;
1035 #ifdef DEBUG_EVAL_COUNTS
1036  cur->nb = 0;
1037 #endif
1038  return(cur);
1039 }
1040 
1047 void
1048 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1049 {
1050  xmlXPathStepOpPtr op;
1051  int i;
1052 
1053  if (comp == NULL)
1054  return;
1055  if (comp->dict == NULL) {
1056  for (i = 0; i < comp->nbStep; i++) {
1057  op = &comp->steps[i];
1058  if (op->value4 != NULL) {
1059  if (op->op == XPATH_OP_VALUE)
1060  xmlXPathFreeObject(op->value4);
1061  else
1062  xmlFree(op->value4);
1063  }
1064  if (op->value5 != NULL)
1065  xmlFree(op->value5);
1066  }
1067  } else {
1068  for (i = 0; i < comp->nbStep; i++) {
1069  op = &comp->steps[i];
1070  if (op->value4 != NULL) {
1071  if (op->op == XPATH_OP_VALUE)
1072  xmlXPathFreeObject(op->value4);
1073  }
1074  }
1075  xmlDictFree(comp->dict);
1076  }
1077  if (comp->steps != NULL) {
1078  xmlFree(comp->steps);
1079  }
1080 #ifdef DEBUG_EVAL_COUNTS
1081  if (comp->string != NULL) {
1082  xmlFree(comp->string);
1083  }
1084 #endif
1085 #ifdef XPATH_STREAMING
1086  if (comp->stream != NULL) {
1087  xmlFreePatternList(comp->stream);
1088  }
1089 #endif
1090  if (comp->expr != NULL) {
1091  xmlFree(comp->expr);
1092  }
1093 
1094  xmlFree(comp);
1095 }
1096 
1113 static int
1114 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1115  xmlXPathOp op, int value,
1116  int value2, int value3, void *value4, void *value5) {
1117  xmlXPathCompExprPtr comp = ctxt->comp;
1118  if (comp->nbStep >= comp->maxStep) {
1119  xmlXPathStepOp *real;
1120 
1121  if (comp->maxStep >= XPATH_MAX_STEPS) {
1122  xmlXPathPErrMemory(ctxt, "adding step\n");
1123  return(-1);
1124  }
1125  comp->maxStep *= 2;
1126  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1127  comp->maxStep * sizeof(xmlXPathStepOp));
1128  if (real == NULL) {
1129  comp->maxStep /= 2;
1130  xmlXPathPErrMemory(ctxt, "adding step\n");
1131  return(-1);
1132  }
1133  comp->steps = real;
1134  }
1135  comp->last = comp->nbStep;
1136  comp->steps[comp->nbStep].ch1 = ch1;
1137  comp->steps[comp->nbStep].ch2 = ch2;
1138  comp->steps[comp->nbStep].op = op;
1139  comp->steps[comp->nbStep].value = value;
1140  comp->steps[comp->nbStep].value2 = value2;
1141  comp->steps[comp->nbStep].value3 = value3;
1142  if ((comp->dict != NULL) &&
1143  ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1144  (op == XPATH_OP_COLLECT))) {
1145  if (value4 != NULL) {
1146  comp->steps[comp->nbStep].value4 = (xmlChar *)
1147  (void *)xmlDictLookup(comp->dict, value4, -1);
1148  xmlFree(value4);
1149  } else
1150  comp->steps[comp->nbStep].value4 = NULL;
1151  if (value5 != NULL) {
1152  comp->steps[comp->nbStep].value5 = (xmlChar *)
1153  (void *)xmlDictLookup(comp->dict, value5, -1);
1154  xmlFree(value5);
1155  } else
1156  comp->steps[comp->nbStep].value5 = NULL;
1157  } else {
1158  comp->steps[comp->nbStep].value4 = value4;
1159  comp->steps[comp->nbStep].value5 = value5;
1160  }
1161  comp->steps[comp->nbStep].cache = NULL;
1162  return(comp->nbStep++);
1163 }
1164 
1172 static void
1173 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1174  int tmp;
1175 
1176 #ifndef LIBXML_THREAD_ENABLED
1177  /*
1178  * Since this manipulates possibly shared variables, this is
1179  * disabled if one detects that the library is used in a multithreaded
1180  * application
1181  */
1182  if (xmlXPathDisableOptimizer)
1183  return;
1184 #endif
1185 
1186  tmp = op->ch1;
1187  op->ch1 = op->ch2;
1188  op->ch2 = tmp;
1189 }
1190 
1191 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1192  xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1193  (op), (val), (val2), (val3), (val4), (val5))
1194 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1195  xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1196  (op), (val), (val2), (val3), (val4), (val5))
1197 
1198 #define PUSH_LEAVE_EXPR(op, val, val2) \
1199 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1200 
1201 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1202 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1203 
1204 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1205 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1206  (val), (val2), 0 ,NULL ,NULL)
1207 
1208 /************************************************************************
1209  * *
1210  * XPath object cache structures *
1211  * *
1212  ************************************************************************/
1213 
1214 /* #define XP_DEFAULT_CACHE_ON */
1215 
1216 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1217 
1218 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1219 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1220 struct _xmlXPathContextCache {
1221  xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1222  xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1223  xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1224  xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1225  xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1226  int maxNodeset;
1227  int maxString;
1228  int maxBoolean;
1229  int maxNumber;
1230  int maxMisc;
1231 #ifdef XP_DEBUG_OBJ_USAGE
1232  int dbgCachedAll;
1233  int dbgCachedNodeset;
1234  int dbgCachedString;
1235  int dbgCachedBool;
1236  int dbgCachedNumber;
1237  int dbgCachedPoint;
1238  int dbgCachedRange;
1239  int dbgCachedLocset;
1240  int dbgCachedUsers;
1241  int dbgCachedXSLTTree;
1242  int dbgCachedUndefined;
1243 
1244 
1245  int dbgReusedAll;
1246  int dbgReusedNodeset;
1247  int dbgReusedString;
1248  int dbgReusedBool;
1249  int dbgReusedNumber;
1250  int dbgReusedPoint;
1251  int dbgReusedRange;
1252  int dbgReusedLocset;
1253  int dbgReusedUsers;
1254  int dbgReusedXSLTTree;
1255  int dbgReusedUndefined;
1256 
1257 #endif
1258 };
1259 
1260 /************************************************************************
1261  * *
1262  * Debugging related functions *
1263  * *
1264  ************************************************************************/
1265 
1266 #define STRANGE \
1267  xmlGenericError(xmlGenericErrorContext, \
1268  "Internal error at %s:%d\n", \
1269  __FILE__, __LINE__);
1270 
1271 #ifdef LIBXML_DEBUG_ENABLED
1272 static void
1273 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1274  int i;
1275  char shift[100];
1276 
1277  for (i = 0;((i < depth) && (i < 25));i++)
1278  shift[2 * i] = shift[2 * i + 1] = ' ';
1279  shift[2 * i] = shift[2 * i + 1] = 0;
1280  if (cur == NULL) {
1281  fprintf(output, "%s", shift);
1282  fprintf(output, "Node is NULL !\n");
1283  return;
1284 
1285  }
1286 
1287  if ((cur->type == XML_DOCUMENT_NODE) ||
1288  (cur->type == XML_HTML_DOCUMENT_NODE)) {
1289  fprintf(output, "%s", shift);
1290  fprintf(output, " /\n");
1291  } else if (cur->type == XML_ATTRIBUTE_NODE)
1292  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1293  else
1294  xmlDebugDumpOneNode(output, cur, depth);
1295 }
1296 static void
1297 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1298  xmlNodePtr tmp;
1299  int i;
1300  char shift[100];
1301 
1302  for (i = 0;((i < depth) && (i < 25));i++)
1303  shift[2 * i] = shift[2 * i + 1] = ' ';
1304  shift[2 * i] = shift[2 * i + 1] = 0;
1305  if (cur == NULL) {
1306  fprintf(output, "%s", shift);
1307  fprintf(output, "Node is NULL !\n");
1308  return;
1309 
1310  }
1311 
1312  while (cur != NULL) {
1313  tmp = cur;
1314  cur = cur->next;
1315  xmlDebugDumpOneNode(output, tmp, depth);
1316  }
1317 }
1318 
1319 static void
1320 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1321  int i;
1322  char shift[100];
1323 
1324  for (i = 0;((i < depth) && (i < 25));i++)
1325  shift[2 * i] = shift[2 * i + 1] = ' ';
1326  shift[2 * i] = shift[2 * i + 1] = 0;
1327 
1328  if (cur == NULL) {
1329  fprintf(output, "%s", shift);
1330  fprintf(output, "NodeSet is NULL !\n");
1331  return;
1332 
1333  }
1334 
1335  if (cur != NULL) {
1336  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1337  for (i = 0;i < cur->nodeNr;i++) {
1338  fprintf(output, "%s", shift);
1339  fprintf(output, "%d", i + 1);
1340  xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1341  }
1342  }
1343 }
1344 
1345 static void
1346 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1347  int i;
1348  char shift[100];
1349 
1350  for (i = 0;((i < depth) && (i < 25));i++)
1351  shift[2 * i] = shift[2 * i + 1] = ' ';
1352  shift[2 * i] = shift[2 * i + 1] = 0;
1353 
1354  if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1355  fprintf(output, "%s", shift);
1356  fprintf(output, "Value Tree is NULL !\n");
1357  return;
1358 
1359  }
1360 
1361  fprintf(output, "%s", shift);
1362  fprintf(output, "%d", i + 1);
1363  xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1364 }
1365 #if defined(LIBXML_XPTR_ENABLED)
1366 static void
1367 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1368  int i;
1369  char shift[100];
1370 
1371  for (i = 0;((i < depth) && (i < 25));i++)
1372  shift[2 * i] = shift[2 * i + 1] = ' ';
1373  shift[2 * i] = shift[2 * i + 1] = 0;
1374 
1375  if (cur == NULL) {
1376  fprintf(output, "%s", shift);
1377  fprintf(output, "LocationSet is NULL !\n");
1378  return;
1379 
1380  }
1381 
1382  for (i = 0;i < cur->locNr;i++) {
1383  fprintf(output, "%s", shift);
1384  fprintf(output, "%d : ", i + 1);
1385  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1386  }
1387 }
1388 #endif /* LIBXML_XPTR_ENABLED */
1389 
1398 void
1399 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1400  int i;
1401  char shift[100];
1402 
1403  if (output == NULL) return;
1404 
1405  for (i = 0;((i < depth) && (i < 25));i++)
1406  shift[2 * i] = shift[2 * i + 1] = ' ';
1407  shift[2 * i] = shift[2 * i + 1] = 0;
1408 
1409 
1410  fprintf(output, "%s", shift);
1411 
1412  if (cur == NULL) {
1413  fprintf(output, "Object is empty (NULL)\n");
1414  return;
1415  }
1416  switch(cur->type) {
1417  case XPATH_UNDEFINED:
1418  fprintf(output, "Object is uninitialized\n");
1419  break;
1420  case XPATH_NODESET:
1421  fprintf(output, "Object is a Node Set :\n");
1422  xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1423  break;
1424  case XPATH_XSLT_TREE:
1425  fprintf(output, "Object is an XSLT value tree :\n");
1426  xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1427  break;
1428  case XPATH_BOOLEAN:
1429  fprintf(output, "Object is a Boolean : ");
1430  if (cur->boolval) fprintf(output, "true\n");
1431  else fprintf(output, "false\n");
1432  break;
1433  case XPATH_NUMBER:
1434  switch (xmlXPathIsInf(cur->floatval)) {
1435  case 1:
1436  fprintf(output, "Object is a number : Infinity\n");
1437  break;
1438  case -1:
1439  fprintf(output, "Object is a number : -Infinity\n");
1440  break;
1441  default:
1442  if (xmlXPathIsNaN(cur->floatval)) {
1443  fprintf(output, "Object is a number : NaN\n");
1444  } else if (cur->floatval == 0) {
1445  /* Omit sign for negative zero. */
1446  fprintf(output, "Object is a number : 0\n");
1447  } else {
1448  fprintf(output, "Object is a number : %0g\n", cur->floatval);
1449  }
1450  }
1451  break;
1452  case XPATH_STRING:
1453  fprintf(output, "Object is a string : ");
1454  xmlDebugDumpString(output, cur->stringval);
1455  fprintf(output, "\n");
1456  break;
1457  case XPATH_POINT:
1458  fprintf(output, "Object is a point : index %d in node", cur->index);
1459  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1460  fprintf(output, "\n");
1461  break;
1462  case XPATH_RANGE:
1463  if ((cur->user2 == NULL) ||
1464  ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1465  fprintf(output, "Object is a collapsed range :\n");
1466  fprintf(output, "%s", shift);
1467  if (cur->index >= 0)
1468  fprintf(output, "index %d in ", cur->index);
1469  fprintf(output, "node\n");
1470  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1471  depth + 1);
1472  } else {
1473  fprintf(output, "Object is a range :\n");
1474  fprintf(output, "%s", shift);
1475  fprintf(output, "From ");
1476  if (cur->index >= 0)
1477  fprintf(output, "index %d in ", cur->index);
1478  fprintf(output, "node\n");
1479  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1480  depth + 1);
1481  fprintf(output, "%s", shift);
1482  fprintf(output, "To ");
1483  if (cur->index2 >= 0)
1484  fprintf(output, "index %d in ", cur->index2);
1485  fprintf(output, "node\n");
1486  xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1487  depth + 1);
1488  fprintf(output, "\n");
1489  }
1490  break;
1491  case XPATH_LOCATIONSET:
1492 #if defined(LIBXML_XPTR_ENABLED)
1493  fprintf(output, "Object is a Location Set:\n");
1494  xmlXPathDebugDumpLocationSet(output,
1495  (xmlLocationSetPtr) cur->user, depth);
1496 #endif
1497  break;
1498  case XPATH_USERS:
1499  fprintf(output, "Object is user defined\n");
1500  break;
1501  }
1502 }
1503 
1504 static void
1505 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1506  xmlXPathStepOpPtr op, int depth) {
1507  int i;
1508  char shift[100];
1509 
1510  for (i = 0;((i < depth) && (i < 25));i++)
1511  shift[2 * i] = shift[2 * i + 1] = ' ';
1512  shift[2 * i] = shift[2 * i + 1] = 0;
1513 
1514  fprintf(output, "%s", shift);
1515  if (op == NULL) {
1516  fprintf(output, "Step is NULL\n");
1517  return;
1518  }
1519  switch (op->op) {
1520  case XPATH_OP_END:
1521  fprintf(output, "END"); break;
1522  case XPATH_OP_AND:
1523  fprintf(output, "AND"); break;
1524  case XPATH_OP_OR:
1525  fprintf(output, "OR"); break;
1526  case XPATH_OP_EQUAL:
1527  if (op->value)
1528  fprintf(output, "EQUAL =");
1529  else
1530  fprintf(output, "EQUAL !=");
1531  break;
1532  case XPATH_OP_CMP:
1533  if (op->value)
1534  fprintf(output, "CMP <");
1535  else
1536  fprintf(output, "CMP >");
1537  if (!op->value2)
1538  fprintf(output, "=");
1539  break;
1540  case XPATH_OP_PLUS:
1541  if (op->value == 0)
1542  fprintf(output, "PLUS -");
1543  else if (op->value == 1)
1544  fprintf(output, "PLUS +");
1545  else if (op->value == 2)
1546  fprintf(output, "PLUS unary -");
1547  else if (op->value == 3)
1548  fprintf(output, "PLUS unary - -");
1549  break;
1550  case XPATH_OP_MULT:
1551  if (op->value == 0)
1552  fprintf(output, "MULT *");
1553  else if (op->value == 1)
1554  fprintf(output, "MULT div");
1555  else
1556  fprintf(output, "MULT mod");
1557  break;
1558  case XPATH_OP_UNION:
1559  fprintf(output, "UNION"); break;
1560  case XPATH_OP_ROOT:
1561  fprintf(output, "ROOT"); break;
1562  case XPATH_OP_NODE:
1563  fprintf(output, "NODE"); break;
1564  case XPATH_OP_SORT:
1565  fprintf(output, "SORT"); break;
1566  case XPATH_OP_COLLECT: {
1567  xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1568  xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1569  xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1570  const xmlChar *prefix = op->value4;
1571  const xmlChar *name = op->value5;
1572 
1573  fprintf(output, "COLLECT ");
1574  switch (axis) {
1575  case AXIS_ANCESTOR:
1576  fprintf(output, " 'ancestors' "); break;
1577  case AXIS_ANCESTOR_OR_SELF:
1578  fprintf(output, " 'ancestors-or-self' "); break;
1579  case AXIS_ATTRIBUTE:
1580  fprintf(output, " 'attributes' "); break;
1581  case AXIS_CHILD:
1582  fprintf(output, " 'child' "); break;
1583  case AXIS_DESCENDANT:
1584  fprintf(output, " 'descendant' "); break;
1585  case AXIS_DESCENDANT_OR_SELF:
1586  fprintf(output, " 'descendant-or-self' "); break;
1587  case AXIS_FOLLOWING:
1588  fprintf(output, " 'following' "); break;
1589  case AXIS_FOLLOWING_SIBLING:
1590  fprintf(output, " 'following-siblings' "); break;
1591  case AXIS_NAMESPACE:
1592  fprintf(output, " 'namespace' "); break;
1593  case AXIS_PARENT:
1594  fprintf(output, " 'parent' "); break;
1595  case AXIS_PRECEDING:
1596  fprintf(output, " 'preceding' "); break;
1597  case AXIS_PRECEDING_SIBLING:
1598  fprintf(output, " 'preceding-sibling' "); break;
1599  case AXIS_SELF:
1600  fprintf(output, " 'self' "); break;
1601  }
1602  switch (test) {
1603  case NODE_TEST_NONE:
1604  fprintf(output, "'none' "); break;
1605  case NODE_TEST_TYPE:
1606  fprintf(output, "'type' "); break;
1607  case NODE_TEST_PI:
1608  fprintf(output, "'PI' "); break;
1609  case NODE_TEST_ALL:
1610  fprintf(output, "'all' "); break;
1611  case NODE_TEST_NS:
1612  fprintf(output, "'namespace' "); break;
1613  case NODE_TEST_NAME:
1614  fprintf(output, "'name' "); break;
1615  }
1616  switch (type) {
1617  case NODE_TYPE_NODE:
1618  fprintf(output, "'node' "); break;
1619  case NODE_TYPE_COMMENT:
1620  fprintf(output, "'comment' "); break;
1621  case NODE_TYPE_TEXT:
1622  fprintf(output, "'text' "); break;
1623  case NODE_TYPE_PI:
1624  fprintf(output, "'PI' "); break;
1625  }
1626  if (prefix != NULL)
1627  fprintf(output, "%s:", prefix);
1628  if (name != NULL)
1629  fprintf(output, "%s", (const char *) name);
1630  break;
1631 
1632  }
1633  case XPATH_OP_VALUE: {
1634  xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1635 
1636  fprintf(output, "ELEM ");
1637  xmlXPathDebugDumpObject(output, object, 0);
1638  goto finish;
1639  }
1640  case XPATH_OP_VARIABLE: {
1641  const xmlChar *prefix = op->value5;
1642  const xmlChar *name = op->value4;
1643 
1644  if (prefix != NULL)
1645  fprintf(output, "VARIABLE %s:%s", prefix, name);
1646  else
1647  fprintf(output, "VARIABLE %s", name);
1648  break;
1649  }
1650  case XPATH_OP_FUNCTION: {
1651  int nbargs = op->value;
1652  const xmlChar *prefix = op->value5;
1653  const xmlChar *name = op->value4;
1654 
1655  if (prefix != NULL)
1656  fprintf(output, "FUNCTION %s:%s(%d args)",
1657  prefix, name, nbargs);
1658  else
1659  fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1660  break;
1661  }
1662  case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1663  case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1664  case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1665 #ifdef LIBXML_XPTR_ENABLED
1666  case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1667 #endif
1668  default:
1669  fprintf(output, "UNKNOWN %d\n", op->op); return;
1670  }
1671  fprintf(output, "\n");
1672 finish:
1673  if (op->ch1 >= 0)
1674  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1675  if (op->ch2 >= 0)
1676  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1677 }
1678 
1687 void
1688 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1689  int depth) {
1690  int i;
1691  char shift[100];
1692 
1693  if ((output == NULL) || (comp == NULL)) return;
1694 
1695  for (i = 0;((i < depth) && (i < 25));i++)
1696  shift[2 * i] = shift[2 * i + 1] = ' ';
1697  shift[2 * i] = shift[2 * i + 1] = 0;
1698 
1699  fprintf(output, "%s", shift);
1700 
1701 #ifdef XPATH_STREAMING
1702  if (comp->stream) {
1703  fprintf(output, "Streaming Expression\n");
1704  } else
1705 #endif
1706  {
1707  fprintf(output, "Compiled Expression : %d elements\n",
1708  comp->nbStep);
1709  i = comp->last;
1710  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1711  }
1712 }
1713 
1714 #ifdef XP_DEBUG_OBJ_USAGE
1715 
1716 /*
1717 * XPath object usage related debugging variables.
1718 */
1719 static int xmlXPathDebugObjCounterUndefined = 0;
1720 static int xmlXPathDebugObjCounterNodeset = 0;
1721 static int xmlXPathDebugObjCounterBool = 0;
1722 static int xmlXPathDebugObjCounterNumber = 0;
1723 static int xmlXPathDebugObjCounterString = 0;
1724 static int xmlXPathDebugObjCounterPoint = 0;
1725 static int xmlXPathDebugObjCounterRange = 0;
1726 static int xmlXPathDebugObjCounterLocset = 0;
1727 static int xmlXPathDebugObjCounterUsers = 0;
1728 static int xmlXPathDebugObjCounterXSLTTree = 0;
1729 static int xmlXPathDebugObjCounterAll = 0;
1730 
1731 static int xmlXPathDebugObjTotalUndefined = 0;
1732 static int xmlXPathDebugObjTotalNodeset = 0;
1733 static int xmlXPathDebugObjTotalBool = 0;
1734 static int xmlXPathDebugObjTotalNumber = 0;
1735 static int xmlXPathDebugObjTotalString = 0;
1736 static int xmlXPathDebugObjTotalPoint = 0;
1737 static int xmlXPathDebugObjTotalRange = 0;
1738 static int xmlXPathDebugObjTotalLocset = 0;
1739 static int xmlXPathDebugObjTotalUsers = 0;
1740 static int xmlXPathDebugObjTotalXSLTTree = 0;
1741 static int xmlXPathDebugObjTotalAll = 0;
1742 
1743 static int xmlXPathDebugObjMaxUndefined = 0;
1744 static int xmlXPathDebugObjMaxNodeset = 0;
1745 static int xmlXPathDebugObjMaxBool = 0;
1746 static int xmlXPathDebugObjMaxNumber = 0;
1747 static int xmlXPathDebugObjMaxString = 0;
1748 static int xmlXPathDebugObjMaxPoint = 0;
1749 static int xmlXPathDebugObjMaxRange = 0;
1750 static int xmlXPathDebugObjMaxLocset = 0;
1751 static int xmlXPathDebugObjMaxUsers = 0;
1752 static int xmlXPathDebugObjMaxXSLTTree = 0;
1753 static int xmlXPathDebugObjMaxAll = 0;
1754 
1755 static void
1756 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1757 {
1758  if (ctxt != NULL) {
1759  if (ctxt->cache != NULL) {
1760  xmlXPathContextCachePtr cache =
1761  (xmlXPathContextCachePtr) ctxt->cache;
1762 
1763  cache->dbgCachedAll = 0;
1764  cache->dbgCachedNodeset = 0;
1765  cache->dbgCachedString = 0;
1766  cache->dbgCachedBool = 0;
1767  cache->dbgCachedNumber = 0;
1768  cache->dbgCachedPoint = 0;
1769  cache->dbgCachedRange = 0;
1770  cache->dbgCachedLocset = 0;
1771  cache->dbgCachedUsers = 0;
1772  cache->dbgCachedXSLTTree = 0;
1773  cache->dbgCachedUndefined = 0;
1774 
1775  cache->dbgReusedAll = 0;
1776  cache->dbgReusedNodeset = 0;
1777  cache->dbgReusedString = 0;
1778  cache->dbgReusedBool = 0;
1779  cache->dbgReusedNumber = 0;
1780  cache->dbgReusedPoint = 0;
1781  cache->dbgReusedRange = 0;
1782  cache->dbgReusedLocset = 0;
1783  cache->dbgReusedUsers = 0;
1784  cache->dbgReusedXSLTTree = 0;
1785  cache->dbgReusedUndefined = 0;
1786  }
1787  }
1788 
1789  xmlXPathDebugObjCounterUndefined = 0;
1790  xmlXPathDebugObjCounterNodeset = 0;
1791  xmlXPathDebugObjCounterBool = 0;
1792  xmlXPathDebugObjCounterNumber = 0;
1793  xmlXPathDebugObjCounterString = 0;
1794  xmlXPathDebugObjCounterPoint = 0;
1795  xmlXPathDebugObjCounterRange = 0;
1796  xmlXPathDebugObjCounterLocset = 0;
1797  xmlXPathDebugObjCounterUsers = 0;
1798  xmlXPathDebugObjCounterXSLTTree = 0;
1799  xmlXPathDebugObjCounterAll = 0;
1800 
1801  xmlXPathDebugObjTotalUndefined = 0;
1802  xmlXPathDebugObjTotalNodeset = 0;
1803  xmlXPathDebugObjTotalBool = 0;
1804  xmlXPathDebugObjTotalNumber = 0;
1805  xmlXPathDebugObjTotalString = 0;
1806  xmlXPathDebugObjTotalPoint = 0;
1807  xmlXPathDebugObjTotalRange = 0;
1808  xmlXPathDebugObjTotalLocset = 0;
1809  xmlXPathDebugObjTotalUsers = 0;
1810  xmlXPathDebugObjTotalXSLTTree = 0;
1811  xmlXPathDebugObjTotalAll = 0;
1812 
1813  xmlXPathDebugObjMaxUndefined = 0;
1814  xmlXPathDebugObjMaxNodeset = 0;
1815  xmlXPathDebugObjMaxBool = 0;
1816  xmlXPathDebugObjMaxNumber = 0;
1817  xmlXPathDebugObjMaxString = 0;
1818  xmlXPathDebugObjMaxPoint = 0;
1819  xmlXPathDebugObjMaxRange = 0;
1820  xmlXPathDebugObjMaxLocset = 0;
1821  xmlXPathDebugObjMaxUsers = 0;
1822  xmlXPathDebugObjMaxXSLTTree = 0;
1823  xmlXPathDebugObjMaxAll = 0;
1824 
1825 }
1826 
1827 static void
1828 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1829  xmlXPathObjectType objType)
1830 {
1831  int isCached = 0;
1832 
1833  if (ctxt != NULL) {
1834  if (ctxt->cache != NULL) {
1835  xmlXPathContextCachePtr cache =
1836  (xmlXPathContextCachePtr) ctxt->cache;
1837 
1838  isCached = 1;
1839 
1840  cache->dbgReusedAll++;
1841  switch (objType) {
1842  case XPATH_UNDEFINED:
1843  cache->dbgReusedUndefined++;
1844  break;
1845  case XPATH_NODESET:
1846  cache->dbgReusedNodeset++;
1847  break;
1848  case XPATH_BOOLEAN:
1849  cache->dbgReusedBool++;
1850  break;
1851  case XPATH_NUMBER:
1852  cache->dbgReusedNumber++;
1853  break;
1854  case XPATH_STRING:
1855  cache->dbgReusedString++;
1856  break;
1857  case XPATH_POINT:
1858  cache->dbgReusedPoint++;
1859  break;
1860  case XPATH_RANGE:
1861  cache->dbgReusedRange++;
1862  break;
1863  case XPATH_LOCATIONSET:
1864  cache->dbgReusedLocset++;
1865  break;
1866  case XPATH_USERS:
1867  cache->dbgReusedUsers++;
1868  break;
1869  case XPATH_XSLT_TREE:
1870  cache->dbgReusedXSLTTree++;
1871  break;
1872  default:
1873  break;
1874  }
1875  }
1876  }
1877 
1878  switch (objType) {
1879  case XPATH_UNDEFINED:
1880  if (! isCached)
1881  xmlXPathDebugObjTotalUndefined++;
1882  xmlXPathDebugObjCounterUndefined++;
1883  if (xmlXPathDebugObjCounterUndefined >
1884  xmlXPathDebugObjMaxUndefined)
1885  xmlXPathDebugObjMaxUndefined =
1886  xmlXPathDebugObjCounterUndefined;
1887  break;
1888  case XPATH_NODESET:
1889  if (! isCached)
1890  xmlXPathDebugObjTotalNodeset++;
1891  xmlXPathDebugObjCounterNodeset++;
1892  if (xmlXPathDebugObjCounterNodeset >
1893  xmlXPathDebugObjMaxNodeset)
1894  xmlXPathDebugObjMaxNodeset =
1895  xmlXPathDebugObjCounterNodeset;
1896  break;
1897  case XPATH_BOOLEAN:
1898  if (! isCached)
1899  xmlXPathDebugObjTotalBool++;
1900  xmlXPathDebugObjCounterBool++;
1901  if (xmlXPathDebugObjCounterBool >
1902  xmlXPathDebugObjMaxBool)
1903  xmlXPathDebugObjMaxBool =
1904  xmlXPathDebugObjCounterBool;
1905  break;
1906  case XPATH_NUMBER:
1907  if (! isCached)
1908  xmlXPathDebugObjTotalNumber++;
1909  xmlXPathDebugObjCounterNumber++;
1910  if (xmlXPathDebugObjCounterNumber >
1911  xmlXPathDebugObjMaxNumber)
1912  xmlXPathDebugObjMaxNumber =
1913  xmlXPathDebugObjCounterNumber;
1914  break;
1915  case XPATH_STRING:
1916  if (! isCached)
1917  xmlXPathDebugObjTotalString++;
1918  xmlXPathDebugObjCounterString++;
1919  if (xmlXPathDebugObjCounterString >
1920  xmlXPathDebugObjMaxString)
1921  xmlXPathDebugObjMaxString =
1922  xmlXPathDebugObjCounterString;
1923  break;
1924  case XPATH_POINT:
1925  if (! isCached)
1926  xmlXPathDebugObjTotalPoint++;
1927  xmlXPathDebugObjCounterPoint++;
1928  if (xmlXPathDebugObjCounterPoint >
1929  xmlXPathDebugObjMaxPoint)
1930  xmlXPathDebugObjMaxPoint =
1931  xmlXPathDebugObjCounterPoint;
1932  break;
1933  case XPATH_RANGE:
1934  if (! isCached)
1935  xmlXPathDebugObjTotalRange++;
1936  xmlXPathDebugObjCounterRange++;
1937  if (xmlXPathDebugObjCounterRange >
1938  xmlXPathDebugObjMaxRange)
1939  xmlXPathDebugObjMaxRange =
1940  xmlXPathDebugObjCounterRange;
1941  break;
1942  case XPATH_LOCATIONSET:
1943  if (! isCached)
1944  xmlXPathDebugObjTotalLocset++;
1945  xmlXPathDebugObjCounterLocset++;
1946  if (xmlXPathDebugObjCounterLocset >
1947  xmlXPathDebugObjMaxLocset)
1948  xmlXPathDebugObjMaxLocset =
1949  xmlXPathDebugObjCounterLocset;
1950  break;
1951  case XPATH_USERS:
1952  if (! isCached)
1953  xmlXPathDebugObjTotalUsers++;
1954  xmlXPathDebugObjCounterUsers++;
1955  if (xmlXPathDebugObjCounterUsers >
1956  xmlXPathDebugObjMaxUsers)
1957  xmlXPathDebugObjMaxUsers =
1958  xmlXPathDebugObjCounterUsers;
1959  break;
1960  case XPATH_XSLT_TREE:
1961  if (! isCached)
1962  xmlXPathDebugObjTotalXSLTTree++;
1963  xmlXPathDebugObjCounterXSLTTree++;
1964  if (xmlXPathDebugObjCounterXSLTTree >
1965  xmlXPathDebugObjMaxXSLTTree)
1966  xmlXPathDebugObjMaxXSLTTree =
1967  xmlXPathDebugObjCounterXSLTTree;
1968  break;
1969  default:
1970  break;
1971  }
1972  if (! isCached)
1973  xmlXPathDebugObjTotalAll++;
1974  xmlXPathDebugObjCounterAll++;
1975  if (xmlXPathDebugObjCounterAll >
1976  xmlXPathDebugObjMaxAll)
1977  xmlXPathDebugObjMaxAll =
1978  xmlXPathDebugObjCounterAll;
1979 }
1980 
1981 static void
1982 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1983  xmlXPathObjectType objType)
1984 {
1985  int isCached = 0;
1986 
1987  if (ctxt != NULL) {
1988  if (ctxt->cache != NULL) {
1989  xmlXPathContextCachePtr cache =
1990  (xmlXPathContextCachePtr) ctxt->cache;
1991 
1992  isCached = 1;
1993 
1994  cache->dbgCachedAll++;
1995  switch (objType) {
1996  case XPATH_UNDEFINED:
1997  cache->dbgCachedUndefined++;
1998  break;
1999  case XPATH_NODESET:
2000  cache->dbgCachedNodeset++;
2001  break;
2002  case XPATH_BOOLEAN:
2003  cache->dbgCachedBool++;
2004  break;
2005  case XPATH_NUMBER:
2006  cache->dbgCachedNumber++;
2007  break;
2008  case XPATH_STRING:
2009  cache->dbgCachedString++;
2010  break;
2011  case XPATH_POINT:
2012  cache->dbgCachedPoint++;
2013  break;
2014  case XPATH_RANGE:
2015  cache->dbgCachedRange++;
2016  break;
2017  case XPATH_LOCATIONSET:
2018  cache->dbgCachedLocset++;
2019  break;
2020  case XPATH_USERS:
2021  cache->dbgCachedUsers++;
2022  break;
2023  case XPATH_XSLT_TREE:
2024  cache->dbgCachedXSLTTree++;
2025  break;
2026  default:
2027  break;
2028  }
2029 
2030  }
2031  }
2032  switch (objType) {
2033  case XPATH_UNDEFINED:
2034  xmlXPathDebugObjCounterUndefined--;
2035  break;
2036  case XPATH_NODESET:
2037  xmlXPathDebugObjCounterNodeset--;
2038  break;
2039  case XPATH_BOOLEAN:
2040  xmlXPathDebugObjCounterBool--;
2041  break;
2042  case XPATH_NUMBER:
2043  xmlXPathDebugObjCounterNumber--;
2044  break;
2045  case XPATH_STRING:
2046  xmlXPathDebugObjCounterString--;
2047  break;
2048  case XPATH_POINT:
2049  xmlXPathDebugObjCounterPoint--;
2050  break;
2051  case XPATH_RANGE:
2052  xmlXPathDebugObjCounterRange--;
2053  break;
2054  case XPATH_LOCATIONSET:
2055  xmlXPathDebugObjCounterLocset--;
2056  break;
2057  case XPATH_USERS:
2058  xmlXPathDebugObjCounterUsers--;
2059  break;
2060  case XPATH_XSLT_TREE:
2061  xmlXPathDebugObjCounterXSLTTree--;
2062  break;
2063  default:
2064  break;
2065  }
2066  xmlXPathDebugObjCounterAll--;
2067 }
2068 
2069 static void
2070 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2071 {
2072  int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2073  reqXSLTTree, reqUndefined;
2074  int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2075  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2076  int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2077  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2078  int leftObjs = xmlXPathDebugObjCounterAll;
2079 
2080  reqAll = xmlXPathDebugObjTotalAll;
2081  reqNodeset = xmlXPathDebugObjTotalNodeset;
2082  reqString = xmlXPathDebugObjTotalString;
2083  reqBool = xmlXPathDebugObjTotalBool;
2084  reqNumber = xmlXPathDebugObjTotalNumber;
2085  reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2086  reqUndefined = xmlXPathDebugObjTotalUndefined;
2087 
2088  printf("# XPath object usage:\n");
2089 
2090  if (ctxt != NULL) {
2091  if (ctxt->cache != NULL) {
2092  xmlXPathContextCachePtr cache =
2093  (xmlXPathContextCachePtr) ctxt->cache;
2094 
2095  reAll = cache->dbgReusedAll;
2096  reqAll += reAll;
2097  reNodeset = cache->dbgReusedNodeset;
2098  reqNodeset += reNodeset;
2099  reString = cache->dbgReusedString;
2100  reqString += reString;
2101  reBool = cache->dbgReusedBool;
2102  reqBool += reBool;
2103  reNumber = cache->dbgReusedNumber;
2104  reqNumber += reNumber;
2105  reXSLTTree = cache->dbgReusedXSLTTree;
2106  reqXSLTTree += reXSLTTree;
2107  reUndefined = cache->dbgReusedUndefined;
2108  reqUndefined += reUndefined;
2109 
2110  caAll = cache->dbgCachedAll;
2111  caBool = cache->dbgCachedBool;
2112  caNodeset = cache->dbgCachedNodeset;
2113  caString = cache->dbgCachedString;
2114  caNumber = cache->dbgCachedNumber;
2115  caXSLTTree = cache->dbgCachedXSLTTree;
2116  caUndefined = cache->dbgCachedUndefined;
2117 
2118  if (cache->nodesetObjs)
2119  leftObjs -= cache->nodesetObjs->number;
2120  if (cache->stringObjs)
2121  leftObjs -= cache->stringObjs->number;
2122  if (cache->booleanObjs)
2123  leftObjs -= cache->booleanObjs->number;
2124  if (cache->numberObjs)
2125  leftObjs -= cache->numberObjs->number;
2126  if (cache->miscObjs)
2127  leftObjs -= cache->miscObjs->number;
2128  }
2129  }
2130 
2131  printf("# all\n");
2132  printf("# total : %d\n", reqAll);
2133  printf("# left : %d\n", leftObjs);
2134  printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2135  printf("# reused : %d\n", reAll);
2136  printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2137 
2138  printf("# node-sets\n");
2139  printf("# total : %d\n", reqNodeset);
2140  printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2141  printf("# reused : %d\n", reNodeset);
2142  printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2143 
2144  printf("# strings\n");
2145  printf("# total : %d\n", reqString);
2146  printf("# created: %d\n", xmlXPathDebugObjTotalString);
2147  printf("# reused : %d\n", reString);
2148  printf("# max : %d\n", xmlXPathDebugObjMaxString);
2149 
2150  printf("# booleans\n");
2151  printf("# total : %d\n", reqBool);
2152  printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2153  printf("# reused : %d\n", reBool);
2154  printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2155 
2156  printf("# numbers\n");
2157  printf("# total : %d\n", reqNumber);
2158  printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2159  printf("# reused : %d\n", reNumber);
2160  printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2161 
2162  printf("# XSLT result tree fragments\n");
2163  printf("# total : %d\n", reqXSLTTree);
2164  printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2165  printf("# reused : %d\n", reXSLTTree);
2166  printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2167 
2168  printf("# undefined\n");
2169  printf("# total : %d\n", reqUndefined);
2170  printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2171  printf("# reused : %d\n", reUndefined);
2172  printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2173 
2174 }
2175 
2176 #endif /* XP_DEBUG_OBJ_USAGE */
2177 
2178 #endif /* LIBXML_DEBUG_ENABLED */
2179 
2180 /************************************************************************
2181  * *
2182  * XPath object caching *
2183  * *
2184  ************************************************************************/
2185 
2193 static xmlXPathContextCachePtr
2194 xmlXPathNewCache(void)
2195 {
2196  xmlXPathContextCachePtr ret;
2197 
2198  ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2199  if (ret == NULL) {
2200  xmlXPathErrMemory(NULL, "creating object cache\n");
2201  return(NULL);
2202  }
2203  memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2204  ret->maxNodeset = 100;
2205  ret->maxString = 100;
2206  ret->maxBoolean = 100;
2207  ret->maxNumber = 100;
2208  ret->maxMisc = 100;
2209  return(ret);
2210 }
2211 
2212 static void
2213 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2214 {
2215  int i;
2216  xmlXPathObjectPtr obj;
2217 
2218  if (list == NULL)
2219  return;
2220 
2221  for (i = 0; i < list->number; i++) {
2222  obj = list->items[i];
2223  /*
2224  * Note that it is already assured that we don't need to
2225  * look out for namespace nodes in the node-set.
2226  */
2227  if (obj->nodesetval != NULL) {
2228  if (obj->nodesetval->nodeTab != NULL)
2229  xmlFree(obj->nodesetval->nodeTab);
2230  xmlFree(obj->nodesetval);
2231  }
2232  xmlFree(obj);
2233 #ifdef XP_DEBUG_OBJ_USAGE
2234  xmlXPathDebugObjCounterAll--;
2235 #endif
2236  }
2237  xmlPointerListFree(list);
2238 }
2239 
2240 static void
2241 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2242 {
2243  if (cache == NULL)
2244  return;
2245  if (cache->nodesetObjs)
2246  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2247  if (cache->stringObjs)
2248  xmlXPathCacheFreeObjectList(cache->stringObjs);
2249  if (cache->booleanObjs)
2250  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2251  if (cache->numberObjs)
2252  xmlXPathCacheFreeObjectList(cache->numberObjs);
2253  if (cache->miscObjs)
2254  xmlXPathCacheFreeObjectList(cache->miscObjs);
2255  xmlFree(cache);
2256 }
2257 
2280 int
2281 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2282  int active,
2283  int value,
2284  int options)
2285 {
2286  if (ctxt == NULL)
2287  return(-1);
2288  if (active) {
2289  xmlXPathContextCachePtr cache;
2290 
2291  if (ctxt->cache == NULL) {
2292  ctxt->cache = xmlXPathNewCache();
2293  if (ctxt->cache == NULL)
2294  return(-1);
2295  }
2296  cache = (xmlXPathContextCachePtr) ctxt->cache;
2297  if (options == 0) {
2298  if (value < 0)
2299  value = 100;
2300  cache->maxNodeset = value;
2301  cache->maxString = value;
2302  cache->maxNumber = value;
2303  cache->maxBoolean = value;
2304  cache->maxMisc = value;
2305  }
2306  } else if (ctxt->cache != NULL) {
2307  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2308  ctxt->cache = NULL;
2309  }
2310  return(0);
2311 }
2312 
2323 static xmlXPathObjectPtr
2324 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2325 {
2326  if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2327  xmlXPathContextCachePtr cache =
2328  (xmlXPathContextCachePtr) ctxt->cache;
2329 
2330  if ((cache->miscObjs != NULL) &&
2331  (cache->miscObjs->number != 0))
2332  {
2333  xmlXPathObjectPtr ret;
2334 
2335  ret = (xmlXPathObjectPtr)
2336  cache->miscObjs->items[--cache->miscObjs->number];
2337  ret->type = XPATH_NODESET;
2338  ret->nodesetval = val;
2339 #ifdef XP_DEBUG_OBJ_USAGE
2340  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2341 #endif
2342  return(ret);
2343  }
2344  }
2345 
2346  return(xmlXPathWrapNodeSet(val));
2347 
2348 }
2349 
2360 static xmlXPathObjectPtr
2361 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2362 {
2363  if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2364  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2365 
2366  if ((cache->stringObjs != NULL) &&
2367  (cache->stringObjs->number != 0))
2368  {
2369 
2370  xmlXPathObjectPtr ret;
2371 
2372  ret = (xmlXPathObjectPtr)
2373  cache->stringObjs->items[--cache->stringObjs->number];
2374  ret->type = XPATH_STRING;
2375  ret->stringval = val;
2376 #ifdef XP_DEBUG_OBJ_USAGE
2377  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2378 #endif
2379  return(ret);
2380  } else if ((cache->miscObjs != NULL) &&
2381  (cache->miscObjs->number != 0))
2382  {
2383  xmlXPathObjectPtr ret;
2384  /*
2385  * Fallback to misc-cache.
2386  */
2387  ret = (xmlXPathObjectPtr)
2388  cache->miscObjs->items[--cache->miscObjs->number];
2389 
2390  ret->type = XPATH_STRING;
2391  ret->stringval = val;
2392 #ifdef XP_DEBUG_OBJ_USAGE
2393  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394 #endif
2395  return(ret);
2396  }
2397  }
2398  return(xmlXPathWrapString(val));
2399 }
2400 
2412 static xmlXPathObjectPtr
2413 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2414 {
2415  if ((ctxt != NULL) && (ctxt->cache)) {
2416  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2417 
2418  if ((cache->nodesetObjs != NULL) &&
2419  (cache->nodesetObjs->number != 0))
2420  {
2421  xmlXPathObjectPtr ret;
2422  /*
2423  * Use the nodeset-cache.
2424  */
2425  ret = (xmlXPathObjectPtr)
2426  cache->nodesetObjs->items[--cache->nodesetObjs->number];
2427  ret->type = XPATH_NODESET;
2428  ret->boolval = 0;
2429  if (val) {
2430  if ((ret->nodesetval->nodeMax == 0) ||
2431  (val->type == XML_NAMESPACE_DECL))
2432  {
2433  /* TODO: Check memory error. */
2434  xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2435  } else {
2436  ret->nodesetval->nodeTab[0] = val;
2437  ret->nodesetval->nodeNr = 1;
2438  }
2439  }
2440 #ifdef XP_DEBUG_OBJ_USAGE
2441  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2442 #endif
2443  return(ret);
2444  } else if ((cache->miscObjs != NULL) &&
2445  (cache->miscObjs->number != 0))
2446  {
2447  xmlXPathObjectPtr ret;
2448  /*
2449  * Fallback to misc-cache.
2450  */
2451 
2452  ret = (xmlXPathObjectPtr)
2453  cache->miscObjs->items[--cache->miscObjs->number];
2454 
2455  ret->type = XPATH_NODESET;
2456  ret->boolval = 0;
2457  ret->nodesetval = xmlXPathNodeSetCreate(val);
2458  if (ret->nodesetval == NULL) {
2459  ctxt->lastError.domain = XML_FROM_XPATH;
2460  ctxt->lastError.code = XML_ERR_NO_MEMORY;
2461  return(NULL);
2462  }
2463 #ifdef XP_DEBUG_OBJ_USAGE
2464  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2465 #endif
2466  return(ret);
2467  }
2468  }
2469  return(xmlXPathNewNodeSet(val));
2470 }
2471 
2482 static xmlXPathObjectPtr
2483 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2484 {
2485  if ((ctxt != NULL) && (ctxt->cache)) {
2486  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2487 
2488  if ((cache->stringObjs != NULL) &&
2489  (cache->stringObjs->number != 0))
2490  {
2491  xmlXPathObjectPtr ret;
2492 
2493  ret = (xmlXPathObjectPtr)
2494  cache->stringObjs->items[--cache->stringObjs->number];
2495 
2496  ret->type = XPATH_STRING;
2497  ret->stringval = xmlStrdup(BAD_CAST val);
2498 #ifdef XP_DEBUG_OBJ_USAGE
2499  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2500 #endif
2501  return(ret);
2502  } else if ((cache->miscObjs != NULL) &&
2503  (cache->miscObjs->number != 0))
2504  {
2505  xmlXPathObjectPtr ret;
2506 
2507  ret = (xmlXPathObjectPtr)
2508  cache->miscObjs->items[--cache->miscObjs->number];
2509 
2510  ret->type = XPATH_STRING;
2511  ret->stringval = xmlStrdup(BAD_CAST val);
2512 #ifdef XP_DEBUG_OBJ_USAGE
2513  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2514 #endif
2515  return(ret);
2516  }
2517  }
2518  return(xmlXPathNewCString(val));
2519 }
2520 
2531 static xmlXPathObjectPtr
2532 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2533 {
2534  if ((ctxt != NULL) && (ctxt->cache)) {
2535  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2536 
2537  if ((cache->stringObjs != NULL) &&
2538  (cache->stringObjs->number != 0))
2539  {
2540  xmlXPathObjectPtr ret;
2541 
2542  ret = (xmlXPathObjectPtr)
2543  cache->stringObjs->items[--cache->stringObjs->number];
2544  ret->type = XPATH_STRING;
2545  if (val != NULL)
2546  ret->stringval = xmlStrdup(val);
2547  else
2548  ret->stringval = xmlStrdup((const xmlChar *)"");
2549 #ifdef XP_DEBUG_OBJ_USAGE
2550  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2551 #endif
2552  return(ret);
2553  } else if ((cache->miscObjs != NULL) &&
2554  (cache->miscObjs->number != 0))
2555  {
2556  xmlXPathObjectPtr ret;
2557 
2558  ret = (xmlXPathObjectPtr)
2559  cache->miscObjs->items[--cache->miscObjs->number];
2560 
2561  ret->type = XPATH_STRING;
2562  if (val != NULL)
2563  ret->stringval = xmlStrdup(val);
2564  else
2565  ret->stringval = xmlStrdup((const xmlChar *)"");
2566 #ifdef XP_DEBUG_OBJ_USAGE
2567  xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2568 #endif
2569  return(ret);
2570  }
2571  }
2572  return(xmlXPathNewString(val));
2573 }
2574 
2585 static xmlXPathObjectPtr
2586 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2587 {
2588  if ((ctxt != NULL) && (ctxt->cache)) {
2589  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2590 
2591  if ((cache->booleanObjs != NULL) &&
2592  (cache->booleanObjs->number != 0))
2593  {
2594  xmlXPathObjectPtr ret;
2595 
2596  ret = (xmlXPathObjectPtr)
2597  cache->booleanObjs->items[--cache->booleanObjs->number];
2598  ret->type = XPATH_BOOLEAN;
2599  ret->boolval = (val != 0);
2600 #ifdef XP_DEBUG_OBJ_USAGE
2601  xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2602 #endif
2603  return(ret);
2604  } else if ((cache->miscObjs != NULL) &&
2605  (cache->miscObjs->number != 0))
2606  {
2607  xmlXPathObjectPtr ret;
2608 
2609  ret = (xmlXPathObjectPtr)
2610  cache->miscObjs->items[--cache->miscObjs->number];
2611 
2612  ret->type = XPATH_BOOLEAN;
2613  ret->boolval = (val != 0);
2614 #ifdef XP_DEBUG_OBJ_USAGE
2615  xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2616 #endif
2617  return(ret);
2618  }
2619  }
2620  return(xmlXPathNewBoolean(val));
2621 }
2622 
2633 static xmlXPathObjectPtr
2634 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2635 {
2636  if ((ctxt != NULL) && (ctxt->cache)) {
2637  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2638 
2639  if ((cache->numberObjs != NULL) &&
2640  (cache->numberObjs->number != 0))
2641  {
2642  xmlXPathObjectPtr ret;
2643 
2644  ret = (xmlXPathObjectPtr)
2645  cache->numberObjs->items[--cache->numberObjs->number];
2646  ret->type = XPATH_NUMBER;
2647  ret->floatval = val;
2648 #ifdef XP_DEBUG_OBJ_USAGE
2649  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2650 #endif
2651  return(ret);
2652  } else if ((cache->miscObjs != NULL) &&
2653  (cache->miscObjs->number != 0))
2654  {
2655  xmlXPathObjectPtr ret;
2656 
2657  ret = (xmlXPathObjectPtr)
2658  cache->miscObjs->items[--cache->miscObjs->number];
2659 
2660  ret->type = XPATH_NUMBER;
2661  ret->floatval = val;
2662 #ifdef XP_DEBUG_OBJ_USAGE
2663  xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2664 #endif
2665  return(ret);
2666  }
2667  }
2668  return(xmlXPathNewFloat(val));
2669 }
2670 
2683 static xmlXPathObjectPtr
2684 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2685  xmlChar *res = NULL;
2686 
2687  if (val == NULL)
2688  return(xmlXPathCacheNewCString(ctxt, ""));
2689 
2690  switch (val->type) {
2691  case XPATH_UNDEFINED:
2692 #ifdef DEBUG_EXPR
2693  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2694 #endif
2695  break;
2696  case XPATH_NODESET:
2697  case XPATH_XSLT_TREE:
2698  res = xmlXPathCastNodeSetToString(val->nodesetval);
2699  break;
2700  case XPATH_STRING:
2701  return(val);
2702  case XPATH_BOOLEAN:
2703  res = xmlXPathCastBooleanToString(val->boolval);
2704  break;
2705  case XPATH_NUMBER:
2706  res = xmlXPathCastNumberToString(val->floatval);
2707  break;
2708  case XPATH_USERS:
2709  case XPATH_POINT:
2710  case XPATH_RANGE:
2711  case XPATH_LOCATIONSET:
2712  TODO;
2713  break;
2714  }
2715  xmlXPathReleaseObject(ctxt, val);
2716  if (res == NULL)
2717  return(xmlXPathCacheNewCString(ctxt, ""));
2718  return(xmlXPathCacheWrapString(ctxt, res));
2719 }
2720 
2731 static xmlXPathObjectPtr
2732 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2733 {
2734  if (val == NULL)
2735  return(NULL);
2736 
2737  if (XP_HAS_CACHE(ctxt)) {
2738  switch (val->type) {
2739  case XPATH_NODESET:
2740  return(xmlXPathCacheWrapNodeSet(ctxt,
2741  xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2742  case XPATH_STRING:
2743  return(xmlXPathCacheNewString(ctxt, val->stringval));
2744  case XPATH_BOOLEAN:
2745  return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2746  case XPATH_NUMBER:
2747  return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2748  default:
2749  break;
2750  }
2751  }
2752  return(xmlXPathObjectCopy(val));
2753 }
2754 
2766 static xmlXPathObjectPtr
2767 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2768  xmlXPathObjectPtr ret;
2769 
2770  if (val == NULL)
2771  return(xmlXPathCacheNewBoolean(ctxt, 0));
2772  if (val->type == XPATH_BOOLEAN)
2773  return(val);
2774  ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2775  xmlXPathReleaseObject(ctxt, val);
2776  return(ret);
2777 }
2778 
2790 static xmlXPathObjectPtr
2791 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2792  xmlXPathObjectPtr ret;
2793 
2794  if (val == NULL)
2795  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2796  if (val->type == XPATH_NUMBER)
2797  return(val);
2798  ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2799  xmlXPathReleaseObject(ctxt, val);
2800  return(ret);
2801 }
2802 
2803 /************************************************************************
2804  * *
2805  * Parser stacks related functions and macros *
2806  * *
2807  ************************************************************************/
2808 
2817 static int
2818 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2819  int ret;
2820 
2821  if (ctxt == NULL)
2822  return(0);
2823  ret = ctxt->valueFrame;
2824  ctxt->valueFrame = ctxt->valueNr;
2825  return(ret);
2826 }
2827 
2835 static void
2836 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2837  if (ctxt == NULL)
2838  return;
2839  if (ctxt->valueNr < ctxt->valueFrame) {
2840  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2841  }
2842  ctxt->valueFrame = frame;
2843 }
2844 
2853 xmlXPathObjectPtr
2854 valuePop(xmlXPathParserContextPtr ctxt)
2855 {
2856  xmlXPathObjectPtr ret;
2857 
2858  if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2859  return (NULL);
2860 
2861  if (ctxt->valueNr <= ctxt->valueFrame) {
2862  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2863  return (NULL);
2864  }
2865 
2866  ctxt->valueNr--;
2867  if (ctxt->valueNr > 0)
2868  ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2869  else
2870  ctxt->value = NULL;
2871  ret = ctxt->valueTab[ctxt->valueNr];
2872  ctxt->valueTab[ctxt->valueNr] = NULL;
2873  return (ret);
2874 }
2885 int
2886 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2887 {
2888  if (ctxt == NULL) return(-1);
2889  if (value == NULL) {
2890  /*
2891  * A NULL value typically indicates that a memory allocation failed,
2892  * so we set ctxt->error here to propagate the error.
2893  */
2894  ctxt->error = XPATH_MEMORY_ERROR;
2895  return(-1);
2896  }
2897  if (ctxt->valueNr >= ctxt->valueMax) {
2898  xmlXPathObjectPtr *tmp;
2899 
2900  if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2901  xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2902  return (-1);
2903  }
2904  tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2905  2 * ctxt->valueMax *
2906  sizeof(ctxt->valueTab[0]));
2907  if (tmp == NULL) {
2908  xmlXPathPErrMemory(ctxt, "pushing value\n");
2909  return (-1);
2910  }
2911  ctxt->valueMax *= 2;
2912  ctxt->valueTab = tmp;
2913  }
2914  ctxt->valueTab[ctxt->valueNr] = value;
2915  ctxt->value = value;
2916  return (ctxt->valueNr++);
2917 }
2918 
2928 int
2929 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2930  xmlXPathObjectPtr obj;
2931  int ret;
2932 
2933  obj = valuePop(ctxt);
2934  if (obj == NULL) {
2935  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2936  return(0);
2937  }
2938  if (obj->type != XPATH_BOOLEAN)
2939  ret = xmlXPathCastToBoolean(obj);
2940  else
2941  ret = obj->boolval;
2942  xmlXPathReleaseObject(ctxt->context, obj);
2943  return(ret);
2944 }
2945 
2955 double
2956 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2957  xmlXPathObjectPtr obj;
2958  double ret;
2959 
2960  obj = valuePop(ctxt);
2961  if (obj == NULL) {
2962  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2963  return(0);
2964  }
2965  if (obj->type != XPATH_NUMBER)
2966  ret = xmlXPathCastToNumber(obj);
2967  else
2968  ret = obj->floatval;
2969  xmlXPathReleaseObject(ctxt->context, obj);
2970  return(ret);
2971 }
2972 
2982 xmlChar *
2983 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2984  xmlXPathObjectPtr obj;
2985  xmlChar * ret;
2986 
2987  obj = valuePop(ctxt);
2988  if (obj == NULL) {
2989  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2990  return(NULL);
2991  }
2992  ret = xmlXPathCastToString(obj); /* this does required strdup */
2993  /* TODO: needs refactoring somewhere else */
2994  if (obj->stringval == ret)
2995  obj->stringval = NULL;
2996  xmlXPathReleaseObject(ctxt->context, obj);
2997  return(ret);
2998 }
2999 
3009 xmlNodeSetPtr
3010 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3011  xmlXPathObjectPtr obj;
3012  xmlNodeSetPtr ret;
3013 
3014  if (ctxt == NULL) return(NULL);
3015  if (ctxt->value == NULL) {
3016  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3017  return(NULL);
3018  }
3019  if (!xmlXPathStackIsNodeSet(ctxt)) {
3020  xmlXPathSetTypeError(ctxt);
3021  return(NULL);
3022  }
3023  obj = valuePop(ctxt);
3024  ret = obj->nodesetval;
3025 #if 0
3026  /* to fix memory leak of not clearing obj->user */
3027  if (obj->boolval && obj->user != NULL)
3028  xmlFreeNodeList((xmlNodePtr) obj->user);
3029 #endif
3030  obj->nodesetval = NULL;
3031  xmlXPathReleaseObject(ctxt->context, obj);
3032  return(ret);
3033 }
3034 
3044 void *
3045 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3046  xmlXPathObjectPtr obj;
3047  void * ret;
3048 
3049  if ((ctxt == NULL) || (ctxt->value == NULL)) {
3050  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3051  return(NULL);
3052  }
3053  if (ctxt->value->type != XPATH_USERS) {
3054  xmlXPathSetTypeError(ctxt);
3055  return(NULL);
3056  }
3057  obj = valuePop(ctxt);
3058  ret = obj->user;
3059  obj->user = NULL;
3060  xmlXPathReleaseObject(ctxt->context, obj);
3061  return(ret);
3062 }
3063 
3064 /*
3065  * Macros for accessing the content. Those should be used only by the parser,
3066  * and not exported.
3067  *
3068  * Dirty macros, i.e. one need to make assumption on the context to use them
3069  *
3070  * CUR_PTR return the current pointer to the xmlChar to be parsed.
3071  * CUR returns the current xmlChar value, i.e. a 8 bit value
3072  * in ISO-Latin or UTF-8.
3073  * This should be used internally by the parser
3074  * only to compare to ASCII values otherwise it would break when
3075  * running with UTF-8 encoding.
3076  * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3077  * to compare on ASCII based substring.
3078  * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3079  * strings within the parser.
3080  * CURRENT Returns the current char value, with the full decoding of
3081  * UTF-8 if we are using this mode. It returns an int.
3082  * NEXT Skip to the next character, this does the proper decoding
3083  * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3084  * It returns the pointer to the current xmlChar.
3085  */
3086 
3087 #define CUR (*ctxt->cur)
3088 #define SKIP(val) ctxt->cur += (val)
3089 #define NXT(val) ctxt->cur[(val)]
3090 #define CUR_PTR ctxt->cur
3091 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3092 
3093 #define COPY_BUF(l,b,i,v) \
3094  if (l == 1) b[i++] = (xmlChar) v; \
3095  else i += xmlCopyChar(l,&b[i],v)
3096 
3097 #define NEXTL(l) ctxt->cur += l
3098 
3099 #define SKIP_BLANKS \
3100  while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3101 
3102 #define CURRENT (*ctxt->cur)
3103 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3104 
3105 
3106 #ifndef DBL_DIG
3107 #define DBL_DIG 16
3108 #endif
3109 #ifndef DBL_EPSILON
3110 #define DBL_EPSILON 1E-9
3111 #endif
3112 
3113 #define UPPER_DOUBLE 1E9
3114 #define LOWER_DOUBLE 1E-5
3115 #define LOWER_DOUBLE_EXP 5
3116 
3117 #define INTEGER_DIGITS DBL_DIG
3118 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3119 #define EXPONENT_DIGITS (3 + 2)
3120 
3129 static void
3130 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3131 {
3132  switch (xmlXPathIsInf(number)) {
3133  case 1:
3134  if (buffersize > (int)sizeof("Infinity"))
3135  snprintf(buffer, buffersize, "Infinity");
3136  break;
3137  case -1:
3138  if (buffersize > (int)sizeof("-Infinity"))
3139  snprintf(buffer, buffersize, "-Infinity");
3140  break;
3141  default:
3142  if (xmlXPathIsNaN(number)) {
3143  if (buffersize > (int)sizeof("NaN"))
3144  snprintf(buffer, buffersize, "NaN");
3145  } else if (number == 0) {
3146  /* Omit sign for negative zero. */
3147  snprintf(buffer, buffersize, "0");
3148  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3149  (number == (int) number)) {
3150  char work[30];
3151  char *ptr, *cur;
3152  int value = (int) number;
3153 
3154  ptr = &buffer[0];
3155  if (value == 0) {
3156  *ptr++ = '0';
3157  } else {
3158  snprintf(work, 29, "%d", value);
3159  cur = &work[0];
3160  while ((*cur) && (ptr - buffer < buffersize)) {
3161  *ptr++ = *cur++;
3162  }
3163  }
3164  if (ptr - buffer < buffersize) {
3165  *ptr = 0;
3166  } else if (buffersize > 0) {
3167  ptr--;
3168  *ptr = 0;
3169  }
3170  } else {
3171  /*
3172  For the dimension of work,
3173  DBL_DIG is number of significant digits
3174  EXPONENT is only needed for "scientific notation"
3175  3 is sign, decimal point, and terminating zero
3176  LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3177  Note that this dimension is slightly (a few characters)
3178  larger than actually necessary.
3179  */
3180  char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3181  int integer_place, fraction_place;
3182  char *ptr;
3183  char *after_fraction;
3184  double absolute_value;
3185  int size;
3186 
3187  absolute_value = fabs(number);
3188 
3189  /*
3190  * First choose format - scientific or regular floating point.
3191  * In either case, result is in work, and after_fraction points
3192  * just past the fractional part.
3193  */
3194  if ( ((absolute_value > UPPER_DOUBLE) ||
3195  (absolute_value < LOWER_DOUBLE)) &&
3196  (absolute_value != 0.0) ) {
3197  /* Use scientific notation */
3198  integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3199  fraction_place = DBL_DIG - 1;
3200  size = snprintf(work, sizeof(work),"%*.*e",
3201  integer_place, fraction_place, number);
3202  while ((size > 0) && (work[size] != 'e')) size--;
3203 
3204  }
3205  else {
3206  /* Use regular notation */
3207  if (absolute_value > 0.0) {
3208  integer_place = (int)log10(absolute_value);
3209  if (integer_place > 0)
3210  fraction_place = DBL_DIG - integer_place - 1;
3211  else
3212  fraction_place = DBL_DIG - integer_place;
3213  } else {
3214  fraction_place = 1;
3215  }
3216  size = snprintf(work, sizeof(work), "%0.*f",
3217  fraction_place, number);
3218  }
3219 
3220  /* Remove leading spaces sometimes inserted by snprintf */
3221  while (work[0] == ' ') {
3222  for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3223  size--;
3224  }
3225 
3226  /* Remove fractional trailing zeroes */
3227  after_fraction = work + size;
3228  ptr = after_fraction;
3229  while (*(--ptr) == '0')
3230  ;
3231  if (*ptr != '.')
3232  ptr++;
3233  while ((*ptr++ = *after_fraction++) != 0);
3234 
3235  /* Finally copy result back to caller */
3236  size = strlen(work) + 1;
3237  if (size > buffersize) {
3238  work[buffersize - 1] = 0;
3239  size = buffersize;
3240  }
3241  memmove(buffer, work, size);
3242  }
3243  break;
3244  }
3245 }
3246 
3247 
3248 /************************************************************************
3249  * *
3250  * Routines to handle NodeSets *
3251  * *
3252  ************************************************************************/
3253 
3267 long
3268 xmlXPathOrderDocElems(xmlDocPtr doc) {
3269  ptrdiff_t count = 0;
3270  xmlNodePtr cur;
3271 
3272  if (doc == NULL)
3273  return(-1);
3274  cur = doc->children;
3275  while (cur != NULL) {
3276  if (cur->type == XML_ELEMENT_NODE) {
3277  cur->content = (void *) (-(++count));
3278  if (cur->children != NULL) {
3279  cur = cur->children;
3280  continue;
3281  }
3282  }
3283  if (cur->next != NULL) {
3284  cur = cur->next;
3285  continue;
3286  }
3287  do {
3288  cur = cur->parent;
3289  if (cur == NULL)
3290  break;
3291  if (cur == (xmlNodePtr) doc) {
3292  cur = NULL;
3293  break;
3294  }
3295  if (cur->next != NULL) {
3296  cur = cur->next;
3297  break;
3298  }
3299  } while (cur != NULL);
3300  }
3301  return((long) count);
3302 }
3303 
3314 int
3315 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3316  int depth1, depth2;
3317  int attr1 = 0, attr2 = 0;
3318  xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3319  xmlNodePtr cur, root;
3320 
3321  if ((node1 == NULL) || (node2 == NULL))
3322  return(-2);
3323  /*
3324  * a couple of optimizations which will avoid computations in most cases
3325  */
3326  if (node1 == node2) /* trivial case */
3327  return(0);
3328  if (node1->type == XML_ATTRIBUTE_NODE) {
3329  attr1 = 1;
3330  attrNode1 = node1;
3331  node1 = node1->parent;
3332  }
3333  if (node2->type == XML_ATTRIBUTE_NODE) {
3334  attr2 = 1;
3335  attrNode2 = node2;
3336  node2 = node2->parent;
3337  }
3338  if (node1 == node2) {
3339  if (attr1 == attr2) {
3340  /* not required, but we keep attributes in order */
3341  if (attr1 != 0) {
3342  cur = attrNode2->prev;
3343  while (cur != NULL) {
3344  if (cur == attrNode1)
3345  return (1);
3346  cur = cur->prev;
3347  }
3348  return (-1);
3349  }
3350  return(0);
3351  }
3352  if (attr2 == 1)
3353  return(1);
3354  return(-1);
3355  }
3356  if ((node1->type == XML_NAMESPACE_DECL) ||
3357  (node2->type == XML_NAMESPACE_DECL))
3358  return(1);
3359  if (node1 == node2->prev)
3360  return(1);
3361  if (node1 == node2->next)
3362  return(-1);
3363 
3364  /*
3365  * Speedup using document order if available.
3366  */
3367  if ((node1->type == XML_ELEMENT_NODE) &&
3368  (node2->type == XML_ELEMENT_NODE) &&
3369  (0 > (ptrdiff_t) node1->content) &&
3370  (0 > (ptrdiff_t) node2->content) &&
3371  (node1->doc == node2->doc)) {
3372  ptrdiff_t l1, l2;
3373 
3374  l1 = -((ptrdiff_t) node1->content);
3375  l2 = -((ptrdiff_t) node2->content);
3376  if (l1 < l2)
3377  return(1);
3378  if (l1 > l2)
3379  return(-1);
3380  }
3381 
3382  /*
3383  * compute depth to root
3384  */
3385  for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3386  if (cur->parent == node1)
3387  return(1);
3388  depth2++;
3389  }
3390  root = cur;
3391  for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3392  if (cur->parent == node2)
3393  return(-1);
3394  depth1++;
3395  }
3396  /*
3397  * Distinct document (or distinct entities :-( ) case.
3398  */
3399  if (root != cur) {
3400  return(-2);
3401  }
3402  /*
3403  * get the nearest common ancestor.
3404  */
3405  while (depth1 > depth2) {
3406  depth1--;
3407  node1 = node1->parent;
3408  }
3409  while (depth2 > depth1) {
3410  depth2--;
3411  node2 = node2->parent;
3412  }
3413  while (node1->parent != node2->parent) {
3414  node1 = node1->parent;
3415  node2 = node2->parent;
3416  /* should not happen but just in case ... */
3417  if ((node1 == NULL) || (node2 == NULL))
3418  return(-2);
3419  }
3420  /*
3421  * Find who's first.
3422  */
3423  if (node1 == node2->prev)
3424  return(1);
3425  if (node1 == node2->next)
3426  return(-1);
3427  /*
3428  * Speedup using document order if available.
3429  */
3430  if ((node1->type == XML_ELEMENT_NODE) &&
3431  (node2->type == XML_ELEMENT_NODE) &&
3432  (0 > (ptrdiff_t) node1->content) &&
3433  (0 > (ptrdiff_t) node2->content) &&
3434  (node1->doc == node2->doc)) {
3435  ptrdiff_t l1, l2;
3436 
3437  l1 = -((ptrdiff_t) node1->content);
3438  l2 = -((ptrdiff_t) node2->content);
3439  if (l1 < l2)
3440  return(1);
3441  if (l1 > l2)
3442  return(-1);
3443  }
3444 
3445  for (cur = node1->next;cur != NULL;cur = cur->next)
3446  if (cur == node2)
3447  return(1);
3448  return(-1); /* assume there is no sibling list corruption */
3449 }
3450 
3457 void
3458 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3459 #ifndef WITH_TIM_SORT
3460  int i, j, incr, len;
3461  xmlNodePtr tmp;
3462 #endif
3463 
3464  if (set == NULL)
3465  return;
3466 
3467 #ifndef WITH_TIM_SORT
3468  /*
3469  * Use the old Shell's sort implementation to sort the node-set
3470  * Timsort ought to be quite faster
3471  */
3472  len = set->nodeNr;
3473  for (incr = len / 2; incr > 0; incr /= 2) {
3474  for (i = incr; i < len; i++) {
3475  j = i - incr;
3476  while (j >= 0) {
3477 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3478  if (xmlXPathCmpNodesExt(set->nodeTab[j],
3479  set->nodeTab[j + incr]) == -1)
3480 #else
3481  if (xmlXPathCmpNodes(set->nodeTab[j],
3482  set->nodeTab[j + incr]) == -1)
3483 #endif
3484  {
3485  tmp = set->nodeTab[j];
3486  set->nodeTab[j] = set->nodeTab[j + incr];
3487  set->nodeTab[j + incr] = tmp;
3488  j -= incr;
3489  } else
3490  break;
3491  }
3492  }
3493  }
3494 #else /* WITH_TIM_SORT */
3495  libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3496 #endif /* WITH_TIM_SORT */
3497 }
3498 
3499 #define XML_NODESET_DEFAULT 10
3500 
3511 static xmlNodePtr
3512 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3513  xmlNsPtr cur;
3514 
3515  if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3516  return(NULL);
3517  if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3518  return((xmlNodePtr) ns);
3519 
3520  /*
3521  * Allocate a new Namespace and fill the fields.
3522  */
3523  cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3524  if (cur == NULL) {
3525  xmlXPathErrMemory(NULL, "duplicating namespace\n");
3526  return(NULL);
3527  }
3528  memset(cur, 0, sizeof(xmlNs));
3529  cur->type = XML_NAMESPACE_DECL;
3530  if (ns->href != NULL)
3531  cur->href = xmlStrdup(ns->href);
3532  if (ns->prefix != NULL)
3533  cur->prefix = xmlStrdup(ns->prefix);
3534  cur->next = (xmlNsPtr) node;
3535  return((xmlNodePtr) cur);
3536 }
3537 
3546 void
3547 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3548  if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3549  return;
3550 
3551  if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3552  if (ns->href != NULL)
3553  xmlFree((xmlChar *)ns->href);
3554  if (ns->prefix != NULL)
3555  xmlFree((xmlChar *)ns->prefix);
3556  xmlFree(ns);
3557  }
3558 }
3559 
3568 xmlNodeSetPtr
3569 xmlXPathNodeSetCreate(xmlNodePtr val) {
3570  xmlNodeSetPtr ret;
3571 
3572  ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3573  if (ret == NULL) {
3574  xmlXPathErrMemory(NULL, "creating nodeset\n");
3575  return(NULL);
3576  }
3577  memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3578  if (val != NULL) {
3579  ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3580  sizeof(xmlNodePtr));
3581  if (ret->nodeTab == NULL) {
3582  xmlXPathErrMemory(NULL, "creating nodeset\n");
3583  xmlFree(ret);
3584  return(NULL);
3585  }
3586  memset(ret->nodeTab, 0 ,
3587  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3588  ret->nodeMax = XML_NODESET_DEFAULT;
3589  if (val->type == XML_NAMESPACE_DECL) {
3590  xmlNsPtr ns = (xmlNsPtr) val;
3591 
3592  /* TODO: Check memory error. */
3593  ret->nodeTab[ret->nodeNr++] =
3594  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3595  } else
3596  ret->nodeTab[ret->nodeNr++] = val;
3597  }
3598  return(ret);
3599 }
3600 
3610 int
3611 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3612  int i;
3613 
3614  if ((cur == NULL) || (val == NULL)) return(0);
3615  if (val->type == XML_NAMESPACE_DECL) {
3616  for (i = 0; i < cur->nodeNr; i++) {
3617  if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3618  xmlNsPtr ns1, ns2;
3619 
3620  ns1 = (xmlNsPtr) val;
3621  ns2 = (xmlNsPtr) cur->nodeTab[i];
3622  if (ns1 == ns2)
3623  return(1);
3624  if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3625  (xmlStrEqual(ns1->prefix, ns2->prefix)))
3626  return(1);
3627  }
3628  }
3629  } else {
3630  for (i = 0; i < cur->nodeNr; i++) {
3631  if (cur->nodeTab[i] == val)
3632  return(1);
3633  }
3634  }
3635  return(0);
3636 }
3637 
3648 int
3649 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3650  int i;
3651 
3652 
3653  if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3654  (ns->type != XML_NAMESPACE_DECL) ||
3655  (node->type != XML_ELEMENT_NODE))
3656  return(-1);
3657 
3658  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3659  /*
3660  * prevent duplicates
3661  */
3662  for (i = 0;i < cur->nodeNr;i++) {
3663  if ((cur->nodeTab[i] != NULL) &&
3664  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3665  (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3666  (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3667  return(0);
3668  }
3669 
3670  /*
3671  * grow the nodeTab if needed
3672  */
3673  if (cur->nodeMax == 0) {
3674  cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3675  sizeof(xmlNodePtr));
3676  if (cur->nodeTab == NULL) {
3677  xmlXPathErrMemory(NULL, "growing nodeset\n");
3678  return(-1);
3679  }
3680  memset(cur->nodeTab, 0 ,
3681  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3682  cur->nodeMax = XML_NODESET_DEFAULT;
3683  } else if (cur->nodeNr == cur->nodeMax) {
3684  xmlNodePtr *temp;
3685 
3686  if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3687  xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3688  return(-1);
3689  }
3690  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3691  sizeof(xmlNodePtr));
3692  if (temp == NULL) {
3693  xmlXPathErrMemory(NULL, "growing nodeset\n");
3694  return(-1);
3695  }
3696  cur->nodeMax *= 2;
3697  cur->nodeTab = temp;
3698  }
3699  /* TODO: Check memory error. */
3700  cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3701  return(0);
3702 }
3703 
3713 int
3714 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3715  int i;
3716 
3717  if ((cur == NULL) || (val == NULL)) return(-1);
3718 
3719  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3720  /*
3721  * prevent duplicates
3722  */
3723  for (i = 0;i < cur->nodeNr;i++)
3724  if (cur->nodeTab[i] == val) return(0);
3725 
3726  /*
3727  * grow the nodeTab if needed
3728  */
3729  if (cur->nodeMax == 0) {
3730  cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3731  sizeof(xmlNodePtr));
3732  if (cur->nodeTab == NULL) {
3733  xmlXPathErrMemory(NULL, "growing nodeset\n");
3734  return(-1);
3735  }
3736  memset(cur->nodeTab, 0 ,
3737  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3738  cur->nodeMax = XML_NODESET_DEFAULT;
3739  } else if (cur->nodeNr == cur->nodeMax) {
3740  xmlNodePtr *temp;
3741 
3742  if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3743  xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3744  return(-1);
3745  }
3746  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3747  sizeof(xmlNodePtr));
3748  if (temp == NULL) {
3749  xmlXPathErrMemory(NULL, "growing nodeset\n");
3750  return(-1);
3751  }
3752  cur->nodeMax *= 2;
3753  cur->nodeTab = temp;
3754  }
3755  if (val->type == XML_NAMESPACE_DECL) {
3756  xmlNsPtr ns = (xmlNsPtr) val;
3757 
3758  /* TODO: Check memory error. */
3759  cur->nodeTab[cur->nodeNr++] =
3760  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3761  } else
3762  cur->nodeTab[cur->nodeNr++] = val;
3763  return(0);
3764 }
3765 
3776 int
3777 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3778  if ((cur == NULL) || (val == NULL)) return(-1);
3779 
3780  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3781  /*
3782  * grow the nodeTab if needed
3783  */
3784  if (cur->nodeMax == 0) {
3785  cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3786  sizeof(xmlNodePtr));
3787  if (cur->nodeTab == NULL) {
3788  xmlXPathErrMemory(NULL, "growing nodeset\n");
3789  return(-1);
3790  }
3791  memset(cur->nodeTab, 0 ,
3792  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3793  cur->nodeMax = XML_NODESET_DEFAULT;
3794  } else if (cur->nodeNr == cur->nodeMax) {
3795  xmlNodePtr *temp;
3796 
3797  if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3798  xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3799  return(-1);
3800  }
3801  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3802  sizeof(xmlNodePtr));
3803  if (temp == NULL) {
3804  xmlXPathErrMemory(NULL, "growing nodeset\n");
3805  return(-1);
3806  }
3807  cur->nodeTab = temp;
3808  cur->nodeMax *= 2;
3809  }
3810  if (val->type == XML_NAMESPACE_DECL) {
3811  xmlNsPtr ns = (xmlNsPtr) val;
3812 
3813  /* TODO: Check memory error. */
3814  cur->nodeTab[cur->nodeNr++] =
3815  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3816  } else
3817  cur->nodeTab[cur->nodeNr++] = val;
3818  return(0);
3819 }
3820 
3831 xmlNodeSetPtr
3832 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3833  int i, j, initNr, skip;
3834  xmlNodePtr n1, n2;
3835 
3836  if (val2 == NULL) return(val1);
3837  if (val1 == NULL) {
3838  val1 = xmlXPathNodeSetCreate(NULL);
3839  if (val1 == NULL)
3840  return (NULL);
3841 #if 0
3842  /*
3843  * TODO: The optimization won't work in every case, since
3844  * those nasty namespace nodes need to be added with
3845  * xmlXPathNodeSetDupNs() to the set; thus a pure
3846  * memcpy is not possible.
3847  * If there was a flag on the nodesetval, indicating that
3848  * some temporary nodes are in, that would be helpful.
3849  */
3850  /*
3851  * Optimization: Create an equally sized node-set
3852  * and memcpy the content.
3853  */
3854  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3855  if (val1 == NULL)
3856  return(NULL);
3857  if (val2->nodeNr != 0) {
3858  if (val2->nodeNr == 1)
3859  *(val1->nodeTab) = *(val2->nodeTab);
3860  else {
3861  memcpy(val1->nodeTab, val2->nodeTab,
3862  val2->nodeNr * sizeof(xmlNodePtr));
3863  }
3864  val1->nodeNr = val2->nodeNr;
3865  }
3866  return(val1);
3867 #endif
3868  }
3869 
3870  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3871  initNr = val1->nodeNr;
3872 
3873  for (i = 0;i < val2->nodeNr;i++) {
3874  n2 = val2->nodeTab[i];
3875  /*
3876  * check against duplicates
3877  */
3878  skip = 0;
3879  for (j = 0; j < initNr; j++) {
3880  n1 = val1->nodeTab[j];
3881  if (n1 == n2) {
3882  skip = 1;
3883  break;
3884  } else if ((n1->type == XML_NAMESPACE_DECL) &&
3885  (n2->type == XML_NAMESPACE_DECL)) {
3886  if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3887  (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3888  ((xmlNsPtr) n2)->prefix)))
3889  {
3890  skip = 1;
3891  break;
3892  }
3893  }
3894  }
3895  if (skip)
3896  continue;
3897 
3898  /*
3899  * grow the nodeTab if needed
3900  */
3901  if (val1->nodeMax == 0) {
3902  val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3903  sizeof(xmlNodePtr));
3904  if (val1->nodeTab == NULL) {
3905  xmlXPathErrMemory(NULL, "merging nodeset\n");
3906  return(NULL);
3907  }
3908  memset(val1->nodeTab, 0 ,
3909  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3910  val1->nodeMax = XML_NODESET_DEFAULT;
3911  } else if (val1->nodeNr == val1->nodeMax) {
3912  xmlNodePtr *temp;
3913 
3914  if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3915  xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3916  return(NULL);
3917  }
3918  temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3919  sizeof(xmlNodePtr));
3920  if (temp == NULL) {
3921  xmlXPathErrMemory(NULL, "merging nodeset\n");
3922  return(NULL);
3923  }
3924  val1->nodeTab = temp;
3925  val1->nodeMax *= 2;
3926  }
3927  if (n2->type == XML_NAMESPACE_DECL) {
3928  xmlNsPtr ns = (xmlNsPtr) n2;
3929 
3930  /* TODO: Check memory error. */
3931  val1->nodeTab[val1->nodeNr++] =
3932  xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933  } else
3934  val1->nodeTab[val1->nodeNr++] = n2;
3935  }
3936 
3937  return(val1);
3938 }
3939 
3940 
3951 static xmlNodeSetPtr
3952 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3953 {
3954  {
3955  int i, j, initNbSet1;
3956  xmlNodePtr n1, n2;
3957 
3958  initNbSet1 = set1->nodeNr;
3959  for (i = 0;i < set2->nodeNr;i++) {
3960  n2 = set2->nodeTab[i];
3961  /*
3962  * Skip duplicates.
3963  */
3964  for (j = 0; j < initNbSet1; j++) {
3965  n1 = set1->nodeTab[j];
3966  if (n1 == n2) {
3967  goto skip_node;
3968  } else if ((n1->type == XML_NAMESPACE_DECL) &&
3969  (n2->type == XML_NAMESPACE_DECL))
3970  {
3971  if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3972  (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3973  ((xmlNsPtr) n2)->prefix)))
3974  {
3975  /*
3976  * Free the namespace node.
3977  */
3978  set2->nodeTab[i] = NULL;
3979  xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3980  goto skip_node;
3981  }
3982  }
3983  }
3984  /*
3985  * grow the nodeTab if needed
3986  */
3987  if (set1->nodeMax == 0) {
3988  set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3989  XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3990  if (set1->nodeTab == NULL) {
3991  xmlXPathErrMemory(NULL, "merging nodeset\n");
3992  return(NULL);
3993  }
3994  memset(set1->nodeTab, 0,
3995  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3996  set1->nodeMax = XML_NODESET_DEFAULT;
3997  } else if (set1->nodeNr >= set1->nodeMax) {
3998  xmlNodePtr *temp;
3999 
4000  if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4001  xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4002  return(NULL);
4003  }
4004  temp = (xmlNodePtr *) xmlRealloc(
4005  set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4006  if (temp == NULL) {
4007  xmlXPathErrMemory(NULL, "merging nodeset\n");
4008  return(NULL);
4009  }
4010  set1->nodeTab = temp;
4011  set1->nodeMax *= 2;
4012  }
4013  set1->nodeTab[set1->nodeNr++] = n2;
4014 skip_node:
4015  {}
4016  }
4017  }
4018  set2->nodeNr = 0;
4019  return(set1);
4020 }
4021 
4032 static xmlNodeSetPtr
4033 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4034 {
4035  {
4036  int i;
4037  xmlNodePtr n2;
4038 
4039  for (i = 0;i < set2->nodeNr;i++) {
4040  n2 = set2->nodeTab[i];
4041  if (set1->nodeMax == 0) {
4042  set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4043  XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4044  if (set1->nodeTab == NULL) {
4045  xmlXPathErrMemory(NULL, "merging nodeset\n");
4046  return(NULL);
4047  }
4048  memset(set1->nodeTab, 0,
4049  XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4050  set1->nodeMax = XML_NODESET_DEFAULT;
4051  } else if (set1->nodeNr >= set1->nodeMax) {
4052  xmlNodePtr *temp;
4053 
4054  if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4055  xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4056  return(NULL);
4057  }
4058  temp = (xmlNodePtr *) xmlRealloc(
4059  set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4060  if (temp == NULL) {
4061  xmlXPathErrMemory(NULL, "merging nodeset\n");
4062  return(NULL);
4063  }
4064  set1->nodeTab = temp;
4065  set1->nodeMax *= 2;
4066  }
4067  set1->nodeTab[set1->nodeNr++] = n2;
4068  }
4069  }
4070  set2->nodeNr = 0;
4071  return(set1);
4072 }
4073 
4081 void
4082 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4083  int i;
4084 
4085  if (cur == NULL) return;
4086  if (val == NULL) return;
4087 
4088  /*
4089  * find node in nodeTab
4090  */
4091  for (i = 0;i < cur->nodeNr;i++)
4092  if (cur->nodeTab[i] == val) break;
4093 
4094  if (i >= cur->nodeNr) { /* not found */
4095 #ifdef DEBUG
4097  "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4098  val->name);
4099 #endif
4100  return;
4101  }
4102  if ((cur->nodeTab[i] != NULL) &&
4103  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4104  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4105  cur->nodeNr--;
4106  for (;i < cur->nodeNr;i++)
4107  cur->nodeTab[i] = cur->nodeTab[i + 1];
4108  cur->nodeTab[cur->nodeNr] = NULL;
4109 }
4110 
4118 void
4119 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4120  if (cur == NULL) return;
4121  if (val >= cur->nodeNr) return;
4122  if ((cur->nodeTab[val] != NULL) &&
4123  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4124  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4125  cur->nodeNr--;
4126  for (;val < cur->nodeNr;val++)
4127  cur->nodeTab[val] = cur->nodeTab[val + 1];
4128  cur->nodeTab[cur->nodeNr] = NULL;
4129 }
4130 
4137 void
4138 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4139  if (obj == NULL) return;
4140  if (obj->nodeTab != NULL) {
4141  int i;
4142 
4143  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4144  for (i = 0;i < obj->nodeNr;i++)
4145  if ((obj->nodeTab[i] != NULL) &&
4146  (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4147  xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4148  xmlFree(obj->nodeTab);
4149  }
4150  xmlFree(obj);
4151 }
4152 
4162 static void
4163 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4164 {
4165  if ((set == NULL) || (pos >= set->nodeNr))
4166  return;
4167  else if ((hasNsNodes)) {
4168  int i;
4169  xmlNodePtr node;
4170 
4171  for (i = pos; i < set->nodeNr; i++) {
4172  node = set->nodeTab[i];
4173  if ((node != NULL) &&
4174  (node->type == XML_NAMESPACE_DECL))
4175  xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4176  }
4177  }
4178  set->nodeNr = pos;
4179 }
4180 
4189 static void
4190 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4191 {
4192  xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4193 }
4194 
4203 static void
4204 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4205 {
4206  int i;
4207  xmlNodePtr node;
4208 
4209  if ((set == NULL) || (set->nodeNr <= 1))
4210  return;
4211  for (i = 0; i < set->nodeNr - 1; i++) {
4212  node = set->nodeTab[i];
4213  if ((node != NULL) &&
4214  (node->type == XML_NAMESPACE_DECL))
4215  xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4216  }
4217  set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4218  set->nodeNr = 1;
4219 }
4220 
4228 static void
4229 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4230  int i;
4231 
4232  if (obj == NULL) return;
4233 
4234  if (obj->nodeTab != NULL) {
4235  for (i = 0;i < obj->nodeNr;i++) {
4236  if (obj->nodeTab[i] != NULL) {
4237  if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4238  xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4239  } else {
4240  xmlFreeNodeList(obj->nodeTab[i]);
4241  }
4242  }
4243  }
4244  xmlFree(obj->nodeTab);
4245  }
4246  xmlFree(obj);
4247 }
4248 
4249 #if defined(DEBUG) || defined(DEBUG_STEP)
4250 
4257 void
4258 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4259  int i;
4260 
4262  if (obj == NULL) {
4263  fprintf(output, "NodeSet == NULL !\n");
4264  return;
4265  }
4266  if (obj->nodeNr == 0) {
4267  fprintf(output, "NodeSet is empty\n");
4268  return;
4269  }
4270  if (obj->nodeTab == NULL) {
4271  fprintf(output, " nodeTab == NULL !\n");
4272  return;
4273  }
4274  for (i = 0; i < obj->nodeNr; i++) {
4275  if (obj->nodeTab[i] == NULL) {
4276  fprintf(output, " NULL !\n");
4277  return;
4278  }
4279  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4280  (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4281  fprintf(output, " /");
4282  else if (obj->nodeTab[i]->name == NULL)
4283  fprintf(output, " noname!");
4284  else fprintf(output, " %s", obj->nodeTab[i]->name);
4285  }
4286  fprintf(output, "\n");
4287 }
4288 #endif
4289 
4299 xmlXPathObjectPtr
4300 xmlXPathNewNodeSet(xmlNodePtr val) {
4301  xmlXPathObjectPtr ret;
4302 
4303  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304  if (ret == NULL) {
4305  xmlXPathErrMemory(NULL, "creating nodeset\n");
4306  return(NULL);
4307  }
4308  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4309  ret->type = XPATH_NODESET;
4310  ret->boolval = 0;
4311  /* TODO: Check memory error. */
4312  ret->nodesetval = xmlXPathNodeSetCreate(val);
4313  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4314 #ifdef XP_DEBUG_OBJ_USAGE
4315  xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4316 #endif
4317  return(ret);
4318 }
4319 
4329 xmlXPathObjectPtr
4330 xmlXPathNewValueTree(xmlNodePtr val) {
4331  xmlXPathObjectPtr ret;
4332 
4333  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4334  if (ret == NULL) {
4335  xmlXPathErrMemory(NULL, "creating result value tree\n");
4336  return(NULL);
4337  }
4338  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4339  ret->type = XPATH_XSLT_TREE;
4340  ret->boolval = 1;
4341  ret->user = (void *) val;
4342  ret->nodesetval = xmlXPathNodeSetCreate(val);
4343 #ifdef XP_DEBUG_OBJ_USAGE
4344  xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4345 #endif
4346  return(ret);
4347 }
4348 
4358 xmlXPathObjectPtr
4359 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4360 {
4361  xmlXPathObjectPtr ret;
4362  int i;
4363 
4364  if (val == NULL)
4365  ret = NULL;
4366  else if (val->nodeTab == NULL)
4367  ret = xmlXPathNewNodeSet(NULL);
4368  else {
4369  ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4370  if (ret) {
4371  for (i = 1; i < val->nodeNr; ++i) {
4372  /* TODO: Propagate memory error. */
4373  if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4374  < 0) break;
4375  }
4376  }
4377  }
4378 
4379  return (ret);
4380 }
4381 
4390 xmlXPathObjectPtr
4391 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4392  xmlXPathObjectPtr ret;
4393 
4394  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4395  if (ret == NULL) {
4396  xmlXPathErrMemory(NULL, "creating node set object\n");
4397  return(NULL);
4398  }
4399  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4400  ret->type = XPATH_NODESET;
4401  ret->nodesetval = val;
4402 #ifdef XP_DEBUG_OBJ_USAGE
4403  xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4404 #endif
4405  return(ret);
4406 }
4407 
4415 void
4416 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4417  if (obj == NULL) return;
4418 #ifdef XP_DEBUG_OBJ_USAGE
4419  xmlXPathDebugObjUsageReleased(NULL, obj->type);
4420 #endif
4421  xmlFree(obj);
4422 }
4423 
4435 xmlNodeSetPtr
4436 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4437  xmlNodeSetPtr ret;
4438  int i, l1;
4439  xmlNodePtr cur;
4440 
4441  if (xmlXPathNodeSetIsEmpty(nodes2))
4442  return(nodes1);
4443 
4444  /* TODO: Check memory error. */
4445  ret = xmlXPathNodeSetCreate(NULL);
4446  if (xmlXPathNodeSetIsEmpty(nodes1))
4447  return(ret);
4448 
4449  l1 = xmlXPathNodeSetGetLength(nodes1);
4450 
4451  for (i = 0; i < l1; i++) {
4452  cur = xmlXPathNodeSetItem(nodes1, i);
4453  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4454  /* TODO: Propagate memory error. */
4455  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4456  break;
4457  }
4458  }
4459  return(ret);
4460 }
4461 
4473 xmlNodeSetPtr
4474 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475  xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4476  int i, l1;
4477  xmlNodePtr cur;
4478 
4479  if (ret == NULL)
4480  return(ret);
4481  if (xmlXPathNodeSetIsEmpty(nodes1))
4482  return(ret);
4483  if (xmlXPathNodeSetIsEmpty(nodes2))
4484  return(ret);
4485 
4486  l1 = xmlXPathNodeSetGetLength(nodes1);
4487 
4488  for (i = 0; i < l1; i++) {
4489  cur = xmlXPathNodeSetItem(nodes1, i);
4490  if (xmlXPathNodeSetContains(nodes2, cur)) {
4491  /* TODO: Propagate memory error. */
4492  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4493  break;
4494  }
4495  }
4496  return(ret);
4497 }
4498 
4509 xmlNodeSetPtr
4510 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4511  xmlNodeSetPtr ret;
4513  int i, l;
4514  xmlChar * strval;
4515  xmlNodePtr cur;
4516 
4517  if (xmlXPathNodeSetIsEmpty(nodes))
4518  return(nodes);
4519 
4520  ret = xmlXPathNodeSetCreate(NULL);
4521  if (ret == NULL)
4522  return(ret);
4523  l = xmlXPathNodeSetGetLength(nodes);
4524  hash = xmlHashCreate (l);
4525  for (i = 0; i < l; i++) {
4526  cur = xmlXPathNodeSetItem(nodes, i);
4527  strval = xmlXPathCastNodeToString(cur);
4528  if (xmlHashLookup(hash, strval) == NULL) {
4530  /* TODO: Propagate memory error. */
4531  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4532  break;
4533  } else {
4534  xmlFree(strval);
4535  }
4536  }
4538  return(ret);
4539 }
4540 
4553 xmlNodeSetPtr
4554 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4555  if (xmlXPathNodeSetIsEmpty(nodes))
4556  return(nodes);
4557 
4558  xmlXPathNodeSetSort(nodes);
4559  return(xmlXPathDistinctSorted(nodes));
4560 }
4561 
4573 int
4574 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4575  int i, l;
4576  xmlNodePtr cur;
4577 
4578  if (xmlXPathNodeSetIsEmpty(nodes1) ||
4579  xmlXPathNodeSetIsEmpty(nodes2))
4580  return(0);
4581 
4582  l = xmlXPathNodeSetGetLength(nodes1);
4583  for (i = 0; i < l; i++) {
4584  cur = xmlXPathNodeSetItem(nodes1, i);
4585  if (xmlXPathNodeSetContains(nodes2, cur))
4586  return(1);
4587  }
4588  return(0);
4589 }
4590 
4603 xmlNodeSetPtr
4604 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4605  int i, l;
4606  xmlNodePtr cur;
4607  xmlNodeSetPtr ret;
4608 
4609  if (node == NULL)
4610  return(nodes);
4611 
4612  ret = xmlXPathNodeSetCreate(NULL);
4613  if (ret == NULL)
4614  return(ret);
4615  if (xmlXPathNodeSetIsEmpty(nodes) ||
4616  (!xmlXPathNodeSetContains(nodes, node)))
4617  return(ret);
4618 
4619  l = xmlXPathNodeSetGetLength(nodes);
4620  for (i = 0; i < l; i++) {
4621  cur = xmlXPathNodeSetItem(nodes, i);
4622  if (cur == node)
4623  break;
4624  /* TODO: Propagate memory error. */
4625  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4626  break;
4627  }
4628  return(ret);
4629 }
4630 
4645 xmlNodeSetPtr
4646 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4647  xmlXPathNodeSetSort(nodes);
4648  return(xmlXPathNodeLeadingSorted(nodes, node));
4649 }
4650 
4663 xmlNodeSetPtr
4664 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4665  if (xmlXPathNodeSetIsEmpty(nodes2))
4666  return(nodes1);
4667  return(xmlXPathNodeLeadingSorted(nodes1,
4668  xmlXPathNodeSetItem(nodes2, 1)));
4669 }
4670 
4685 xmlNodeSetPtr
4686 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4687  if (xmlXPathNodeSetIsEmpty(nodes2))
4688  return(nodes1);
4689  if (xmlXPathNodeSetIsEmpty(nodes1))
4690  return(xmlXPathNodeSetCreate(NULL));
4691  xmlXPathNodeSetSort(nodes1);
4692  xmlXPathNodeSetSort(nodes2);
4693  return(xmlXPathNodeLeadingSorted(nodes1,
4694  xmlXPathNodeSetItem(nodes2, 1)));
4695 }
4696 
4709 xmlNodeSetPtr
4710 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4711  int i, l;
4712  xmlNodePtr cur;
4713  xmlNodeSetPtr ret;
4714 
4715  if (node == NULL)
4716  return(nodes);
4717 
4718  ret = xmlXPathNodeSetCreate(NULL);
4719  if (ret == NULL)
4720  return(ret);
4721  if (xmlXPathNodeSetIsEmpty(nodes) ||
4722  (!xmlXPathNodeSetContains(nodes, node)))
4723  return(ret);
4724 
4725  l = xmlXPathNodeSetGetLength(nodes);
4726  for (i = l - 1; i >= 0; i--) {
4727  cur = xmlXPathNodeSetItem(nodes, i);
4728  if (cur == node)
4729  break;
4730  /* TODO: Propagate memory error. */
4731  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4732  break;
4733  }
4734  xmlXPathNodeSetSort(ret); /* bug 413451 */
4735  return(ret);
4736 }
4737 
4752 xmlNodeSetPtr
4753 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4754  xmlXPathNodeSetSort(nodes);
4755  return(xmlXPathNodeTrailingSorted(nodes, node));
4756 }
4757 
4770 xmlNodeSetPtr
4771 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4772  if (xmlXPathNodeSetIsEmpty(nodes2))
4773  return(nodes1);
4774  return(xmlXPathNodeTrailingSorted(nodes1,
4775  xmlXPathNodeSetItem(nodes2, 0)));
4776 }
4777 
4792 xmlNodeSetPtr
4793 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4794  if (xmlXPathNodeSetIsEmpty(nodes2))
4795  return(nodes1);
4796  if (xmlXPathNodeSetIsEmpty(nodes1))
4797  return(xmlXPathNodeSetCreate(NULL));
4798  xmlXPathNodeSetSort(nodes1);
4799  xmlXPathNodeSetSort(nodes2);
4800  return(xmlXPathNodeTrailingSorted(nodes1,
4801  xmlXPathNodeSetItem(nodes2, 0)));
4802 }
4803 
4804 /************************************************************************
4805  * *
4806  * Routines to handle extra functions *
4807  * *
4808  ************************************************************************/
4809 
4820 int
4821 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4822  xmlXPathFunction f) {
4823  return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4824 }
4825 
4837 int
4838 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4839  const xmlChar *ns_uri, xmlXPathFunction f) {
4840  if (ctxt == NULL)
4841  return(-1);
4842  if (name == NULL)
4843  return(-1);
4844 
4845  if (ctxt->funcHash == NULL)
4846  ctxt->funcHash = xmlHashCreate(0);
4847  if (ctxt->funcHash == NULL)
4848  return(-1);
4849  if (f == NULL)
4850  return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4852  return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4854 }
4855 
4864 void
4865 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4866  xmlXPathFuncLookupFunc f,
4867  void *funcCtxt) {
4868  if (ctxt == NULL)
4869  return;
4870  ctxt->funcLookupFunc = f;
4871  ctxt->funcLookupData = funcCtxt;
4872 }
4873 
4884 xmlXPathFunction
4885 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4886  if (ctxt == NULL)
4887  return (NULL);
4888 
4889  if (ctxt->funcLookupFunc != NULL) {
4890  xmlXPathFunction ret;
4891  xmlXPathFuncLookupFunc f;
4892 
4893  f = ctxt->funcLookupFunc;
4894  ret = f(ctxt->funcLookupData, name, NULL);
4895  if (ret != NULL)
4896  return(ret);
4897  }
4898  return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4899 }
4900 
4912 xmlXPathFunction
4913 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4914  const xmlChar *ns_uri) {
4915  xmlXPathFunction ret;
4916 
4917  if (ctxt == NULL)
4918  return(NULL);
4919  if (name == NULL)
4920  return(NULL);
4921 
4922  if (ctxt->funcLookupFunc != NULL) {
4923  xmlXPathFuncLookupFunc f;
4924 
4925  f = ctxt->funcLookupFunc;
4926  ret = f(ctxt->funcLookupData, name, ns_uri);
4927  if (ret != NULL)
4928  return(ret);
4929  }
4930 
4931  if (ctxt->funcHash == NULL)
4932  return(NULL);
4933 
4935  ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4937  return(ret);
4938 }
4939 
4946 void
4947 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4948  if (ctxt == NULL)
4949  return;
4950 
4951  xmlHashFree(ctxt->funcHash, NULL);
4952  ctxt->funcHash = NULL;
4953 }
4954 
4955 /************************************************************************
4956  * *
4957  * Routines to handle Variables *
4958  * *
4959  ************************************************************************/
4960 
4972 int
4973 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4974  xmlXPathObjectPtr value) {
4975  return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4976 }
4977 
4990 int
4991 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4992  const xmlChar *ns_uri,
4993  xmlXPathObjectPtr value) {
4994  if (ctxt == NULL)
4995  return(-1);
4996  if (name == NULL)
4997  return(-1);
4998 
4999  if (ctxt->varHash == NULL)
5000  ctxt->varHash = xmlHashCreate(0);
5001  if (ctxt->varHash == NULL)
5002  return(-1);
5003  if (value == NULL)
5004  return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5005  xmlXPathFreeObjectEntry));
5006  return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5007  (void *) value, xmlXPathFreeObjectEntry));
5008 }
5009 
5018 void
5019 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5020  xmlXPathVariableLookupFunc f, void *data) {
5021  if (ctxt == NULL)
5022  return;
5023  ctxt->varLookupFunc = f;
5024  ctxt->varLookupData = data;
5025 }
5026 
5037 xmlXPathObjectPtr
5038 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5039  if (ctxt == NULL)
5040  return(NULL);
5041 
5042  if (ctxt->varLookupFunc != NULL) {
5043  xmlXPathObjectPtr ret;
5044 
5045  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5046  (ctxt->varLookupData, name, NULL);
5047  return(ret);
5048  }
5049  return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5050 }
5051 
5063 xmlXPathObjectPtr
5064 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5065  const xmlChar *ns_uri) {
5066  if (ctxt == NULL)
5067  return(NULL);
5068 
5069  if (ctxt->varLookupFunc != NULL) {
5070  xmlXPathObjectPtr ret;
5071 
5072  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5073  (ctxt->varLookupData, name, ns_uri);
5074  if (ret != NULL) return(ret);
5075  }
5076 
5077  if (ctxt->varHash == NULL)
5078  return(NULL);
5079  if (name == NULL)
5080  return(NULL);
5081 
5082  return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5083  xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5084 }
5085 
5092 void
5093 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5094  if (ctxt == NULL)
5095  return;
5096 
5097  xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5098  ctxt->varHash = NULL;
5099 }
5100 
5112 int
5113 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5114  const xmlChar *ns_uri) {
5115  if (ctxt == NULL)
5116  return(-1);
5117  if (prefix == NULL)
5118  return(-1);
5119  if (prefix[0] == 0)
5120  return(-1);
5121 
5122  if (ctxt->nsHash == NULL)
5123  ctxt->nsHash = xmlHashCreate(10);
5124  if (ctxt->nsHash == NULL)
5125  return(-1);
5126  if (ns_uri == NULL)
5127  return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5129  return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5131 }
5132 
5143 const xmlChar *
5144 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5145  if (ctxt == NULL)
5146  return(NULL);
5147  if (prefix == NULL)
5148  return(NULL);
5149 
5150 #ifdef XML_XML_NAMESPACE
5151  if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5152  return(XML_XML_NAMESPACE);
5153 #endif
5154 
5155  if (ctxt->namespaces != NULL) {
5156  int i;
5157 
5158  for (i = 0;i < ctxt->nsNr;i++) {
5159  if ((ctxt->namespaces[i] != NULL) &&
5160  (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5161  return(ctxt->namespaces[i]->href);
5162  }
5163  }
5164 
5165  return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5166 }
5167 
5174 void
5175 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5176  if (ctxt == NULL)
5177  return;
5178 
5179  xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5180  ctxt->nsHash = NULL;
5181 }
5182 
5183 /************************************************************************
5184  * *
5185  * Routines to handle Values *
5186  * *
5187  ************************************************************************/
5188 
5189 /* Allocations are terrible, one needs to optimize all this !!! */
5190 
5199 xmlXPathObjectPtr
5200 xmlXPathNewFloat(double val) {
5201  xmlXPathObjectPtr ret;
5202 
5203  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5204  if (ret == NULL) {
5205  xmlXPathErrMemory(NULL, "creating float object\n");
5206  return(NULL);
5207  }
5208  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5209  ret->type = XPATH_NUMBER;
5210  ret->floatval = val;
5211 #ifdef XP_DEBUG_OBJ_USAGE
5212  xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5213 #endif
5214  return(ret);
5215 }
5216 
5225 xmlXPathObjectPtr
5226 xmlXPathNewBoolean(int val) {
5227  xmlXPathObjectPtr ret;
5228 
5229  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5230  if (ret == NULL) {
5231  xmlXPathErrMemory(NULL, "creating boolean object\n");
5232  return(NULL);
5233  }
5234  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5235  ret->type = XPATH_BOOLEAN;
5236  ret->boolval = (val != 0);
5237 #ifdef XP_DEBUG_OBJ_USAGE
5238  xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5239 #endif
5240  return(ret);
5241 }
5242 
5251 xmlXPathObjectPtr
5252 xmlXPathNewString(const xmlChar *val) {
5253  xmlXPathObjectPtr ret;
5254 
5255  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5256  if (ret == NULL) {
5257  xmlXPathErrMemory(NULL, "creating string object\n");
5258  return(NULL);
5259  }
5260  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5261  ret->type = XPATH_STRING;
5262  if (val != NULL)
5263  ret->stringval = xmlStrdup(val);
5264  else
5265  ret->stringval = xmlStrdup((const xmlChar *)"");
5266 #ifdef XP_DEBUG_OBJ_USAGE
5267  xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5268 #endif
5269  return(ret);
5270 }
5271 
5280 xmlXPathObjectPtr
5281 xmlXPathWrapString (xmlChar *val) {
5282  xmlXPathObjectPtr ret;
5283 
5284  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5285  if (ret == NULL) {
5286  xmlXPathErrMemory(NULL, "creating string object\n");
5287  return(NULL);
5288  }
5289  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5290  ret->type = XPATH_STRING;
5291  ret->stringval = val;
5292 #ifdef XP_DEBUG_OBJ_USAGE
5293  xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5294 #endif
5295  return(ret);
5296 }
5297 
5306 xmlXPathObjectPtr
5307 xmlXPathNewCString(const char *val) {
5308  xmlXPathObjectPtr ret;
5309 
5310  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5311  if (ret == NULL) {
5312  xmlXPathErrMemory(NULL, "creating string object\n");
5313  return(NULL);
5314  }
5315  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5316  ret->type = XPATH_STRING;
5317  ret->stringval = xmlStrdup(BAD_CAST val);
5318 #ifdef XP_DEBUG_OBJ_USAGE
5319  xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5320 #endif
5321  return(ret);
5322 }
5323 
5332 xmlXPathObjectPtr
5333 xmlXPathWrapCString (char * val) {
5334  return(xmlXPathWrapString((xmlChar *)(val)));
5335 }
5336 
5345 xmlXPathObjectPtr
5346 xmlXPathWrapExternal (void *val) {
5347  xmlXPathObjectPtr ret;
5348 
5349  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5350  if (ret == NULL) {
5351  xmlXPathErrMemory(NULL, "creating user object\n");
5352  return(NULL);
5353  }
5354  memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5355  ret->type = XPATH_USERS;
5356  ret->user = val;
5357 #ifdef XP_DEBUG_OBJ_USAGE
5358  xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5359 #endif
5360  return(ret);
5361 }
5362 
5371 xmlXPathObjectPtr
5372 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5373  xmlXPathObjectPtr ret;
5374 
5375  if (val == NULL)
5376  return(NULL);
5377 
5378  ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5379  if (ret == NULL) {
5380  xmlXPathErrMemory(NULL, "copying object\n");
5381  return(NULL);
5382  }
5383  memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5384 #ifdef XP_DEBUG_OBJ_USAGE
5385  xmlXPathDebugObjUsageRequested(NULL, val->type);
5386 #endif
5387  switch (val->type) {
5388  case XPATH_BOOLEAN:
5389  case XPATH_NUMBER:
5390  case XPATH_POINT:
5391  case XPATH_RANGE:
5392  break;
5393  case XPATH_STRING:
5394  ret->stringval = xmlStrdup(val->stringval);
5395  break;
5396  case XPATH_XSLT_TREE:
5397 #if 0
5398 /*
5399  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5400  this previous handling is no longer correct, and can cause some serious
5401  problems (ref. bug 145547)
5402 */
5403  if ((val->nodesetval != NULL) &&
5404  (val->nodesetval->nodeTab != NULL)) {
5405  xmlNodePtr cur, tmp;
5406  xmlDocPtr top;
5407 
5408  ret->boolval = 1;
5409  top = xmlNewDoc(NULL);
5410  top->name = (char *)
5411  xmlStrdup(val->nodesetval->nodeTab[0]->name);
5412  ret->user = top;
5413  if (top != NULL) {
5414  top->doc = top;
5415  cur = val->nodesetval->nodeTab[0]->children;
5416  while (cur != NULL) {
5417  tmp = xmlDocCopyNode(cur, top, 1);
5418  xmlAddChild((xmlNodePtr) top, tmp);
5419  cur = cur->next;
5420  }
5421  }
5422 
5423  ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5424  } else
5425  ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5426  /* Deallocate the copied tree value */
5427  break;
5428 #endif
5429  case XPATH_NODESET:
5430  /* TODO: Check memory error. */
5431  ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5432  /* Do not deallocate the copied tree value */
5433  ret->boolval = 0;
5434  break;
5435  case XPATH_LOCATIONSET:
5436 #ifdef LIBXML_XPTR_ENABLED
5437  {
5438  xmlLocationSetPtr loc = val->user;
5439  ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5440  break;
5441  }
5442 #endif
5443  case XPATH_USERS:
5444  ret->user = val->user;
5445  break;
5446  case XPATH_UNDEFINED:
5448  "xmlXPathObjectCopy: unsupported type %d\n",
5449  val->type);
5450  break;
5451  }
5452  return(ret);
5453 }
5454 
5461 void
5462 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5463  if (obj == NULL) return;
5464  if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5465  if (obj->boolval) {
5466 #if 0
5467  if (obj->user != NULL) {
5468  xmlXPathFreeNodeSet(obj->nodesetval);
5469  xmlFreeNodeList((xmlNodePtr) obj->user);
5470  } else
5471 #endif
5472  obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5473  if (obj->nodesetval != NULL)
5474  xmlXPathFreeValueTree(obj->nodesetval);
5475  } else {
5476  if (obj->nodesetval != NULL)
5477  xmlXPathFreeNodeSet(obj->nodesetval);
5478  }
5479 #ifdef LIBXML_XPTR_ENABLED
5480  } else if (obj->type == XPATH_LOCATIONSET) {
5481  if (obj->user != NULL)
5482  xmlXPtrFreeLocationSet(obj->user);
5483 #endif
5484  } else if (obj->type == XPATH_STRING) {
5485  if (obj->stringval != NULL)
5486  xmlFree(obj->stringval);
5487  }
5488 #ifdef XP_DEBUG_OBJ_USAGE
5489  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5490 #endif
5491  xmlFree(obj);
5492 }
5493 
5494 static void
5495 xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5496  xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5497 }
5498 
5506 static void
5507 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5508 {
5509 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5510  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5511  if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5512 
5513 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5514 
5515  if (obj == NULL)
5516  return;
5517  if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5518  xmlXPathFreeObject(obj);
5519  } else {
5520  xmlXPathContextCachePtr cache =
5521  (xmlXPathContextCachePtr) ctxt->cache;
5522 
5523  switch (obj->type) {
5524  case XPATH_NODESET:
5525  case XPATH_XSLT_TREE:
5526  if (obj->nodesetval != NULL) {
5527  if (obj->boolval) {
5528  /*
5529  * It looks like the @boolval is used for
5530  * evaluation if this an XSLT Result Tree Fragment.
5531  * TODO: Check if this assumption is correct.
5532  */
5533  obj->type = XPATH_XSLT_TREE; /* just for debugging */
5534  xmlXPathFreeValueTree(obj->nodesetval);
5535  obj->nodesetval = NULL;
5536  } else if ((obj->nodesetval->nodeMax <= 40) &&
5537  (XP_CACHE_WANTS(cache->nodesetObjs,
5538  cache->maxNodeset)))
5539  {
5540  XP_CACHE_ADD(cache->nodesetObjs, obj);
5541  goto obj_cached;
5542  } else {
5543  xmlXPathFreeNodeSet(obj->nodesetval);
5544  obj->nodesetval = NULL;
5545  }
5546  }
5547  break;
5548  case XPATH_STRING:
5549  if (obj->stringval != NULL)
5550  xmlFree(obj->stringval);
5551 
5552  if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5553  XP_CACHE_ADD(cache->stringObjs, obj);
5554  goto obj_cached;
5555  }
5556  break;
5557  case XPATH_BOOLEAN:
5558  if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5559  XP_CACHE_ADD(cache->booleanObjs, obj);
5560  goto obj_cached;
5561  }
5562  break;
5563  case XPATH_NUMBER:
5564  if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5565  XP_CACHE_ADD(cache->numberObjs, obj);
5566  goto obj_cached;
5567  }
5568  break;
5569 #ifdef LIBXML_XPTR_ENABLED
5570  case XPATH_LOCATIONSET:
5571  if (obj->user != NULL) {
5572  xmlXPtrFreeLocationSet(obj->user);
5573  }
5574  goto free_obj;
5575 #endif
5576  default:
5577  goto free_obj;
5578  }
5579 
5580  /*
5581  * Fallback to adding to the misc-objects slot.
5582  */
5583  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5584  XP_CACHE_ADD(cache->miscObjs, obj);
5585  } else
5586  goto free_obj;
5587 
5588 obj_cached:
5589 
5590 #ifdef XP_DEBUG_OBJ_USAGE
5591  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5592 #endif
5593 
5594  if (obj->nodesetval != NULL) {
5595  xmlNodeSetPtr tmpset = obj->nodesetval;
5596 
5597  /*
5598  * TODO: Due to those nasty ns-nodes, we need to traverse
5599  * the list and free the ns-nodes.
5600  * URGENT TODO: Check if it's actually slowing things down.
5601  * Maybe we shouldn't try to preserve the list.
5602  */
5603  if (tmpset->nodeNr > 1) {
5604  int i;
5605  xmlNodePtr node;
5606 
5607  for (i = 0; i < tmpset->nodeNr; i++) {
5608  node = tmpset->nodeTab[i];
5609  if ((node != NULL) &&
5610  (node->type == XML_NAMESPACE_DECL))
5611  {
5612  xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5613  }
5614  }
5615  } else if (tmpset->nodeNr == 1) {
5616  if ((tmpset->nodeTab[0] != NULL) &&
5617  (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5618  xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5619  }
5620  tmpset->nodeNr = 0;
5621  memset(obj, 0, sizeof(xmlXPathObject));
5622  obj->nodesetval = tmpset;
5623  } else
5624  memset(obj, 0, sizeof(xmlXPathObject));
5625 
5626  return;
5627 
5628 free_obj:
5629  /*
5630  * Cache is full; free the object.
5631  */
5632  if (obj->nodesetval != NULL)
5633  xmlXPathFreeNodeSet(obj->nodesetval);
5634 #ifdef XP_DEBUG_OBJ_USAGE
5635  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5636 #endif
5637  xmlFree(obj);
5638  }
5639  return;
5640 }
5641 
5642 
5643 /************************************************************************
5644  * *
5645  * Type Casting Routines *
5646  * *
5647  ************************************************************************/
5648 
5657 xmlChar *
5658 xmlXPathCastBooleanToString (int val) {
5659  xmlChar *ret;
5660  if (val)
5661  ret = xmlStrdup((const xmlChar *) "true");
5662  else
5663  ret = xmlStrdup((const xmlChar *) "false");
5664  return(ret);
5665 }
5666 
5675 xmlChar *
5676 xmlXPathCastNumberToString (double val) {
5677  xmlChar *ret;
5678  switch (xmlXPathIsInf(val)) {
5679  case 1:
5680  ret = xmlStrdup((const xmlChar *) "Infinity");
5681  break;
5682  case -1:
5683  ret = xmlStrdup((const xmlChar *) "-Infinity");
5684  break;
5685  default:
5686  if (xmlXPathIsNaN(val)) {
5687  ret = xmlStrdup((const xmlChar *) "NaN");
5688  } else if (val == 0) {
5689  /* Omit sign for negative zero. */
5690  ret = xmlStrdup((const xmlChar *) "0");
5691  } else {
5692  /* could be improved */
5693  char buf[100];
5694  xmlXPathFormatNumber(val, buf, 99);
5695  buf[99] = 0;
5696  ret = xmlStrdup((const xmlChar *) buf);
5697  }
5698  }
5699  return(ret);
5700 }
5701 
5710 xmlChar *
5711 xmlXPathCastNodeToString (xmlNodePtr node) {
5712 xmlChar *ret;
5713  if ((ret = xmlNodeGetContent(node)) == NULL)
5714  ret = xmlStrdup((const xmlChar *) "");
5715  return(ret);
5716 }
5717 
5726 xmlChar *
5727 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5728  if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5729  return(xmlStrdup((const xmlChar *) ""));
5730 
5731  if (ns->nodeNr > 1)
5732  xmlXPathNodeSetSort(ns);
5733  return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5734 }
5735 
5745 xmlChar *
5746 xmlXPathCastToString(xmlXPathObjectPtr val) {
5747  xmlChar *ret = NULL;
5748 
5749  if (val == NULL)
5750  return(xmlStrdup((const xmlChar *) ""));
5751  switch (val->type) {
5752  case XPATH_UNDEFINED:
5753 #ifdef DEBUG_EXPR
5754  xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5755 #endif
5756  ret = xmlStrdup((const xmlChar *) "");
5757  break;
5758  case XPATH_NODESET:
5759  case XPATH_XSLT_TREE:
5760  ret = xmlXPathCastNodeSetToString(val->nodesetval);
5761  break;
5762  case XPATH_STRING:
5763  return(xmlStrdup(val->stringval));
5764  case XPATH_BOOLEAN:
5765  ret = xmlXPathCastBooleanToString(val->boolval);
5766  break;
5767  case XPATH_NUMBER: {
5768  ret = xmlXPathCastNumberToString(val->floatval);
5769  break;
5770  }
5771  case XPATH_USERS:
5772  case XPATH_POINT:
5773  case XPATH_RANGE:
5774  case XPATH_LOCATIONSET:
5775  TODO
5776  ret = xmlStrdup((const xmlChar *) "");
5777  break;
5778  }
5779  return(ret);
5780 }
5781 
5791 xmlXPathObjectPtr
5792 xmlXPathConvertString(xmlXPathObjectPtr val) {
5793  xmlChar *res = NULL;
5794 
5795  if (val == NULL)
5796  return(xmlXPathNewCString(""));
5797 
5798  switch (val->type) {
5799  case XPATH_UNDEFINED:
5800 #ifdef DEBUG_EXPR
5801  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5802 #endif
5803  break;
5804  case XPATH_NODESET:
5805  case XPATH_XSLT_TREE:
5806  res = xmlXPathCastNodeSetToString(val->nodesetval);
5807  break;
5808  case XPATH_STRING:
5809  return(val);
5810  case XPATH_BOOLEAN:
5811  res = xmlXPathCastBooleanToString(val->boolval);
5812  break;
5813  case XPATH_NUMBER:
5814  res = xmlXPathCastNumberToString(val->floatval);
5815  break;
5816  case XPATH_USERS:
5817  case XPATH_POINT:
5818  case XPATH_RANGE:
5819  case XPATH_LOCATIONSET:
5820  TODO;
5821  break;
5822  }
5823  xmlXPathFreeObject(val);
5824  if (res == NULL)
5825  return(xmlXPathNewCString(""));
5826  return(xmlXPathWrapString(res));
5827 }
5828 
5837 double
5838 xmlXPathCastBooleanToNumber(int val) {
5839  if (val)
5840  return(1.0);
5841  return(0.0);
5842 }
5843 
5852 double
5853 xmlXPathCastStringToNumber(const xmlChar * val) {
5854  return(xmlXPathStringEvalNumber(val));
5855 }
5856 
5865 double
5866 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5867  xmlChar *strval;
5868  double ret;
5869 
5870  if (node == NULL)
5871  return(xmlXPathNAN);
5872  strval = xmlXPathCastNodeToString(node);
5873  if (strval == NULL)
5874  return(xmlXPathNAN);
5875  ret = xmlXPathCastStringToNumber(strval);
5876  xmlFree(strval);
5877 
5878  return(ret);
5879 }
5880 
5889 double
5890 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5891  xmlChar *str;
5892  double ret;
5893 
5894  if (ns == NULL)
5895  return(xmlXPathNAN);
5896  str = xmlXPathCastNodeSetToString(ns);
5897  ret = xmlXPathCastStringToNumber(str);
5898  xmlFree(str);
5899  return(ret);
5900 }
5901 
5910 double
5911 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5912  double ret = 0.0;
5913 
5914  if (val == NULL)
5915  return(xmlXPathNAN);
5916  switch (val->type) {
5917  case XPATH_UNDEFINED:
5918 #ifdef DEBUG_EXPR
5919  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5920 #endif
5921  ret = xmlXPathNAN;
5922  break;
5923  case XPATH_NODESET:
5924  case XPATH_XSLT_TREE:
5925  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5926  break;
5927  case XPATH_STRING:
5928  ret = xmlXPathCastStringToNumber(val->stringval);
5929  break;
5930  case XPATH_NUMBER:
5931  ret = val->floatval;
5932  break;
5933  case XPATH_BOOLEAN:
5934  ret = xmlXPathCastBooleanToNumber(val->boolval);
5935  break;
5936  case XPATH_USERS:
5937  case XPATH_POINT:
5938  case XPATH_RANGE:
5939  case XPATH_LOCATIONSET:
5940  TODO;
5941  ret = xmlXPathNAN;
5942  break;
5943  }
5944  return(ret);
5945 }
5946 
5956 xmlXPathObjectPtr
5957 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5958  xmlXPathObjectPtr ret;
5959 
5960  if (val == NULL)
5961  return(xmlXPathNewFloat(0.0));
5962  if (val->type == XPATH_NUMBER)
5963  return(val);
5964  ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5965  xmlXPathFreeObject(val);
5966  return(ret);
5967 }
5968 
5977 int
5978 xmlXPathCastNumberToBoolean (double val) {
5979  if (xmlXPathIsNaN(val) || (val == 0.0))
5980  return(0);
5981  return(1);
5982 }
5983 
5992 int
5993 xmlXPathCastStringToBoolean (const xmlChar *val) {
5994  if ((val == NULL) || (xmlStrlen(val) == 0))
5995  return(0);
5996  return(1);
5997 }
5998 
6007 int
6008 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6009  if ((ns == NULL) || (ns->nodeNr == 0))
6010  return(0);
6011  return(1);
6012 }
6013 
6022 int
6023 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6024  int ret = 0;
6025 
6026  if (val == NULL)
6027  return(0);
6028  switch (val->type) {
6029  case XPATH_UNDEFINED:
6030 #ifdef DEBUG_EXPR
6031  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6032 #endif
6033  ret = 0;
6034  break;
6035  case XPATH_NODESET:
6036  case XPATH_XSLT_TREE:
6037  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6038  break;
6039  case XPATH_STRING:
6040  ret = xmlXPathCastStringToBoolean(val->stringval);
6041  break;
6042  case XPATH_NUMBER:
6043  ret = xmlXPathCastNumberToBoolean(val->floatval);
6044  break;
6045  case XPATH_BOOLEAN:
6046  ret = val->boolval;
6047  break;
6048  case XPATH_USERS:
6049  case XPATH_POINT:
6050  case XPATH_RANGE:
6051  case XPATH_LOCATIONSET:
6052  TODO;
6053  ret = 0;
6054  break;
6055  }
6056  return(ret);
6057 }
6058 
6059 
6069 xmlXPathObjectPtr
6070 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6071  xmlXPathObjectPtr ret;
6072 
6073  if (val == NULL)
6074  return(xmlXPathNewBoolean(0));
6075  if (val->type == XPATH_BOOLEAN)
6076  return(val);
6077  ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6078  xmlXPathFreeObject(val);
6079  return(ret);
6080 }
6081 
6082 /************************************************************************
6083  * *
6084  * Routines to handle XPath contexts *
6085  * *
6086  ************************************************************************/
6087 
6096 xmlXPathContextPtr
6097 xmlXPathNewContext(xmlDocPtr doc) {
6098  xmlXPathContextPtr ret;
6099 
6100  ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6101  if (ret == NULL) {
6102  xmlXPathErrMemory(NULL, "creating context\n");
6103  return(NULL);
6104  }
6105  memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6106  ret->doc = doc;
6107  ret->node = NULL;
6108 
6109  ret->varHash = NULL;
6110 
6111  ret->nb_types = 0;
6112  ret->max_types = 0;
6113  ret->types = NULL;
6114 
6115  ret->funcHash = xmlHashCreate(0);
6116 
6117  ret->nb_axis = 0;
6118  ret->max_axis = 0;
6119  ret->axis = NULL;
6120 
6121  ret->nsHash = NULL;
6122  ret->user = NULL;
6123 
6124  ret->contextSize = -1;
6125  ret->proximityPosition = -1;
6126 
6127 #ifdef XP_DEFAULT_CACHE_ON
6128  if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6129  xmlXPathFreeContext(ret);
6130  return(NULL);
6131  }
6132 #endif
6133 
6134  xmlXPathRegisterAllFunctions(ret);
6135 
6136  return(ret);
6137 }
6138 
6145 void
6146 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6147  if (ctxt == NULL) return;
6148 
6149  if (ctxt->cache != NULL)
6150  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6151  xmlXPathRegisteredNsCleanup(ctxt);
6152  xmlXPathRegisteredFuncsCleanup(ctxt);
6153  xmlXPathRegisteredVariablesCleanup(ctxt);
6154  xmlResetError(&ctxt->lastError);
6155  xmlFree(ctxt);
6156 }
6157 
6158 /************************************************************************
6159  * *
6160  * Routines to handle XPath parser contexts *
6161  * *
6162  ************************************************************************/
6163 
6164 #define CHECK_CTXT(ctxt) \
6165  if (ctxt == NULL) { \
6166  __xmlRaiseError(NULL, NULL, NULL, \
6167  NULL, NULL, XML_FROM_XPATH, \
6168  XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6169  __FILE__, __LINE__, \
6170  NULL, NULL, NULL, 0, 0, \
6171  "NULL context pointer\n"); \
6172  return(NULL); \
6173  } \
6174 
6175 #define CHECK_CTXT_NEG(ctxt) \
6176  if (ctxt == NULL) { \
6177  __xmlRaiseError(NULL, NULL, NULL, \
6178  NULL, NULL, XML_FROM_XPATH, \
6179  XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6180  __FILE__, __LINE__, \
6181  NULL, NULL, NULL, 0, 0, \
6182  "NULL context pointer\n"); \
6183  return(-1); \
6184  } \
6185 
6186 
6187 #define CHECK_CONTEXT(ctxt) \
6188  if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6189  (ctxt->doc->children == NULL)) { \
6190  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6191  return(NULL); \
6192  }
6193 
6194 
6204 xmlXPathParserContextPtr
6205 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6206  xmlXPathParserContextPtr ret;
6207 
6208  ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6209  if (ret == NULL) {
6210  xmlXPathErrMemory(ctxt, "creating parser context\n");
6211  return(NULL);
6212  }
6213  memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6214  ret->cur = ret->base = str;
6215  ret->context = ctxt;
6216 
6217  ret->comp = xmlXPathNewCompExpr();
6218  if (ret->comp == NULL) {
6219  xmlFree(ret->valueTab);
6220  xmlFree(ret);
6221  return(NULL);
6222  }
6223  if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6224  ret->comp->dict = ctxt->dict;
6225  xmlDictReference(ret->comp->dict);
6226  }
6227 
6228  return(ret);
6229 }
6230 
6240 static xmlXPathParserContextPtr
6241 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6242  xmlXPathParserContextPtr ret;
6243 
6244  ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245  if (ret == NULL) {
6246  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6247  return(NULL);
6248  }
6249  memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250 
6251  /* Allocate the value stack */
6252  ret->valueTab = (xmlXPathObjectPtr *)
6253  xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6254  if (ret->valueTab == NULL) {
6255  xmlFree(ret);
6256  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6257  return(NULL);
6258  }
6259  ret->valueNr = 0;
6260  ret->valueMax = 10;
6261  ret->value = NULL;
6262  ret->valueFrame = 0;
6263 
6264  ret->context = ctxt;
6265  ret->comp = comp;
6266 
6267  return(ret);
6268 }
6269 
6276 void
6277 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6278  int i;
6279 
6280  if (ctxt->valueTab != NULL) {
6281  for (i = 0; i < ctxt->valueNr; i++) {
6282  if (ctxt->context)
6283  xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6284  else
6285  xmlXPathFreeObject(ctxt->valueTab[i]);
6286  }
6287  xmlFree(ctxt->valueTab);
6288  }
6289  if (ctxt->comp != NULL) {
6290 #ifdef XPATH_STREAMING
6291  if (ctxt->comp->stream != NULL) {
6292  xmlFreePatternList(ctxt->comp->stream);
6293  ctxt->comp->stream = NULL;
6294  }
6295 #endif
6296  xmlXPathFreeCompExpr(ctxt->comp);
6297  }
6298  xmlFree(ctxt);
6299 }
6300 
6301 /************************************************************************
6302  * *
6303  * The implicit core function library *
6304  * *
6305  ************************************************************************/
6306 
6316 static unsigned int
6317 xmlXPathNodeValHash(xmlNodePtr node) {
6318  int len = 2;
6319  const xmlChar * string = NULL;
6320  xmlNodePtr tmp = NULL;
6321  unsigned int ret = 0;
6322 
6323  if (node == NULL)
6324  return(0);
6325 
6326  if (node->type == XML_DOCUMENT_NODE) {
6328  if (tmp == NULL)
6329  node = node->children;
6330  else
6331  node = tmp;
6332 
6333  if (node == NULL)
6334  return(0);
6335  }
6336 
6337  switch (node->type) {
6338  case XML_COMMENT_NODE:
6339  case XML_PI_NODE:
6341  case XML_TEXT_NODE:
6342  string = node->content;
6343  if (string == NULL)
6344  return(0);
6345  if (string[0] == 0)
6346  return(0);
6347  return(((unsigned int) string[0]) +
6348  (((unsigned int) string[1]) << 8));
6349  case XML_NAMESPACE_DECL:
6350  string = ((xmlNsPtr)node)->href;
6351  if (string == NULL)
6352  return(0);
6353  if (string[0] == 0)
6354  return(0);
6355  return(((unsigned int) string[0]) +
6356  (((unsigned int) string[1]) << 8));
6357  case XML_ATTRIBUTE_NODE:
6358  tmp = ((xmlAttrPtr) node)->children;
6359  break;
6360  case XML_ELEMENT_NODE:
6361  tmp = node->children;
6362  break;
6363  default:
6364  return(0);
6365  }
6366  while (tmp != NULL) {
6367  switch (tmp->type) {
6369  case XML_TEXT_NODE:
6370  string = tmp->content;
6371  break;
6372  default:
6373  string = NULL;
6374  break;
6375  }
6376  if ((string != NULL) && (string[0] != 0)) {
6377  if (len == 1) {
6378  return(ret + (((unsigned int) string[0]) << 8));
6379  }
6380  if (string[1] == 0) {
6381  len = 1;
6382  ret = (unsigned int) string[0];
6383  } else {
6384  return(((unsigned int) string[0]) +
6385  (((unsigned int)