Coverage Report

Created: 2023-04-29 07:39

/src/libxml2/xpath.c
Line
Count
Source (jump to first uncovered line)
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
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/valid.h>
35
#include <libxml/xpath.h>
36
#include <libxml/xpathInternals.h>
37
#include <libxml/parserInternals.h>
38
#include <libxml/hash.h>
39
#ifdef LIBXML_XPTR_LOCS_ENABLED
40
#include <libxml/xpointer.h>
41
#endif
42
#ifdef LIBXML_DEBUG_ENABLED
43
#include <libxml/debugXML.h>
44
#endif
45
#include <libxml/xmlerror.h>
46
#include <libxml/threads.h>
47
#include <libxml/globals.h>
48
#ifdef LIBXML_PATTERN_ENABLED
49
#include <libxml/pattern.h>
50
#endif
51
52
#include "private/buf.h"
53
#include "private/error.h"
54
#include "private/xpath.h"
55
56
#ifdef LIBXML_PATTERN_ENABLED
57
#define XPATH_STREAMING
58
#endif
59
60
#define TODO                \
61
0
    xmlGenericError(xmlGenericErrorContext,       \
62
0
      "Unimplemented block at %s:%d\n",       \
63
0
            __FILE__, __LINE__);
64
65
/**
66
 * WITH_TIM_SORT:
67
 *
68
 * Use the Timsort algorithm provided in timsort.h to sort
69
 * nodeset as this is a great improvement over the old Shell sort
70
 * used in xmlXPathNodeSetSort()
71
 */
72
#define WITH_TIM_SORT
73
74
/*
75
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
76
* If defined, this will use xmlXPathCmpNodesExt() instead of
77
* xmlXPathCmpNodes(). The new function is optimized comparison of
78
* non-element nodes; actually it will speed up comparison only if
79
* xmlXPathOrderDocElems() was called in order to index the elements of
80
* a tree in document order; Libxslt does such an indexing, thus it will
81
* benefit from this optimization.
82
*/
83
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
84
85
/*
86
* XP_OPTIMIZED_FILTER_FIRST:
87
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
88
* in a way, that it stop evaluation at the first node.
89
*/
90
#define XP_OPTIMIZED_FILTER_FIRST
91
92
/*
93
* XP_DEBUG_OBJ_USAGE:
94
* Internal flag to enable tracking of how much XPath objects have been
95
* created.
96
*/
97
/* #define XP_DEBUG_OBJ_USAGE */
98
99
/*
100
 * XPATH_MAX_STEPS:
101
 * when compiling an XPath expression we arbitrary limit the maximum
102
 * number of step operation in the compiled expression. 1000000 is
103
 * an insanely large value which should never be reached under normal
104
 * circumstances
105
 */
106
15.8k
#define XPATH_MAX_STEPS 1000000
107
108
/*
109
 * XPATH_MAX_STACK_DEPTH:
110
 * when evaluating an XPath expression we arbitrary limit the maximum
111
 * number of object allowed to be pushed on the stack. 1000000 is
112
 * an insanely large value which should never be reached under normal
113
 * circumstances
114
 */
115
650
#define XPATH_MAX_STACK_DEPTH 1000000
116
117
/*
118
 * XPATH_MAX_NODESET_LENGTH:
119
 * when evaluating an XPath expression nodesets are created and we
120
 * arbitrary limit the maximum length of those node set. 10000000 is
121
 * an insanely large value which should never be reached under normal
122
 * circumstances, one would first need to construct an in memory tree
123
 * with more than 10 millions nodes.
124
 */
125
3.89M
#define XPATH_MAX_NODESET_LENGTH 10000000
126
127
/*
128
 * XPATH_MAX_RECRUSION_DEPTH:
129
 * Maximum amount of nested functions calls when parsing or evaluating
130
 * expressions
131
 */
132
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
133
51.6M
#define XPATH_MAX_RECURSION_DEPTH 500
134
#elif defined(_WIN32)
135
/* Windows typically limits stack size to 1MB. */
136
#define XPATH_MAX_RECURSION_DEPTH 1000
137
#else
138
#define XPATH_MAX_RECURSION_DEPTH 5000
139
#endif
140
141
/*
142
 * TODO:
143
 * There are a few spots where some tests are done which depend upon ascii
144
 * data.  These should be enhanced for full UTF8 support (see particularly
145
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
146
 */
147
148
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
149
/**
150
 * xmlXPathCmpNodesExt:
151
 * @node1:  the first node
152
 * @node2:  the second node
153
 *
154
 * Compare two nodes w.r.t document order.
155
 * This one is optimized for handling of non-element nodes.
156
 *
157
 * Returns -2 in case of error 1 if first point < second point, 0 if
158
 *         it's the same node, -1 otherwise
159
 */
160
static int
161
29.5M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
162
29.5M
    int depth1, depth2;
163
29.5M
    int misc = 0, precedence1 = 0, precedence2 = 0;
164
29.5M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
165
29.5M
    xmlNodePtr cur, root;
166
29.5M
    ptrdiff_t l1, l2;
167
168
29.5M
    if ((node1 == NULL) || (node2 == NULL))
169
0
  return(-2);
170
171
29.5M
    if (node1 == node2)
172
0
  return(0);
173
174
    /*
175
     * a couple of optimizations which will avoid computations in most cases
176
     */
177
29.5M
    switch (node1->type) {
178
15.8M
  case XML_ELEMENT_NODE:
179
15.8M
      if (node2->type == XML_ELEMENT_NODE) {
180
10.9M
    if ((0 > (ptrdiff_t) node1->content) &&
181
10.9M
        (0 > (ptrdiff_t) node2->content) &&
182
10.9M
        (node1->doc == node2->doc))
183
10.9M
    {
184
10.9M
        l1 = -((ptrdiff_t) node1->content);
185
10.9M
        l2 = -((ptrdiff_t) node2->content);
186
10.9M
        if (l1 < l2)
187
6.26M
      return(1);
188
4.68M
        if (l1 > l2)
189
4.68M
      return(-1);
190
4.68M
    } else
191
0
        goto turtle_comparison;
192
10.9M
      }
193
4.90M
      break;
194
4.90M
  case XML_ATTRIBUTE_NODE:
195
438k
      precedence1 = 1; /* element is owner */
196
438k
      miscNode1 = node1;
197
438k
      node1 = node1->parent;
198
438k
      misc = 1;
199
438k
      break;
200
9.98M
  case XML_TEXT_NODE:
201
10.4M
  case XML_CDATA_SECTION_NODE:
202
11.2M
  case XML_COMMENT_NODE:
203
12.0M
  case XML_PI_NODE: {
204
12.0M
      miscNode1 = node1;
205
      /*
206
      * Find nearest element node.
207
      */
208
12.0M
      if (node1->prev != NULL) {
209
10.5M
    do {
210
10.5M
        node1 = node1->prev;
211
10.5M
        if (node1->type == XML_ELEMENT_NODE) {
212
7.30M
      precedence1 = 3; /* element in prev-sibl axis */
213
7.30M
      break;
214
7.30M
        }
215
3.24M
        if (node1->prev == NULL) {
216
0
      precedence1 = 2; /* element is parent */
217
      /*
218
      * URGENT TODO: Are there any cases, where the
219
      * parent of such a node is not an element node?
220
      */
221
0
      node1 = node1->parent;
222
0
      break;
223
0
        }
224
3.24M
    } while (1);
225
7.30M
      } else {
226
4.77M
    precedence1 = 2; /* element is parent */
227
4.77M
    node1 = node1->parent;
228
4.77M
      }
229
12.0M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
230
12.0M
    (0 <= (ptrdiff_t) node1->content)) {
231
    /*
232
    * Fallback for whatever case.
233
    */
234
344k
    node1 = miscNode1;
235
344k
    precedence1 = 0;
236
344k
      } else
237
11.7M
    misc = 1;
238
12.0M
  }
239
0
      break;
240
818k
  case XML_NAMESPACE_DECL:
241
      /*
242
      * TODO: why do we return 1 for namespace nodes?
243
      */
244
818k
      return(1);
245
354k
  default:
246
354k
      break;
247
29.5M
    }
248
17.7M
    switch (node2->type) {
249
6.01M
  case XML_ELEMENT_NODE:
250
6.01M
      break;
251
409k
  case XML_ATTRIBUTE_NODE:
252
409k
      precedence2 = 1; /* element is owner */
253
409k
      miscNode2 = node2;
254
409k
      node2 = node2->parent;
255
409k
      misc = 1;
256
409k
      break;
257
8.31M
  case XML_TEXT_NODE:
258
8.72M
  case XML_CDATA_SECTION_NODE:
259
9.48M
  case XML_COMMENT_NODE:
260
10.2M
  case XML_PI_NODE: {
261
10.2M
      miscNode2 = node2;
262
10.2M
      if (node2->prev != NULL) {
263
9.51M
    do {
264
9.51M
        node2 = node2->prev;
265
9.51M
        if (node2->type == XML_ELEMENT_NODE) {
266
6.18M
      precedence2 = 3; /* element in prev-sibl axis */
267
6.18M
      break;
268
6.18M
        }
269
3.32M
        if (node2->prev == NULL) {
270
0
      precedence2 = 2; /* element is parent */
271
0
      node2 = node2->parent;
272
0
      break;
273
0
        }
274
3.32M
    } while (1);
275
6.18M
      } else {
276
4.02M
    precedence2 = 2; /* element is parent */
277
4.02M
    node2 = node2->parent;
278
4.02M
      }
279
10.2M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
280
10.2M
    (0 <= (ptrdiff_t) node2->content))
281
327k
      {
282
327k
    node2 = miscNode2;
283
327k
    precedence2 = 0;
284
327k
      } else
285
9.87M
    misc = 1;
286
10.2M
  }
287
0
      break;
288
189k
  case XML_NAMESPACE_DECL:
289
189k
      return(1);
290
964k
  default:
291
964k
      break;
292
17.7M
    }
293
17.5M
    if (misc) {
294
16.6M
  if (node1 == node2) {
295
7.66M
      if (precedence1 == precedence2) {
296
    /*
297
    * The ugly case; but normally there aren't many
298
    * adjacent non-element nodes around.
299
    */
300
1.82M
    cur = miscNode2->prev;
301
1.88M
    while (cur != NULL) {
302
1.88M
        if (cur == miscNode1)
303
1.64M
      return(1);
304
245k
        if (cur->type == XML_ELEMENT_NODE)
305
177k
      return(-1);
306
68.0k
        cur = cur->prev;
307
68.0k
    }
308
3.31k
    return (-1);
309
5.83M
      } else {
310
    /*
311
    * Evaluate based on higher precedence wrt to the element.
312
    * TODO: This assumes attributes are sorted before content.
313
    *   Is this 100% correct?
314
    */
315
5.83M
    if (precedence1 < precedence2)
316
4.91M
        return(1);
317
924k
    else
318
924k
        return(-1);
319
5.83M
      }
320
7.66M
  }
321
  /*
322
  * Special case: One of the helper-elements is contained by the other.
323
  * <foo>
324
  *   <node2>
325
  *     <node1>Text-1(precedence1 == 2)</node1>
326
  *   </node2>
327
  *   Text-6(precedence2 == 3)
328
  * </foo>
329
  */
330
8.94M
  if ((precedence2 == 3) && (precedence1 > 1)) {
331
1.25M
      cur = node1->parent;
332
3.17M
      while (cur) {
333
2.43M
    if (cur == node2)
334
512k
        return(1);
335
1.92M
    cur = cur->parent;
336
1.92M
      }
337
1.25M
  }
338
8.43M
  if ((precedence1 == 3) && (precedence2 > 1)) {
339
651k
      cur = node2->parent;
340
1.82M
      while (cur) {
341
1.39M
    if (cur == node1)
342
225k
        return(-1);
343
1.17M
    cur = cur->parent;
344
1.17M
      }
345
651k
  }
346
8.43M
    }
347
348
    /*
349
     * Speedup using document order if available.
350
     */
351
9.19M
    if ((node1->type == XML_ELEMENT_NODE) &&
352
9.19M
  (node2->type == XML_ELEMENT_NODE) &&
353
9.19M
  (0 > (ptrdiff_t) node1->content) &&
354
9.19M
  (0 > (ptrdiff_t) node2->content) &&
355
9.19M
  (node1->doc == node2->doc)) {
356
357
7.46M
  l1 = -((ptrdiff_t) node1->content);
358
7.46M
  l2 = -((ptrdiff_t) node2->content);
359
7.46M
  if (l1 < l2)
360
4.82M
      return(1);
361
2.63M
  if (l1 > l2)
362
2.63M
      return(-1);
363
2.63M
    }
364
365
1.72M
turtle_comparison:
366
367
1.72M
    if (node1 == node2->prev)
368
199k
  return(1);
369
1.52M
    if (node1 == node2->next)
370
62.6k
  return(-1);
371
    /*
372
     * compute depth to root
373
     */
374
1.90M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
375
790k
  if (cur->parent == node1)
376
354k
      return(1);
377
435k
  depth2++;
378
435k
    }
379
1.10M
    root = cur;
380
2.71M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
381
2.56M
  if (cur->parent == node2)
382
964k
      return(-1);
383
1.60M
  depth1++;
384
1.60M
    }
385
    /*
386
     * Distinct document (or distinct entities :-( ) case.
387
     */
388
144k
    if (root != cur) {
389
0
  return(-2);
390
0
    }
391
    /*
392
     * get the nearest common ancestor.
393
     */
394
212k
    while (depth1 > depth2) {
395
68.0k
  depth1--;
396
68.0k
  node1 = node1->parent;
397
68.0k
    }
398
288k
    while (depth2 > depth1) {
399
144k
  depth2--;
400
144k
  node2 = node2->parent;
401
144k
    }
402
144k
    while (node1->parent != node2->parent) {
403
0
  node1 = node1->parent;
404
0
  node2 = node2->parent;
405
  /* should not happen but just in case ... */
406
0
  if ((node1 == NULL) || (node2 == NULL))
407
0
      return(-2);
408
0
    }
409
    /*
410
     * Find who's first.
411
     */
412
144k
    if (node1 == node2->prev)
413
95.2k
  return(1);
414
49.4k
    if (node1 == node2->next)
415
49.4k
  return(-1);
416
    /*
417
     * Speedup using document order if available.
418
     */
419
0
    if ((node1->type == XML_ELEMENT_NODE) &&
420
0
  (node2->type == XML_ELEMENT_NODE) &&
421
0
  (0 > (ptrdiff_t) node1->content) &&
422
0
  (0 > (ptrdiff_t) node2->content) &&
423
0
  (node1->doc == node2->doc)) {
424
425
0
  l1 = -((ptrdiff_t) node1->content);
426
0
  l2 = -((ptrdiff_t) node2->content);
427
0
  if (l1 < l2)
428
0
      return(1);
429
0
  if (l1 > l2)
430
0
      return(-1);
431
0
    }
432
433
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
434
0
  if (cur == node2)
435
0
      return(1);
436
0
    return(-1); /* assume there is no sibling list corruption */
437
0
}
438
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
439
440
/*
441
 * Wrapper for the Timsort algorithm from timsort.h
442
 */
443
#ifdef WITH_TIM_SORT
444
#define SORT_NAME libxml_domnode
445
19.1M
#define SORT_TYPE xmlNodePtr
446
/**
447
 * wrap_cmp:
448
 * @x: a node
449
 * @y: another node
450
 *
451
 * Comparison function for the Timsort implementation
452
 *
453
 * Returns -2 in case of error -1 if first point < second point, 0 if
454
 *         it's the same node, +1 otherwise
455
 */
456
static
457
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
458
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
459
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
460
29.4M
    {
461
29.4M
        int res = xmlXPathCmpNodesExt(x, y);
462
29.4M
        return res == -2 ? res : -res;
463
29.4M
    }
464
#else
465
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
466
    {
467
        int res = xmlXPathCmpNodes(x, y);
468
        return res == -2 ? res : -res;
469
    }
470
#endif
471
29.4M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
472
#include "timsort.h"
473
#endif /* WITH_TIM_SORT */
474
475
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
476
477
/************************************************************************
478
 *                  *
479
 *      Floating point stuff        *
480
 *                  *
481
 ************************************************************************/
482
483
double xmlXPathNAN = 0.0;
484
double xmlXPathPINF = 0.0;
485
double xmlXPathNINF = 0.0;
486
487
/**
488
 * xmlXPathInit:
489
 *
490
 * DEPRECATED: Alias for xmlInitParser.
491
 */
492
void
493
0
xmlXPathInit(void) {
494
0
    xmlInitParser();
495
0
}
496
497
/**
498
 * xmlInitXPathInternal:
499
 *
500
 * Initialize the XPath environment
501
 */
502
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
503
void
504
363
xmlInitXPathInternal(void) {
505
363
#if defined(NAN) && defined(INFINITY)
506
363
    xmlXPathNAN = NAN;
507
363
    xmlXPathPINF = INFINITY;
508
363
    xmlXPathNINF = -INFINITY;
509
#else
510
    /* MSVC doesn't allow division by zero in constant expressions. */
511
    double zero = 0.0;
512
    xmlXPathNAN = 0.0 / zero;
513
    xmlXPathPINF = 1.0 / zero;
514
    xmlXPathNINF = -xmlXPathPINF;
515
#endif
516
363
}
517
518
/**
519
 * xmlXPathIsNaN:
520
 * @val:  a double value
521
 *
522
 * Returns 1 if the value is a NaN, 0 otherwise
523
 */
524
int
525
7.32M
xmlXPathIsNaN(double val) {
526
7.32M
#ifdef isnan
527
7.32M
    return isnan(val);
528
#else
529
    return !(val == val);
530
#endif
531
7.32M
}
532
533
/**
534
 * xmlXPathIsInf:
535
 * @val:  a double value
536
 *
537
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
538
 */
539
int
540
2.64M
xmlXPathIsInf(double val) {
541
2.64M
#ifdef isinf
542
2.64M
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
543
#else
544
    if (val >= xmlXPathPINF)
545
        return 1;
546
    if (val <= -xmlXPathPINF)
547
        return -1;
548
    return 0;
549
#endif
550
2.64M
}
551
552
#endif /* SCHEMAS or XPATH */
553
554
#ifdef LIBXML_XPATH_ENABLED
555
556
/*
557
 * TODO: when compatibility allows remove all "fake node libxslt" strings
558
 *       the test should just be name[0] = ' '
559
 */
560
#ifdef DEBUG_XPATH_EXPRESSION
561
#define DEBUG_STEP
562
#define DEBUG_EXPR
563
#define DEBUG_EVAL_COUNTS
564
#endif
565
566
static xmlNs xmlXPathXMLNamespaceStruct = {
567
    NULL,
568
    XML_NAMESPACE_DECL,
569
    XML_XML_NAMESPACE,
570
    BAD_CAST "xml",
571
    NULL,
572
    NULL
573
};
574
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
575
#ifndef LIBXML_THREAD_ENABLED
576
/*
577
 * Optimizer is disabled only when threaded apps are detected while
578
 * the library ain't compiled for thread safety.
579
 */
580
static int xmlXPathDisableOptimizer = 0;
581
#endif
582
583
/************************************************************************
584
 *                  *
585
 *      Error handling routines       *
586
 *                  *
587
 ************************************************************************/
588
589
/**
590
 * XP_ERRORNULL:
591
 * @X:  the error code
592
 *
593
 * Macro to raise an XPath error and return NULL.
594
 */
595
#define XP_ERRORNULL(X)             \
596
556
    { xmlXPathErr(ctxt, X); return(NULL); }
597
598
/*
599
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
600
 */
601
static const char* const xmlXPathErrorMessages[] = {
602
    "Ok\n",
603
    "Number encoding\n",
604
    "Unfinished literal\n",
605
    "Start of literal\n",
606
    "Expected $ for variable reference\n",
607
    "Undefined variable\n",
608
    "Invalid predicate\n",
609
    "Invalid expression\n",
610
    "Missing closing curly brace\n",
611
    "Unregistered function\n",
612
    "Invalid operand\n",
613
    "Invalid type\n",
614
    "Invalid number of arguments\n",
615
    "Invalid context size\n",
616
    "Invalid context position\n",
617
    "Memory allocation error\n",
618
    "Syntax error\n",
619
    "Resource error\n",
620
    "Sub resource error\n",
621
    "Undefined namespace prefix\n",
622
    "Encoding error\n",
623
    "Char out of XML range\n",
624
    "Invalid or incomplete context\n",
625
    "Stack usage error\n",
626
    "Forbidden variable\n",
627
    "Operation limit exceeded\n",
628
    "Recursion limit exceeded\n",
629
    "?? Unknown error ??\n" /* Must be last in the list! */
630
};
631
6.77k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
632
6.77k
       sizeof(xmlXPathErrorMessages[0])) - 1)
633
/**
634
 * xmlXPathErrMemory:
635
 * @ctxt:  an XPath context
636
 * @extra:  extra information
637
 *
638
 * Handle a redefinition of attribute error
639
 */
640
static void
641
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
642
0
{
643
0
    if (ctxt != NULL) {
644
0
        xmlResetError(&ctxt->lastError);
645
0
        if (extra) {
646
0
            xmlChar buf[200];
647
648
0
            xmlStrPrintf(buf, 200,
649
0
                         "Memory allocation failed : %s\n",
650
0
                         extra);
651
0
            ctxt->lastError.message = (char *) xmlStrdup(buf);
652
0
        } else {
653
0
            ctxt->lastError.message = (char *)
654
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
655
0
        }
656
0
        ctxt->lastError.domain = XML_FROM_XPATH;
657
0
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
658
0
  if (ctxt->error != NULL)
659
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
660
0
    } else {
661
0
        if (extra)
662
0
            __xmlRaiseError(NULL, NULL, NULL,
663
0
                            NULL, NULL, XML_FROM_XPATH,
664
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
665
0
                            extra, NULL, NULL, 0, 0,
666
0
                            "Memory allocation failed : %s\n", extra);
667
0
        else
668
0
            __xmlRaiseError(NULL, NULL, NULL,
669
0
                            NULL, NULL, XML_FROM_XPATH,
670
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
671
0
                            NULL, NULL, NULL, 0, 0,
672
0
                            "Memory allocation failed\n");
673
0
    }
674
0
}
675
676
/**
677
 * xmlXPathPErrMemory:
678
 * @ctxt:  an XPath parser context
679
 * @extra:  extra information
680
 *
681
 * Handle a redefinition of attribute error
682
 */
683
static void
684
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
685
0
{
686
0
    if (ctxt == NULL)
687
0
  xmlXPathErrMemory(NULL, extra);
688
0
    else {
689
0
  ctxt->error = XPATH_MEMORY_ERROR;
690
0
  xmlXPathErrMemory(ctxt->context, extra);
691
0
    }
692
0
}
693
694
/**
695
 * xmlXPathErr:
696
 * @ctxt:  a XPath parser context
697
 * @error:  the error code
698
 *
699
 * Handle an XPath error
700
 */
701
void
702
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
703
6.77k
{
704
6.77k
    if ((error < 0) || (error > MAXERRNO))
705
0
  error = MAXERRNO;
706
6.77k
    if (ctxt == NULL) {
707
0
  __xmlRaiseError(NULL, NULL, NULL,
708
0
      NULL, NULL, XML_FROM_XPATH,
709
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
710
0
      XML_ERR_ERROR, NULL, 0,
711
0
      NULL, NULL, NULL, 0, 0,
712
0
      "%s", xmlXPathErrorMessages[error]);
713
0
  return;
714
0
    }
715
6.77k
    ctxt->error = error;
716
6.77k
    if (ctxt->context == NULL) {
717
0
  __xmlRaiseError(NULL, NULL, NULL,
718
0
      NULL, NULL, XML_FROM_XPATH,
719
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
720
0
      XML_ERR_ERROR, NULL, 0,
721
0
      (const char *) ctxt->base, NULL, NULL,
722
0
      ctxt->cur - ctxt->base, 0,
723
0
      "%s", xmlXPathErrorMessages[error]);
724
0
  return;
725
0
    }
726
727
    /* cleanup current last error */
728
6.77k
    xmlResetError(&ctxt->context->lastError);
729
730
6.77k
    ctxt->context->lastError.domain = XML_FROM_XPATH;
731
6.77k
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732
6.77k
                           XPATH_EXPRESSION_OK;
733
6.77k
    ctxt->context->lastError.level = XML_ERR_ERROR;
734
6.77k
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735
6.77k
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736
6.77k
    ctxt->context->lastError.node = ctxt->context->debugNode;
737
6.77k
    if (ctxt->context->error != NULL) {
738
0
  ctxt->context->error(ctxt->context->userData,
739
0
                       &ctxt->context->lastError);
740
6.77k
    } else {
741
6.77k
  __xmlRaiseError(NULL, NULL, NULL,
742
6.77k
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743
6.77k
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744
6.77k
      XML_ERR_ERROR, NULL, 0,
745
6.77k
      (const char *) ctxt->base, NULL, NULL,
746
6.77k
      ctxt->cur - ctxt->base, 0,
747
6.77k
      "%s", xmlXPathErrorMessages[error]);
748
6.77k
    }
749
750
6.77k
}
751
752
/**
753
 * xmlXPatherror:
754
 * @ctxt:  the XPath Parser context
755
 * @file:  the file name
756
 * @line:  the line number
757
 * @no:  the error number
758
 *
759
 * Formats an error message.
760
 */
761
void
762
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
763
475
              int line ATTRIBUTE_UNUSED, int no) {
764
475
    xmlXPathErr(ctxt, no);
765
475
}
766
767
/**
768
 * xmlXPathCheckOpLimit:
769
 * @ctxt:  the XPath Parser context
770
 * @opCount:  the number of operations to be added
771
 *
772
 * Adds opCount to the running total of operations and returns -1 if the
773
 * operation limit is exceeded. Returns 0 otherwise.
774
 */
775
static int
776
254M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
777
254M
    xmlXPathContextPtr xpctxt = ctxt->context;
778
779
254M
    if ((opCount > xpctxt->opLimit) ||
780
254M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
781
435
        xpctxt->opCount = xpctxt->opLimit;
782
435
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
783
435
        return(-1);
784
435
    }
785
786
254M
    xpctxt->opCount += opCount;
787
254M
    return(0);
788
254M
}
789
790
#define OP_LIMIT_EXCEEDED(ctxt, n) \
791
250M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
792
793
/************************************************************************
794
 *                  *
795
 *      Utilities         *
796
 *                  *
797
 ************************************************************************/
798
799
/**
800
 * xsltPointerList:
801
 *
802
 * Pointer-list for various purposes.
803
 */
804
typedef struct _xmlPointerList xmlPointerList;
805
typedef xmlPointerList *xmlPointerListPtr;
806
struct _xmlPointerList {
807
    void **items;
808
    int number;
809
    int size;
810
};
811
/*
812
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
813
* and here, we should make the functions public.
814
*/
815
static int
816
xmlPointerListAddSize(xmlPointerListPtr list,
817
           void *item,
818
           int initialSize)
819
51.5M
{
820
51.5M
    if (list->items == NULL) {
821
14.8k
  if (initialSize <= 0)
822
0
      initialSize = 1;
823
14.8k
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
824
14.8k
  if (list->items == NULL) {
825
0
      xmlXPathErrMemory(NULL,
826
0
    "xmlPointerListCreate: allocating item\n");
827
0
      return(-1);
828
0
  }
829
14.8k
  list->number = 0;
830
14.8k
  list->size = initialSize;
831
51.5M
    } else if (list->size <= list->number) {
832
9.10k
        if (list->size > 50000000) {
833
0
      xmlXPathErrMemory(NULL,
834
0
    "xmlPointerListAddSize: re-allocating item\n");
835
0
            return(-1);
836
0
        }
837
9.10k
  list->size *= 2;
838
9.10k
  list->items = (void **) xmlRealloc(list->items,
839
9.10k
      list->size * sizeof(void *));
840
9.10k
  if (list->items == NULL) {
841
0
      xmlXPathErrMemory(NULL,
842
0
    "xmlPointerListAddSize: re-allocating item\n");
843
0
      list->size = 0;
844
0
      return(-1);
845
0
  }
846
9.10k
    }
847
51.5M
    list->items[list->number++] = item;
848
51.5M
    return(0);
849
51.5M
}
850
851
/**
852
 * xsltPointerListCreate:
853
 *
854
 * Creates an xsltPointerList structure.
855
 *
856
 * Returns a xsltPointerList structure or NULL in case of an error.
857
 */
858
static xmlPointerListPtr
859
xmlPointerListCreate(int initialSize)
860
14.8k
{
861
14.8k
    xmlPointerListPtr ret;
862
863
14.8k
    ret = xmlMalloc(sizeof(xmlPointerList));
864
14.8k
    if (ret == NULL) {
865
0
  xmlXPathErrMemory(NULL,
866
0
      "xmlPointerListCreate: allocating item\n");
867
0
  return (NULL);
868
0
    }
869
14.8k
    memset(ret, 0, sizeof(xmlPointerList));
870
14.8k
    if (initialSize > 0) {
871
14.8k
  xmlPointerListAddSize(ret, NULL, initialSize);
872
14.8k
  ret->number = 0;
873
14.8k
    }
874
14.8k
    return (ret);
875
14.8k
}
876
877
/**
878
 * xsltPointerListFree:
879
 *
880
 * Frees the xsltPointerList structure. This does not free
881
 * the content of the list.
882
 */
883
static void
884
xmlPointerListFree(xmlPointerListPtr list)
885
14.6k
{
886
14.6k
    if (list == NULL)
887
0
  return;
888
14.6k
    if (list->items != NULL)
889
14.6k
  xmlFree(list->items);
890
14.6k
    xmlFree(list);
891
14.6k
}
892
893
/************************************************************************
894
 *                  *
895
 *      Parser Types          *
896
 *                  *
897
 ************************************************************************/
898
899
/*
900
 * Types are private:
901
 */
902
903
typedef enum {
904
    XPATH_OP_END=0,
905
    XPATH_OP_AND,
906
    XPATH_OP_OR,
907
    XPATH_OP_EQUAL,
908
    XPATH_OP_CMP,
909
    XPATH_OP_PLUS,
910
    XPATH_OP_MULT,
911
    XPATH_OP_UNION,
912
    XPATH_OP_ROOT,
913
    XPATH_OP_NODE,
914
    XPATH_OP_COLLECT,
915
    XPATH_OP_VALUE, /* 11 */
916
    XPATH_OP_VARIABLE,
917
    XPATH_OP_FUNCTION,
918
    XPATH_OP_ARG,
919
    XPATH_OP_PREDICATE,
920
    XPATH_OP_FILTER, /* 16 */
921
    XPATH_OP_SORT /* 17 */
922
#ifdef LIBXML_XPTR_LOCS_ENABLED
923
    ,XPATH_OP_RANGETO
924
#endif
925
} xmlXPathOp;
926
927
typedef enum {
928
    AXIS_ANCESTOR = 1,
929
    AXIS_ANCESTOR_OR_SELF,
930
    AXIS_ATTRIBUTE,
931
    AXIS_CHILD,
932
    AXIS_DESCENDANT,
933
    AXIS_DESCENDANT_OR_SELF,
934
    AXIS_FOLLOWING,
935
    AXIS_FOLLOWING_SIBLING,
936
    AXIS_NAMESPACE,
937
    AXIS_PARENT,
938
    AXIS_PRECEDING,
939
    AXIS_PRECEDING_SIBLING,
940
    AXIS_SELF
941
} xmlXPathAxisVal;
942
943
typedef enum {
944
    NODE_TEST_NONE = 0,
945
    NODE_TEST_TYPE = 1,
946
    NODE_TEST_PI = 2,
947
    NODE_TEST_ALL = 3,
948
    NODE_TEST_NS = 4,
949
    NODE_TEST_NAME = 5
950
} xmlXPathTestVal;
951
952
typedef enum {
953
    NODE_TYPE_NODE = 0,
954
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
955
    NODE_TYPE_TEXT = XML_TEXT_NODE,
956
    NODE_TYPE_PI = XML_PI_NODE
957
} xmlXPathTypeVal;
958
959
typedef struct _xmlXPathStepOp xmlXPathStepOp;
960
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
961
struct _xmlXPathStepOp {
962
    xmlXPathOp op;    /* The identifier of the operation */
963
    int ch1;      /* First child */
964
    int ch2;      /* Second child */
965
    int value;
966
    int value2;
967
    int value3;
968
    void *value4;
969
    void *value5;
970
    xmlXPathFunction cache;
971
    void *cacheURI;
972
};
973
974
struct _xmlXPathCompExpr {
975
    int nbStep;     /* Number of steps in this expression */
976
    int maxStep;    /* Maximum number of steps allocated */
977
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
978
    int last;     /* index of last step in expression */
979
    xmlChar *expr;    /* the expression being computed */
980
    xmlDictPtr dict;    /* the dictionary to use if any */
981
#ifdef DEBUG_EVAL_COUNTS
982
    int nb;
983
    xmlChar *string;
984
#endif
985
#ifdef XPATH_STREAMING
986
    xmlPatternPtr stream;
987
#endif
988
};
989
990
/************************************************************************
991
 *                  *
992
 *      Forward declarations        *
993
 *                  *
994
 ************************************************************************/
995
static void
996
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
997
static void
998
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
999
static int
1000
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
1001
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
1002
static int
1003
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
1004
          xmlXPathStepOpPtr op,
1005
          int isPredicate);
1006
static void
1007
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1008
1009
/************************************************************************
1010
 *                  *
1011
 *      Parser Type functions       *
1012
 *                  *
1013
 ************************************************************************/
1014
1015
/**
1016
 * xmlXPathNewCompExpr:
1017
 *
1018
 * Create a new Xpath component
1019
 *
1020
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1021
 */
1022
static xmlXPathCompExprPtr
1023
7.68k
xmlXPathNewCompExpr(void) {
1024
7.68k
    xmlXPathCompExprPtr cur;
1025
1026
7.68k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1027
7.68k
    if (cur == NULL) {
1028
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1029
0
  return(NULL);
1030
0
    }
1031
7.68k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1032
7.68k
    cur->maxStep = 10;
1033
7.68k
    cur->nbStep = 0;
1034
7.68k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1035
7.68k
                                     sizeof(xmlXPathStepOp));
1036
7.68k
    if (cur->steps == NULL) {
1037
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1038
0
  xmlFree(cur);
1039
0
  return(NULL);
1040
0
    }
1041
7.68k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1042
7.68k
    cur->last = -1;
1043
#ifdef DEBUG_EVAL_COUNTS
1044
    cur->nb = 0;
1045
#endif
1046
7.68k
    return(cur);
1047
7.68k
}
1048
1049
/**
1050
 * xmlXPathFreeCompExpr:
1051
 * @comp:  an XPATH comp
1052
 *
1053
 * Free up the memory allocated by @comp
1054
 */
1055
void
1056
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1057
7.68k
{
1058
7.68k
    xmlXPathStepOpPtr op;
1059
7.68k
    int i;
1060
1061
7.68k
    if (comp == NULL)
1062
0
        return;
1063
7.68k
    if (comp->dict == NULL) {
1064
626k
  for (i = 0; i < comp->nbStep; i++) {
1065
618k
      op = &comp->steps[i];
1066
618k
      if (op->value4 != NULL) {
1067
20.7k
    if (op->op == XPATH_OP_VALUE)
1068
16.2k
        xmlXPathFreeObject(op->value4);
1069
4.43k
    else
1070
4.43k
        xmlFree(op->value4);
1071
20.7k
      }
1072
618k
      if (op->value5 != NULL)
1073
109k
    xmlFree(op->value5);
1074
618k
  }
1075
7.68k
    } else {
1076
0
  for (i = 0; i < comp->nbStep; i++) {
1077
0
      op = &comp->steps[i];
1078
0
      if (op->value4 != NULL) {
1079
0
    if (op->op == XPATH_OP_VALUE)
1080
0
        xmlXPathFreeObject(op->value4);
1081
0
      }
1082
0
  }
1083
0
        xmlDictFree(comp->dict);
1084
0
    }
1085
7.68k
    if (comp->steps != NULL) {
1086
7.68k
        xmlFree(comp->steps);
1087
7.68k
    }
1088
#ifdef DEBUG_EVAL_COUNTS
1089
    if (comp->string != NULL) {
1090
        xmlFree(comp->string);
1091
    }
1092
#endif
1093
7.68k
#ifdef XPATH_STREAMING
1094
7.68k
    if (comp->stream != NULL) {
1095
494
        xmlFreePatternList(comp->stream);
1096
494
    }
1097
7.68k
#endif
1098
7.68k
    if (comp->expr != NULL) {
1099
4.68k
        xmlFree(comp->expr);
1100
4.68k
    }
1101
1102
7.68k
    xmlFree(comp);
1103
7.68k
}
1104
1105
/**
1106
 * xmlXPathCompExprAdd:
1107
 * @comp:  the compiled expression
1108
 * @ch1: first child index
1109
 * @ch2: second child index
1110
 * @op:  an op
1111
 * @value:  the first int value
1112
 * @value2:  the second int value
1113
 * @value3:  the third int value
1114
 * @value4:  the first string value
1115
 * @value5:  the second string value
1116
 *
1117
 * Add a step to an XPath Compiled Expression
1118
 *
1119
 * Returns -1 in case of failure, the index otherwise
1120
 */
1121
static int
1122
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1123
   xmlXPathOp op, int value,
1124
618k
   int value2, int value3, void *value4, void *value5) {
1125
618k
    xmlXPathCompExprPtr comp = ctxt->comp;
1126
618k
    if (comp->nbStep >= comp->maxStep) {
1127
15.8k
  xmlXPathStepOp *real;
1128
1129
15.8k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1130
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1131
0
      return(-1);
1132
0
        }
1133
15.8k
  comp->maxStep *= 2;
1134
15.8k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1135
15.8k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1136
15.8k
  if (real == NULL) {
1137
0
      comp->maxStep /= 2;
1138
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1139
0
      return(-1);
1140
0
  }
1141
15.8k
  comp->steps = real;
1142
15.8k
    }
1143
618k
    comp->last = comp->nbStep;
1144
618k
    comp->steps[comp->nbStep].ch1 = ch1;
1145
618k
    comp->steps[comp->nbStep].ch2 = ch2;
1146
618k
    comp->steps[comp->nbStep].op = op;
1147
618k
    comp->steps[comp->nbStep].value = value;
1148
618k
    comp->steps[comp->nbStep].value2 = value2;
1149
618k
    comp->steps[comp->nbStep].value3 = value3;
1150
618k
    if ((comp->dict != NULL) &&
1151
618k
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1152
0
   (op == XPATH_OP_COLLECT))) {
1153
0
        if (value4 != NULL) {
1154
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1155
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1156
0
      xmlFree(value4);
1157
0
  } else
1158
0
      comp->steps[comp->nbStep].value4 = NULL;
1159
0
        if (value5 != NULL) {
1160
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1161
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1162
0
      xmlFree(value5);
1163
0
  } else
1164
0
      comp->steps[comp->nbStep].value5 = NULL;
1165
618k
    } else {
1166
618k
  comp->steps[comp->nbStep].value4 = value4;
1167
618k
  comp->steps[comp->nbStep].value5 = value5;
1168
618k
    }
1169
618k
    comp->steps[comp->nbStep].cache = NULL;
1170
618k
    return(comp->nbStep++);
1171
618k
}
1172
1173
/**
1174
 * xmlXPathCompSwap:
1175
 * @comp:  the compiled expression
1176
 * @op: operation index
1177
 *
1178
 * Swaps 2 operations in the compiled expression
1179
 */
1180
static void
1181
2.64k
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1182
2.64k
    int tmp;
1183
1184
#ifndef LIBXML_THREAD_ENABLED
1185
    /*
1186
     * Since this manipulates possibly shared variables, this is
1187
     * disabled if one detects that the library is used in a multithreaded
1188
     * application
1189
     */
1190
    if (xmlXPathDisableOptimizer)
1191
  return;
1192
#endif
1193
1194
2.64k
    tmp = op->ch1;
1195
2.64k
    op->ch1 = op->ch2;
1196
2.64k
    op->ch2 = tmp;
1197
2.64k
}
1198
1199
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1200
181k
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1201
181k
                  (op), (val), (val2), (val3), (val4), (val5))
1202
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1203
75.8k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1204
75.8k
                  (op), (val), (val2), (val3), (val4), (val5))
1205
1206
185k
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1207
185k
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1208
1209
22.2k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1210
22.2k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1211
1212
154k
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1213
154k
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1214
154k
      (val), (val2), 0 ,NULL ,NULL)
1215
1216
/************************************************************************
1217
 *                  *
1218
 *    XPath object cache structures       *
1219
 *                  *
1220
 ************************************************************************/
1221
1222
/* #define XP_DEFAULT_CACHE_ON */
1223
1224
2.54M
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1225
1226
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1227
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1228
struct _xmlXPathContextCache {
1229
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1230
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1231
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1232
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1233
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1234
    int maxNodeset;
1235
    int maxString;
1236
    int maxBoolean;
1237
    int maxNumber;
1238
    int maxMisc;
1239
#ifdef XP_DEBUG_OBJ_USAGE
1240
    int dbgCachedAll;
1241
    int dbgCachedNodeset;
1242
    int dbgCachedString;
1243
    int dbgCachedBool;
1244
    int dbgCachedNumber;
1245
    int dbgCachedPoint;
1246
    int dbgCachedRange;
1247
    int dbgCachedLocset;
1248
    int dbgCachedUsers;
1249
    int dbgCachedXSLTTree;
1250
    int dbgCachedUndefined;
1251
1252
1253
    int dbgReusedAll;
1254
    int dbgReusedNodeset;
1255
    int dbgReusedString;
1256
    int dbgReusedBool;
1257
    int dbgReusedNumber;
1258
    int dbgReusedPoint;
1259
    int dbgReusedRange;
1260
    int dbgReusedLocset;
1261
    int dbgReusedUsers;
1262
    int dbgReusedXSLTTree;
1263
    int dbgReusedUndefined;
1264
1265
#endif
1266
};
1267
1268
/************************************************************************
1269
 *                  *
1270
 *    Debugging related functions       *
1271
 *                  *
1272
 ************************************************************************/
1273
1274
#define STRANGE             \
1275
0
    xmlGenericError(xmlGenericErrorContext,       \
1276
0
      "Internal error at %s:%d\n",        \
1277
0
            __FILE__, __LINE__);
1278
1279
#ifdef LIBXML_DEBUG_ENABLED
1280
static void
1281
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1282
0
    int i;
1283
0
    char shift[100];
1284
1285
0
    for (i = 0;((i < depth) && (i < 25));i++)
1286
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1287
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1288
0
    if (cur == NULL) {
1289
0
  fprintf(output, "%s", shift);
1290
0
  fprintf(output, "Node is NULL !\n");
1291
0
  return;
1292
1293
0
    }
1294
1295
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1296
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1297
0
  fprintf(output, "%s", shift);
1298
0
  fprintf(output, " /\n");
1299
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1300
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1301
0
    else
1302
0
  xmlDebugDumpOneNode(output, cur, depth);
1303
0
}
1304
static void
1305
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1306
0
    xmlNodePtr tmp;
1307
0
    int i;
1308
0
    char shift[100];
1309
1310
0
    for (i = 0;((i < depth) && (i < 25));i++)
1311
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1312
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1313
0
    if (cur == NULL) {
1314
0
  fprintf(output, "%s", shift);
1315
0
  fprintf(output, "Node is NULL !\n");
1316
0
  return;
1317
1318
0
    }
1319
1320
0
    while (cur != NULL) {
1321
0
  tmp = cur;
1322
0
  cur = cur->next;
1323
0
  xmlDebugDumpOneNode(output, tmp, depth);
1324
0
    }
1325
0
}
1326
1327
static void
1328
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1329
0
    int i;
1330
0
    char shift[100];
1331
1332
0
    for (i = 0;((i < depth) && (i < 25));i++)
1333
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1334
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1335
1336
0
    if (cur == NULL) {
1337
0
  fprintf(output, "%s", shift);
1338
0
  fprintf(output, "NodeSet is NULL !\n");
1339
0
  return;
1340
1341
0
    }
1342
1343
0
    if (cur != NULL) {
1344
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1345
0
  for (i = 0;i < cur->nodeNr;i++) {
1346
0
      fprintf(output, "%s", shift);
1347
0
      fprintf(output, "%d", i + 1);
1348
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1349
0
  }
1350
0
    }
1351
0
}
1352
1353
static void
1354
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1355
0
    int i;
1356
0
    char shift[100];
1357
1358
0
    for (i = 0;((i < depth) && (i < 25));i++)
1359
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1360
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1361
1362
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1363
0
  fprintf(output, "%s", shift);
1364
0
  fprintf(output, "Value Tree is NULL !\n");
1365
0
  return;
1366
1367
0
    }
1368
1369
0
    fprintf(output, "%s", shift);
1370
0
    fprintf(output, "%d", i + 1);
1371
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1372
0
}
1373
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1374
static void
1375
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1376
    int i;
1377
    char shift[100];
1378
1379
    for (i = 0;((i < depth) && (i < 25));i++)
1380
        shift[2 * i] = shift[2 * i + 1] = ' ';
1381
    shift[2 * i] = shift[2 * i + 1] = 0;
1382
1383
    if (cur == NULL) {
1384
  fprintf(output, "%s", shift);
1385
  fprintf(output, "LocationSet is NULL !\n");
1386
  return;
1387
1388
    }
1389
1390
    for (i = 0;i < cur->locNr;i++) {
1391
  fprintf(output, "%s", shift);
1392
        fprintf(output, "%d : ", i + 1);
1393
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1394
    }
1395
}
1396
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1397
1398
/**
1399
 * xmlXPathDebugDumpObject:
1400
 * @output:  the FILE * to dump the output
1401
 * @cur:  the object to inspect
1402
 * @depth:  indentation level
1403
 *
1404
 * Dump the content of the object for debugging purposes
1405
 */
1406
void
1407
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1408
0
    int i;
1409
0
    char shift[100];
1410
1411
0
    if (output == NULL) return;
1412
1413
0
    for (i = 0;((i < depth) && (i < 25));i++)
1414
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1415
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1416
1417
1418
0
    fprintf(output, "%s", shift);
1419
1420
0
    if (cur == NULL) {
1421
0
        fprintf(output, "Object is empty (NULL)\n");
1422
0
  return;
1423
0
    }
1424
0
    switch(cur->type) {
1425
0
        case XPATH_UNDEFINED:
1426
0
      fprintf(output, "Object is uninitialized\n");
1427
0
      break;
1428
0
        case XPATH_NODESET:
1429
0
      fprintf(output, "Object is a Node Set :\n");
1430
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1431
0
      break;
1432
0
  case XPATH_XSLT_TREE:
1433
0
      fprintf(output, "Object is an XSLT value tree :\n");
1434
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1435
0
      break;
1436
0
        case XPATH_BOOLEAN:
1437
0
      fprintf(output, "Object is a Boolean : ");
1438
0
      if (cur->boolval) fprintf(output, "true\n");
1439
0
      else fprintf(output, "false\n");
1440
0
      break;
1441
0
        case XPATH_NUMBER:
1442
0
      switch (xmlXPathIsInf(cur->floatval)) {
1443
0
      case 1:
1444
0
    fprintf(output, "Object is a number : Infinity\n");
1445
0
    break;
1446
0
      case -1:
1447
0
    fprintf(output, "Object is a number : -Infinity\n");
1448
0
    break;
1449
0
      default:
1450
0
    if (xmlXPathIsNaN(cur->floatval)) {
1451
0
        fprintf(output, "Object is a number : NaN\n");
1452
0
    } else if (cur->floatval == 0) {
1453
                    /* Omit sign for negative zero. */
1454
0
        fprintf(output, "Object is a number : 0\n");
1455
0
    } else {
1456
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1457
0
    }
1458
0
      }
1459
0
      break;
1460
0
        case XPATH_STRING:
1461
0
      fprintf(output, "Object is a string : ");
1462
0
      xmlDebugDumpString(output, cur->stringval);
1463
0
      fprintf(output, "\n");
1464
0
      break;
1465
#ifdef LIBXML_XPTR_LOCS_ENABLED
1466
  case XPATH_POINT:
1467
      fprintf(output, "Object is a point : index %d in node", cur->index);
1468
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1469
      fprintf(output, "\n");
1470
      break;
1471
  case XPATH_RANGE:
1472
      if ((cur->user2 == NULL) ||
1473
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1474
    fprintf(output, "Object is a collapsed range :\n");
1475
    fprintf(output, "%s", shift);
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
      } else  {
1482
    fprintf(output, "Object is a range :\n");
1483
    fprintf(output, "%s", shift);
1484
    fprintf(output, "From ");
1485
    if (cur->index >= 0)
1486
        fprintf(output, "index %d in ", cur->index);
1487
    fprintf(output, "node\n");
1488
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1489
                    depth + 1);
1490
    fprintf(output, "%s", shift);
1491
    fprintf(output, "To ");
1492
    if (cur->index2 >= 0)
1493
        fprintf(output, "index %d in ", cur->index2);
1494
    fprintf(output, "node\n");
1495
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1496
                    depth + 1);
1497
    fprintf(output, "\n");
1498
      }
1499
      break;
1500
  case XPATH_LOCATIONSET:
1501
      fprintf(output, "Object is a Location Set:\n");
1502
      xmlXPathDebugDumpLocationSet(output,
1503
        (xmlLocationSetPtr) cur->user, depth);
1504
      break;
1505
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1506
0
  case XPATH_USERS:
1507
0
      fprintf(output, "Object is user defined\n");
1508
0
      break;
1509
0
    }
1510
0
}
1511
1512
static void
1513
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1514
0
                       xmlXPathStepOpPtr op, int depth) {
1515
0
    int i;
1516
0
    char shift[100];
1517
1518
0
    for (i = 0;((i < depth) && (i < 25));i++)
1519
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1520
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1521
1522
0
    fprintf(output, "%s", shift);
1523
0
    if (op == NULL) {
1524
0
  fprintf(output, "Step is NULL\n");
1525
0
  return;
1526
0
    }
1527
0
    switch (op->op) {
1528
0
        case XPATH_OP_END:
1529
0
      fprintf(output, "END"); break;
1530
0
        case XPATH_OP_AND:
1531
0
      fprintf(output, "AND"); break;
1532
0
        case XPATH_OP_OR:
1533
0
      fprintf(output, "OR"); break;
1534
0
        case XPATH_OP_EQUAL:
1535
0
       if (op->value)
1536
0
     fprintf(output, "EQUAL =");
1537
0
       else
1538
0
     fprintf(output, "EQUAL !=");
1539
0
       break;
1540
0
        case XPATH_OP_CMP:
1541
0
       if (op->value)
1542
0
     fprintf(output, "CMP <");
1543
0
       else
1544
0
     fprintf(output, "CMP >");
1545
0
       if (!op->value2)
1546
0
     fprintf(output, "=");
1547
0
       break;
1548
0
        case XPATH_OP_PLUS:
1549
0
       if (op->value == 0)
1550
0
     fprintf(output, "PLUS -");
1551
0
       else if (op->value == 1)
1552
0
     fprintf(output, "PLUS +");
1553
0
       else if (op->value == 2)
1554
0
     fprintf(output, "PLUS unary -");
1555
0
       else if (op->value == 3)
1556
0
     fprintf(output, "PLUS unary - -");
1557
0
       break;
1558
0
        case XPATH_OP_MULT:
1559
0
       if (op->value == 0)
1560
0
     fprintf(output, "MULT *");
1561
0
       else if (op->value == 1)
1562
0
     fprintf(output, "MULT div");
1563
0
       else
1564
0
     fprintf(output, "MULT mod");
1565
0
       break;
1566
0
        case XPATH_OP_UNION:
1567
0
       fprintf(output, "UNION"); break;
1568
0
        case XPATH_OP_ROOT:
1569
0
       fprintf(output, "ROOT"); break;
1570
0
        case XPATH_OP_NODE:
1571
0
       fprintf(output, "NODE"); break;
1572
0
        case XPATH_OP_SORT:
1573
0
       fprintf(output, "SORT"); break;
1574
0
        case XPATH_OP_COLLECT: {
1575
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1576
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1577
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1578
0
      const xmlChar *prefix = op->value4;
1579
0
      const xmlChar *name = op->value5;
1580
1581
0
      fprintf(output, "COLLECT ");
1582
0
      switch (axis) {
1583
0
    case AXIS_ANCESTOR:
1584
0
        fprintf(output, " 'ancestors' "); break;
1585
0
    case AXIS_ANCESTOR_OR_SELF:
1586
0
        fprintf(output, " 'ancestors-or-self' "); break;
1587
0
    case AXIS_ATTRIBUTE:
1588
0
        fprintf(output, " 'attributes' "); break;
1589
0
    case AXIS_CHILD:
1590
0
        fprintf(output, " 'child' "); break;
1591
0
    case AXIS_DESCENDANT:
1592
0
        fprintf(output, " 'descendant' "); break;
1593
0
    case AXIS_DESCENDANT_OR_SELF:
1594
0
        fprintf(output, " 'descendant-or-self' "); break;
1595
0
    case AXIS_FOLLOWING:
1596
0
        fprintf(output, " 'following' "); break;
1597
0
    case AXIS_FOLLOWING_SIBLING:
1598
0
        fprintf(output, " 'following-siblings' "); break;
1599
0
    case AXIS_NAMESPACE:
1600
0
        fprintf(output, " 'namespace' "); break;
1601
0
    case AXIS_PARENT:
1602
0
        fprintf(output, " 'parent' "); break;
1603
0
    case AXIS_PRECEDING:
1604
0
        fprintf(output, " 'preceding' "); break;
1605
0
    case AXIS_PRECEDING_SIBLING:
1606
0
        fprintf(output, " 'preceding-sibling' "); break;
1607
0
    case AXIS_SELF:
1608
0
        fprintf(output, " 'self' "); break;
1609
0
      }
1610
0
      switch (test) {
1611
0
                case NODE_TEST_NONE:
1612
0
        fprintf(output, "'none' "); break;
1613
0
                case NODE_TEST_TYPE:
1614
0
        fprintf(output, "'type' "); break;
1615
0
                case NODE_TEST_PI:
1616
0
        fprintf(output, "'PI' "); break;
1617
0
                case NODE_TEST_ALL:
1618
0
        fprintf(output, "'all' "); break;
1619
0
                case NODE_TEST_NS:
1620
0
        fprintf(output, "'namespace' "); break;
1621
0
                case NODE_TEST_NAME:
1622
0
        fprintf(output, "'name' "); break;
1623
0
      }
1624
0
      switch (type) {
1625
0
                case NODE_TYPE_NODE:
1626
0
        fprintf(output, "'node' "); break;
1627
0
                case NODE_TYPE_COMMENT:
1628
0
        fprintf(output, "'comment' "); break;
1629
0
                case NODE_TYPE_TEXT:
1630
0
        fprintf(output, "'text' "); break;
1631
0
                case NODE_TYPE_PI:
1632
0
        fprintf(output, "'PI' "); break;
1633
0
      }
1634
0
      if (prefix != NULL)
1635
0
    fprintf(output, "%s:", prefix);
1636
0
      if (name != NULL)
1637
0
    fprintf(output, "%s", (const char *) name);
1638
0
      break;
1639
1640
0
        }
1641
0
  case XPATH_OP_VALUE: {
1642
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1643
1644
0
      fprintf(output, "ELEM ");
1645
0
      xmlXPathDebugDumpObject(output, object, 0);
1646
0
      goto finish;
1647
0
  }
1648
0
  case XPATH_OP_VARIABLE: {
1649
0
      const xmlChar *prefix = op->value5;
1650
0
      const xmlChar *name = op->value4;
1651
1652
0
      if (prefix != NULL)
1653
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1654
0
      else
1655
0
    fprintf(output, "VARIABLE %s", name);
1656
0
      break;
1657
0
  }
1658
0
  case XPATH_OP_FUNCTION: {
1659
0
      int nbargs = op->value;
1660
0
      const xmlChar *prefix = op->value5;
1661
0
      const xmlChar *name = op->value4;
1662
1663
0
      if (prefix != NULL)
1664
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1665
0
      prefix, name, nbargs);
1666
0
      else
1667
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1668
0
      break;
1669
0
  }
1670
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1671
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1672
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1673
#ifdef LIBXML_XPTR_LOCS_ENABLED
1674
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1675
#endif
1676
0
  default:
1677
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1678
0
    }
1679
0
    fprintf(output, "\n");
1680
0
finish:
1681
0
    if (op->ch1 >= 0)
1682
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1683
0
    if (op->ch2 >= 0)
1684
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1685
0
}
1686
1687
/**
1688
 * xmlXPathDebugDumpCompExpr:
1689
 * @output:  the FILE * for the output
1690
 * @comp:  the precompiled XPath expression
1691
 * @depth:  the indentation level.
1692
 *
1693
 * Dumps the tree of the compiled XPath expression.
1694
 */
1695
void
1696
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1697
0
                    int depth) {
1698
0
    int i;
1699
0
    char shift[100];
1700
1701
0
    if ((output == NULL) || (comp == NULL)) return;
1702
1703
0
    for (i = 0;((i < depth) && (i < 25));i++)
1704
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1705
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1706
1707
0
    fprintf(output, "%s", shift);
1708
1709
0
#ifdef XPATH_STREAMING
1710
0
    if (comp->stream) {
1711
0
        fprintf(output, "Streaming Expression\n");
1712
0
    } else
1713
0
#endif
1714
0
    {
1715
0
        fprintf(output, "Compiled Expression : %d elements\n",
1716
0
                comp->nbStep);
1717
0
        i = comp->last;
1718
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1719
0
    }
1720
0
}
1721
1722
#ifdef XP_DEBUG_OBJ_USAGE
1723
1724
/*
1725
* XPath object usage related debugging variables.
1726
*/
1727
static int xmlXPathDebugObjCounterUndefined = 0;
1728
static int xmlXPathDebugObjCounterNodeset = 0;
1729
static int xmlXPathDebugObjCounterBool = 0;
1730
static int xmlXPathDebugObjCounterNumber = 0;
1731
static int xmlXPathDebugObjCounterString = 0;
1732
static int xmlXPathDebugObjCounterPoint = 0;
1733
static int xmlXPathDebugObjCounterRange = 0;
1734
static int xmlXPathDebugObjCounterLocset = 0;
1735
static int xmlXPathDebugObjCounterUsers = 0;
1736
static int xmlXPathDebugObjCounterXSLTTree = 0;
1737
static int xmlXPathDebugObjCounterAll = 0;
1738
1739
static int xmlXPathDebugObjTotalUndefined = 0;
1740
static int xmlXPathDebugObjTotalNodeset = 0;
1741
static int xmlXPathDebugObjTotalBool = 0;
1742
static int xmlXPathDebugObjTotalNumber = 0;
1743
static int xmlXPathDebugObjTotalString = 0;
1744
static int xmlXPathDebugObjTotalPoint = 0;
1745
static int xmlXPathDebugObjTotalRange = 0;
1746
static int xmlXPathDebugObjTotalLocset = 0;
1747
static int xmlXPathDebugObjTotalUsers = 0;
1748
static int xmlXPathDebugObjTotalXSLTTree = 0;
1749
static int xmlXPathDebugObjTotalAll = 0;
1750
1751
static int xmlXPathDebugObjMaxUndefined = 0;
1752
static int xmlXPathDebugObjMaxNodeset = 0;
1753
static int xmlXPathDebugObjMaxBool = 0;
1754
static int xmlXPathDebugObjMaxNumber = 0;
1755
static int xmlXPathDebugObjMaxString = 0;
1756
static int xmlXPathDebugObjMaxPoint = 0;
1757
static int xmlXPathDebugObjMaxRange = 0;
1758
static int xmlXPathDebugObjMaxLocset = 0;
1759
static int xmlXPathDebugObjMaxUsers = 0;
1760
static int xmlXPathDebugObjMaxXSLTTree = 0;
1761
static int xmlXPathDebugObjMaxAll = 0;
1762
1763
static void
1764
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1765
{
1766
    if (ctxt != NULL) {
1767
  if (ctxt->cache != NULL) {
1768
      xmlXPathContextCachePtr cache =
1769
    (xmlXPathContextCachePtr) ctxt->cache;
1770
1771
      cache->dbgCachedAll = 0;
1772
      cache->dbgCachedNodeset = 0;
1773
      cache->dbgCachedString = 0;
1774
      cache->dbgCachedBool = 0;
1775
      cache->dbgCachedNumber = 0;
1776
      cache->dbgCachedPoint = 0;
1777
      cache->dbgCachedRange = 0;
1778
      cache->dbgCachedLocset = 0;
1779
      cache->dbgCachedUsers = 0;
1780
      cache->dbgCachedXSLTTree = 0;
1781
      cache->dbgCachedUndefined = 0;
1782
1783
      cache->dbgReusedAll = 0;
1784
      cache->dbgReusedNodeset = 0;
1785
      cache->dbgReusedString = 0;
1786
      cache->dbgReusedBool = 0;
1787
      cache->dbgReusedNumber = 0;
1788
      cache->dbgReusedPoint = 0;
1789
      cache->dbgReusedRange = 0;
1790
      cache->dbgReusedLocset = 0;
1791
      cache->dbgReusedUsers = 0;
1792
      cache->dbgReusedXSLTTree = 0;
1793
      cache->dbgReusedUndefined = 0;
1794
  }
1795
    }
1796
1797
    xmlXPathDebugObjCounterUndefined = 0;
1798
    xmlXPathDebugObjCounterNodeset = 0;
1799
    xmlXPathDebugObjCounterBool = 0;
1800
    xmlXPathDebugObjCounterNumber = 0;
1801
    xmlXPathDebugObjCounterString = 0;
1802
    xmlXPathDebugObjCounterPoint = 0;
1803
    xmlXPathDebugObjCounterRange = 0;
1804
    xmlXPathDebugObjCounterLocset = 0;
1805
    xmlXPathDebugObjCounterUsers = 0;
1806
    xmlXPathDebugObjCounterXSLTTree = 0;
1807
    xmlXPathDebugObjCounterAll = 0;
1808
1809
    xmlXPathDebugObjTotalUndefined = 0;
1810
    xmlXPathDebugObjTotalNodeset = 0;
1811
    xmlXPathDebugObjTotalBool = 0;
1812
    xmlXPathDebugObjTotalNumber = 0;
1813
    xmlXPathDebugObjTotalString = 0;
1814
    xmlXPathDebugObjTotalPoint = 0;
1815
    xmlXPathDebugObjTotalRange = 0;
1816
    xmlXPathDebugObjTotalLocset = 0;
1817
    xmlXPathDebugObjTotalUsers = 0;
1818
    xmlXPathDebugObjTotalXSLTTree = 0;
1819
    xmlXPathDebugObjTotalAll = 0;
1820
1821
    xmlXPathDebugObjMaxUndefined = 0;
1822
    xmlXPathDebugObjMaxNodeset = 0;
1823
    xmlXPathDebugObjMaxBool = 0;
1824
    xmlXPathDebugObjMaxNumber = 0;
1825
    xmlXPathDebugObjMaxString = 0;
1826
    xmlXPathDebugObjMaxPoint = 0;
1827
    xmlXPathDebugObjMaxRange = 0;
1828
    xmlXPathDebugObjMaxLocset = 0;
1829
    xmlXPathDebugObjMaxUsers = 0;
1830
    xmlXPathDebugObjMaxXSLTTree = 0;
1831
    xmlXPathDebugObjMaxAll = 0;
1832
1833
}
1834
1835
static void
1836
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1837
            xmlXPathObjectType objType)
1838
{
1839
    int isCached = 0;
1840
1841
    if (ctxt != NULL) {
1842
  if (ctxt->cache != NULL) {
1843
      xmlXPathContextCachePtr cache =
1844
    (xmlXPathContextCachePtr) ctxt->cache;
1845
1846
      isCached = 1;
1847
1848
      cache->dbgReusedAll++;
1849
      switch (objType) {
1850
    case XPATH_UNDEFINED:
1851
        cache->dbgReusedUndefined++;
1852
        break;
1853
    case XPATH_NODESET:
1854
        cache->dbgReusedNodeset++;
1855
        break;
1856
    case XPATH_BOOLEAN:
1857
        cache->dbgReusedBool++;
1858
        break;
1859
    case XPATH_NUMBER:
1860
        cache->dbgReusedNumber++;
1861
        break;
1862
    case XPATH_STRING:
1863
        cache->dbgReusedString++;
1864
        break;
1865
#ifdef LIBXML_XPTR_LOCS_ENABLED
1866
    case XPATH_POINT:
1867
        cache->dbgReusedPoint++;
1868
        break;
1869
    case XPATH_RANGE:
1870
        cache->dbgReusedRange++;
1871
        break;
1872
    case XPATH_LOCATIONSET:
1873
        cache->dbgReusedLocset++;
1874
        break;
1875
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1876
    case XPATH_USERS:
1877
        cache->dbgReusedUsers++;
1878
        break;
1879
    case XPATH_XSLT_TREE:
1880
        cache->dbgReusedXSLTTree++;
1881
        break;
1882
    default:
1883
        break;
1884
      }
1885
  }
1886
    }
1887
1888
    switch (objType) {
1889
  case XPATH_UNDEFINED:
1890
      if (! isCached)
1891
    xmlXPathDebugObjTotalUndefined++;
1892
      xmlXPathDebugObjCounterUndefined++;
1893
      if (xmlXPathDebugObjCounterUndefined >
1894
    xmlXPathDebugObjMaxUndefined)
1895
    xmlXPathDebugObjMaxUndefined =
1896
        xmlXPathDebugObjCounterUndefined;
1897
      break;
1898
  case XPATH_NODESET:
1899
      if (! isCached)
1900
    xmlXPathDebugObjTotalNodeset++;
1901
      xmlXPathDebugObjCounterNodeset++;
1902
      if (xmlXPathDebugObjCounterNodeset >
1903
    xmlXPathDebugObjMaxNodeset)
1904
    xmlXPathDebugObjMaxNodeset =
1905
        xmlXPathDebugObjCounterNodeset;
1906
      break;
1907
  case XPATH_BOOLEAN:
1908
      if (! isCached)
1909
    xmlXPathDebugObjTotalBool++;
1910
      xmlXPathDebugObjCounterBool++;
1911
      if (xmlXPathDebugObjCounterBool >
1912
    xmlXPathDebugObjMaxBool)
1913
    xmlXPathDebugObjMaxBool =
1914
        xmlXPathDebugObjCounterBool;
1915
      break;
1916
  case XPATH_NUMBER:
1917
      if (! isCached)
1918
    xmlXPathDebugObjTotalNumber++;
1919
      xmlXPathDebugObjCounterNumber++;
1920
      if (xmlXPathDebugObjCounterNumber >
1921
    xmlXPathDebugObjMaxNumber)
1922
    xmlXPathDebugObjMaxNumber =
1923
        xmlXPathDebugObjCounterNumber;
1924
      break;
1925
  case XPATH_STRING:
1926
      if (! isCached)
1927
    xmlXPathDebugObjTotalString++;
1928
      xmlXPathDebugObjCounterString++;
1929
      if (xmlXPathDebugObjCounterString >
1930
    xmlXPathDebugObjMaxString)
1931
    xmlXPathDebugObjMaxString =
1932
        xmlXPathDebugObjCounterString;
1933
      break;
1934
#ifdef LIBXML_XPTR_LOCS_ENABLED
1935
  case XPATH_POINT:
1936
      if (! isCached)
1937
    xmlXPathDebugObjTotalPoint++;
1938
      xmlXPathDebugObjCounterPoint++;
1939
      if (xmlXPathDebugObjCounterPoint >
1940
    xmlXPathDebugObjMaxPoint)
1941
    xmlXPathDebugObjMaxPoint =
1942
        xmlXPathDebugObjCounterPoint;
1943
      break;
1944
  case XPATH_RANGE:
1945
      if (! isCached)
1946
    xmlXPathDebugObjTotalRange++;
1947
      xmlXPathDebugObjCounterRange++;
1948
      if (xmlXPathDebugObjCounterRange >
1949
    xmlXPathDebugObjMaxRange)
1950
    xmlXPathDebugObjMaxRange =
1951
        xmlXPathDebugObjCounterRange;
1952
      break;
1953
  case XPATH_LOCATIONSET:
1954
      if (! isCached)
1955
    xmlXPathDebugObjTotalLocset++;
1956
      xmlXPathDebugObjCounterLocset++;
1957
      if (xmlXPathDebugObjCounterLocset >
1958
    xmlXPathDebugObjMaxLocset)
1959
    xmlXPathDebugObjMaxLocset =
1960
        xmlXPathDebugObjCounterLocset;
1961
      break;
1962
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1963
  case XPATH_USERS:
1964
      if (! isCached)
1965
    xmlXPathDebugObjTotalUsers++;
1966
      xmlXPathDebugObjCounterUsers++;
1967
      if (xmlXPathDebugObjCounterUsers >
1968
    xmlXPathDebugObjMaxUsers)
1969
    xmlXPathDebugObjMaxUsers =
1970
        xmlXPathDebugObjCounterUsers;
1971
      break;
1972
  case XPATH_XSLT_TREE:
1973
      if (! isCached)
1974
    xmlXPathDebugObjTotalXSLTTree++;
1975
      xmlXPathDebugObjCounterXSLTTree++;
1976
      if (xmlXPathDebugObjCounterXSLTTree >
1977
    xmlXPathDebugObjMaxXSLTTree)
1978
    xmlXPathDebugObjMaxXSLTTree =
1979
        xmlXPathDebugObjCounterXSLTTree;
1980
      break;
1981
  default:
1982
      break;
1983
    }
1984
    if (! isCached)
1985
  xmlXPathDebugObjTotalAll++;
1986
    xmlXPathDebugObjCounterAll++;
1987
    if (xmlXPathDebugObjCounterAll >
1988
  xmlXPathDebugObjMaxAll)
1989
  xmlXPathDebugObjMaxAll =
1990
      xmlXPathDebugObjCounterAll;
1991
}
1992
1993
static void
1994
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1995
            xmlXPathObjectType objType)
1996
{
1997
    int isCached = 0;
1998
1999
    if (ctxt != NULL) {
2000
  if (ctxt->cache != NULL) {
2001
      xmlXPathContextCachePtr cache =
2002
    (xmlXPathContextCachePtr) ctxt->cache;
2003
2004
      isCached = 1;
2005
2006
      cache->dbgCachedAll++;
2007
      switch (objType) {
2008
    case XPATH_UNDEFINED:
2009
        cache->dbgCachedUndefined++;
2010
        break;
2011
    case XPATH_NODESET:
2012
        cache->dbgCachedNodeset++;
2013
        break;
2014
    case XPATH_BOOLEAN:
2015
        cache->dbgCachedBool++;
2016
        break;
2017
    case XPATH_NUMBER:
2018
        cache->dbgCachedNumber++;
2019
        break;
2020
    case XPATH_STRING:
2021
        cache->dbgCachedString++;
2022
        break;
2023
#ifdef LIBXML_XPTR_LOCS_ENABLED
2024
    case XPATH_POINT:
2025
        cache->dbgCachedPoint++;
2026
        break;
2027
    case XPATH_RANGE:
2028
        cache->dbgCachedRange++;
2029
        break;
2030
    case XPATH_LOCATIONSET:
2031
        cache->dbgCachedLocset++;
2032
        break;
2033
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2034
    case XPATH_USERS:
2035
        cache->dbgCachedUsers++;
2036
        break;
2037
    case XPATH_XSLT_TREE:
2038
        cache->dbgCachedXSLTTree++;
2039
        break;
2040
    default:
2041
        break;
2042
      }
2043
2044
  }
2045
    }
2046
    switch (objType) {
2047
  case XPATH_UNDEFINED:
2048
      xmlXPathDebugObjCounterUndefined--;
2049
      break;
2050
  case XPATH_NODESET:
2051
      xmlXPathDebugObjCounterNodeset--;
2052
      break;
2053
  case XPATH_BOOLEAN:
2054
      xmlXPathDebugObjCounterBool--;
2055
      break;
2056
  case XPATH_NUMBER:
2057
      xmlXPathDebugObjCounterNumber--;
2058
      break;
2059
  case XPATH_STRING:
2060
      xmlXPathDebugObjCounterString--;
2061
      break;
2062
#ifdef LIBXML_XPTR_LOCS_ENABLED
2063
  case XPATH_POINT:
2064
      xmlXPathDebugObjCounterPoint--;
2065
      break;
2066
  case XPATH_RANGE:
2067
      xmlXPathDebugObjCounterRange--;
2068
      break;
2069
  case XPATH_LOCATIONSET:
2070
      xmlXPathDebugObjCounterLocset--;
2071
      break;
2072
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2073
  case XPATH_USERS:
2074
      xmlXPathDebugObjCounterUsers--;
2075
      break;
2076
  case XPATH_XSLT_TREE:
2077
      xmlXPathDebugObjCounterXSLTTree--;
2078
      break;
2079
  default:
2080
      break;
2081
    }
2082
    xmlXPathDebugObjCounterAll--;
2083
}
2084
2085
static void
2086
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2087
{
2088
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2089
  reqXSLTTree, reqUndefined;
2090
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2091
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2092
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2093
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2094
    int leftObjs = xmlXPathDebugObjCounterAll;
2095
2096
    reqAll = xmlXPathDebugObjTotalAll;
2097
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2098
    reqString = xmlXPathDebugObjTotalString;
2099
    reqBool = xmlXPathDebugObjTotalBool;
2100
    reqNumber = xmlXPathDebugObjTotalNumber;
2101
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2102
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2103
2104
    printf("# XPath object usage:\n");
2105
2106
    if (ctxt != NULL) {
2107
  if (ctxt->cache != NULL) {
2108
      xmlXPathContextCachePtr cache =
2109
    (xmlXPathContextCachePtr) ctxt->cache;
2110
2111
      reAll = cache->dbgReusedAll;
2112
      reqAll += reAll;
2113
      reNodeset = cache->dbgReusedNodeset;
2114
      reqNodeset += reNodeset;
2115
      reString = cache->dbgReusedString;
2116
      reqString += reString;
2117
      reBool = cache->dbgReusedBool;
2118
      reqBool += reBool;
2119
      reNumber = cache->dbgReusedNumber;
2120
      reqNumber += reNumber;
2121
      reXSLTTree = cache->dbgReusedXSLTTree;
2122
      reqXSLTTree += reXSLTTree;
2123
      reUndefined = cache->dbgReusedUndefined;
2124
      reqUndefined += reUndefined;
2125
2126
      caAll = cache->dbgCachedAll;
2127
      caBool = cache->dbgCachedBool;
2128
      caNodeset = cache->dbgCachedNodeset;
2129
      caString = cache->dbgCachedString;
2130
      caNumber = cache->dbgCachedNumber;
2131
      caXSLTTree = cache->dbgCachedXSLTTree;
2132
      caUndefined = cache->dbgCachedUndefined;
2133
2134
      if (cache->nodesetObjs)
2135
    leftObjs -= cache->nodesetObjs->number;
2136
      if (cache->stringObjs)
2137
    leftObjs -= cache->stringObjs->number;
2138
      if (cache->booleanObjs)
2139
    leftObjs -= cache->booleanObjs->number;
2140
      if (cache->numberObjs)
2141
    leftObjs -= cache->numberObjs->number;
2142
      if (cache->miscObjs)
2143
    leftObjs -= cache->miscObjs->number;
2144
  }
2145
    }
2146
2147
    printf("# all\n");
2148
    printf("#   total  : %d\n", reqAll);
2149
    printf("#   left  : %d\n", leftObjs);
2150
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2151
    printf("#   reused : %d\n", reAll);
2152
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2153
2154
    printf("# node-sets\n");
2155
    printf("#   total  : %d\n", reqNodeset);
2156
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2157
    printf("#   reused : %d\n", reNodeset);
2158
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2159
2160
    printf("# strings\n");
2161
    printf("#   total  : %d\n", reqString);
2162
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2163
    printf("#   reused : %d\n", reString);
2164
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2165
2166
    printf("# booleans\n");
2167
    printf("#   total  : %d\n", reqBool);
2168
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2169
    printf("#   reused : %d\n", reBool);
2170
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2171
2172
    printf("# numbers\n");
2173
    printf("#   total  : %d\n", reqNumber);
2174
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2175
    printf("#   reused : %d\n", reNumber);
2176
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2177
2178
    printf("# XSLT result tree fragments\n");
2179
    printf("#   total  : %d\n", reqXSLTTree);
2180
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2181
    printf("#   reused : %d\n", reXSLTTree);
2182
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2183
2184
    printf("# undefined\n");
2185
    printf("#   total  : %d\n", reqUndefined);
2186
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2187
    printf("#   reused : %d\n", reUndefined);
2188
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2189
2190
}
2191
2192
#endif /* XP_DEBUG_OBJ_USAGE */
2193
2194
#endif /* LIBXML_DEBUG_ENABLED */
2195
2196
/************************************************************************
2197
 *                  *
2198
 *      XPath object caching        *
2199
 *                  *
2200
 ************************************************************************/
2201
2202
/**
2203
 * xmlXPathNewCache:
2204
 *
2205
 * Create a new object cache
2206
 *
2207
 * Returns the xmlXPathCache just allocated.
2208
 */
2209
static xmlXPathContextCachePtr
2210
xmlXPathNewCache(void)
2211
5.90k
{
2212
5.90k
    xmlXPathContextCachePtr ret;
2213
2214
5.90k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2215
5.90k
    if (ret == NULL) {
2216
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2217
0
  return(NULL);
2218
0
    }
2219
5.90k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2220
5.90k
    ret->maxNodeset = 100;
2221
5.90k
    ret->maxString = 100;
2222
5.90k
    ret->maxBoolean = 100;
2223
5.90k
    ret->maxNumber = 100;
2224
5.90k
    ret->maxMisc = 100;
2225
5.90k
    return(ret);
2226
5.90k
}
2227
2228
static void
2229
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2230
14.6k
{
2231
14.6k
    int i;
2232
14.6k
    xmlXPathObjectPtr obj;
2233
2234
14.6k
    if (list == NULL)
2235
0
  return;
2236
2237
247k
    for (i = 0; i < list->number; i++) {
2238
232k
  obj = list->items[i];
2239
  /*
2240
  * Note that it is already assured that we don't need to
2241
  * look out for namespace nodes in the node-set.
2242
  */
2243
232k
  if (obj->nodesetval != NULL) {
2244
205k
      if (obj->nodesetval->nodeTab != NULL)
2245
184k
    xmlFree(obj->nodesetval->nodeTab);
2246
205k
      xmlFree(obj->nodesetval);
2247
205k
  }
2248
232k
  xmlFree(obj);
2249
#ifdef XP_DEBUG_OBJ_USAGE
2250
  xmlXPathDebugObjCounterAll--;
2251
#endif
2252
232k
    }
2253
14.6k
    xmlPointerListFree(list);
2254
14.6k
}
2255
2256
static void
2257
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2258
5.18k
{
2259
5.18k
    if (cache == NULL)
2260
0
  return;
2261
5.18k
    if (cache->nodesetObjs)
2262
4.43k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2263
5.18k
    if (cache->stringObjs)
2264
1.59k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2265
5.18k
    if (cache->booleanObjs)
2266
2.66k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2267
5.18k
    if (cache->numberObjs)
2268
3.12k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2269
5.18k
    if (cache->miscObjs)
2270
2.85k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2271
5.18k
    xmlFree(cache);
2272
5.18k
}
2273
2274
/**
2275
 * xmlXPathContextSetCache:
2276
 *
2277
 * @ctxt:  the XPath context
2278
 * @active: enables/disables (creates/frees) the cache
2279
 * @value: a value with semantics dependent on @options
2280
 * @options: options (currently only the value 0 is used)
2281
 *
2282
 * Creates/frees an object cache on the XPath context.
2283
 * If activates XPath objects (xmlXPathObject) will be cached internally
2284
 * to be reused.
2285
 * @options:
2286
 *   0: This will set the XPath object caching:
2287
 *      @value:
2288
 *        This will set the maximum number of XPath objects
2289
 *        to be cached per slot
2290
 *        There are 5 slots for: node-set, string, number, boolean, and
2291
 *        misc objects. Use <0 for the default number (100).
2292
 *   Other values for @options have currently no effect.
2293
 *
2294
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2295
 */
2296
int
2297
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2298
      int active,
2299
      int value,
2300
      int options)
2301
11.0k
{
2302
11.0k
    if (ctxt == NULL)
2303
0
  return(-1);
2304
11.0k
    if (active) {
2305
5.90k
  xmlXPathContextCachePtr cache;
2306
2307
5.90k
  if (ctxt->cache == NULL) {
2308
5.90k
      ctxt->cache = xmlXPathNewCache();
2309
5.90k
      if (ctxt->cache == NULL)
2310
0
    return(-1);
2311
5.90k
  }
2312
5.90k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2313
5.90k
  if (options == 0) {
2314
5.90k
      if (value < 0)
2315
5.90k
    value = 100;
2316
5.90k
      cache->maxNodeset = value;
2317
5.90k
      cache->maxString = value;
2318
5.90k
      cache->maxNumber = value;
2319
5.90k
      cache->maxBoolean = value;
2320
5.90k
      cache->maxMisc = value;
2321
5.90k
  }
2322
5.90k
    } else if (ctxt->cache != NULL) {
2323
5.18k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2324
5.18k
  ctxt->cache = NULL;
2325
5.18k
    }
2326
11.0k
    return(0);
2327
11.0k
}
2328
2329
/**
2330
 * xmlXPathCacheWrapNodeSet:
2331
 * @ctxt: the XPath context
2332
 * @val:  the NodePtr value
2333
 *
2334
 * This is the cached version of xmlXPathWrapNodeSet().
2335
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2336
 *
2337
 * Returns the created or reused object.
2338
 */
2339
static xmlXPathObjectPtr
2340
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2341
19.7M
{
2342
19.7M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2343
19.7M
  xmlXPathContextCachePtr cache =
2344
19.7M
      (xmlXPathContextCachePtr) ctxt->cache;
2345
2346
19.7M
  if ((cache->miscObjs != NULL) &&
2347
19.7M
      (cache->miscObjs->number != 0))
2348
17.6M
  {
2349
17.6M
      xmlXPathObjectPtr ret;
2350
2351
17.6M
      ret = (xmlXPathObjectPtr)
2352
17.6M
    cache->miscObjs->items[--cache->miscObjs->number];
2353
17.6M
      ret->type = XPATH_NODESET;
2354
17.6M
      ret->nodesetval = val;
2355
#ifdef XP_DEBUG_OBJ_USAGE
2356
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2357
#endif
2358
17.6M
      return(ret);
2359
17.6M
  }
2360
19.7M
    }
2361
2362
2.11M
    return(xmlXPathWrapNodeSet(val));
2363
2364
19.7M
}
2365
2366
/**
2367
 * xmlXPathCacheWrapString:
2368
 * @ctxt: the XPath context
2369
 * @val:  the xmlChar * value
2370
 *
2371
 * This is the cached version of xmlXPathWrapString().
2372
 * Wraps the @val string into an XPath object.
2373
 *
2374
 * Returns the created or reused object.
2375
 */
2376
static xmlXPathObjectPtr
2377
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2378
81.1k
{
2379
81.1k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2380
81.1k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2381
2382
81.1k
  if ((cache->stringObjs != NULL) &&
2383
81.1k
      (cache->stringObjs->number != 0))
2384
80.9k
  {
2385
2386
80.9k
      xmlXPathObjectPtr ret;
2387
2388
80.9k
      ret = (xmlXPathObjectPtr)
2389
80.9k
    cache->stringObjs->items[--cache->stringObjs->number];
2390
80.9k
      ret->type = XPATH_STRING;
2391
80.9k
      ret->stringval = val;
2392
#ifdef XP_DEBUG_OBJ_USAGE
2393
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394
#endif
2395
80.9k
      return(ret);
2396
80.9k
  } else if ((cache->miscObjs != NULL) &&
2397
114
      (cache->miscObjs->number != 0))
2398
5
  {
2399
5
      xmlXPathObjectPtr ret;
2400
      /*
2401
      * Fallback to misc-cache.
2402
      */
2403
5
      ret = (xmlXPathObjectPtr)
2404
5
    cache->miscObjs->items[--cache->miscObjs->number];
2405
2406
5
      ret->type = XPATH_STRING;
2407
5
      ret->stringval = val;
2408
#ifdef XP_DEBUG_OBJ_USAGE
2409
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2410
#endif
2411
5
      return(ret);
2412
5
  }
2413
81.1k
    }
2414
109
    return(xmlXPathWrapString(val));
2415
81.1k
}
2416
2417
/**
2418
 * xmlXPathCacheNewNodeSet:
2419
 * @ctxt: the XPath context
2420
 * @val:  the NodePtr value
2421
 *
2422
 * This is the cached version of xmlXPathNewNodeSet().
2423
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2424
 * it with the single Node @val
2425
 *
2426
 * Returns the created or reused object.
2427
 */
2428
static xmlXPathObjectPtr
2429
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2430
14.5M
{
2431
14.5M
    if ((ctxt != NULL) && (ctxt->cache)) {
2432
14.5M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2433
2434
14.5M
  if ((cache->nodesetObjs != NULL) &&
2435
14.5M
      (cache->nodesetObjs->number != 0))
2436
14.4M
  {
2437
14.4M
      xmlXPathObjectPtr ret;
2438
      /*
2439
      * Use the nodeset-cache.
2440
      */
2441
14.4M
      ret = (xmlXPathObjectPtr)
2442
14.4M
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2443
14.4M
      ret->type = XPATH_NODESET;
2444
14.4M
      ret->boolval = 0;
2445
14.4M
      if (val) {
2446
14.4M
    if ((ret->nodesetval->nodeMax == 0) ||
2447
14.4M
        (val->type == XML_NAMESPACE_DECL))
2448
565k
    {
2449
                    /* TODO: Check memory error. */
2450
565k
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2451
13.9M
    } else {
2452
13.9M
        ret->nodesetval->nodeTab[0] = val;
2453
13.9M
        ret->nodesetval->nodeNr = 1;
2454
13.9M
    }
2455
14.4M
      }
2456
#ifdef XP_DEBUG_OBJ_USAGE
2457
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2458
#endif
2459
14.4M
      return(ret);
2460
14.4M
  } else if ((cache->miscObjs != NULL) &&
2461
13.4k
      (cache->miscObjs->number != 0))
2462
4.15k
  {
2463
4.15k
      xmlXPathObjectPtr ret;
2464
      /*
2465
      * Fallback to misc-cache.
2466
      */
2467
2468
4.15k
      ret = (xmlXPathObjectPtr)
2469
4.15k
    cache->miscObjs->items[--cache->miscObjs->number];
2470
2471
4.15k
      ret->type = XPATH_NODESET;
2472
4.15k
      ret->boolval = 0;
2473
4.15k
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2474
4.15k
      if (ret->nodesetval == NULL) {
2475
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2476
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2477
0
    return(NULL);
2478
0
      }
2479
#ifdef XP_DEBUG_OBJ_USAGE
2480
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2481
#endif
2482
4.15k
      return(ret);
2483
4.15k
  }
2484
14.5M
    }
2485
9.33k
    return(xmlXPathNewNodeSet(val));
2486
14.5M
}
2487
2488
/**
2489
 * xmlXPathCacheNewCString:
2490
 * @ctxt: the XPath context
2491
 * @val:  the char * value
2492
 *
2493
 * This is the cached version of xmlXPathNewCString().
2494
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2495
 *
2496
 * Returns the created or reused object.
2497
 */
2498
static xmlXPathObjectPtr
2499
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2500
25.5k
{
2501
25.5k
    if ((ctxt != NULL) && (ctxt->cache)) {
2502
25.5k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2503
2504
25.5k
  if ((cache->stringObjs != NULL) &&
2505
25.5k
      (cache->stringObjs->number != 0))
2506
25.4k
  {
2507
25.4k
      xmlXPathObjectPtr ret;
2508
2509
25.4k
      ret = (xmlXPathObjectPtr)
2510
25.4k
    cache->stringObjs->items[--cache->stringObjs->number];
2511
2512
25.4k
      ret->type = XPATH_STRING;
2513
25.4k
      ret->stringval = xmlStrdup(BAD_CAST val);
2514
#ifdef XP_DEBUG_OBJ_USAGE
2515
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516
#endif
2517
25.4k
      return(ret);
2518
25.4k
  } else if ((cache->miscObjs != NULL) &&
2519
70
      (cache->miscObjs->number != 0))
2520
27
  {
2521
27
      xmlXPathObjectPtr ret;
2522
2523
27
      ret = (xmlXPathObjectPtr)
2524
27
    cache->miscObjs->items[--cache->miscObjs->number];
2525
2526
27
      ret->type = XPATH_STRING;
2527
27
      ret->stringval = xmlStrdup(BAD_CAST val);
2528
#ifdef XP_DEBUG_OBJ_USAGE
2529
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2530
#endif
2531
27
      return(ret);
2532
27
  }
2533
25.5k
    }
2534
43
    return(xmlXPathNewCString(val));
2535
25.5k
}
2536
2537
/**
2538
 * xmlXPathCacheNewString:
2539
 * @ctxt: the XPath context
2540
 * @val:  the xmlChar * value
2541
 *
2542
 * This is the cached version of xmlXPathNewString().
2543
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2544
 *
2545
 * Returns the created or reused object.
2546
 */
2547
static xmlXPathObjectPtr
2548
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2549
2.23M
{
2550
2.23M
    if ((ctxt != NULL) && (ctxt->cache)) {
2551
2.23M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2552
2553
2.23M
  if ((cache->stringObjs != NULL) &&
2554
2.23M
      (cache->stringObjs->number != 0))
2555
2.23M
  {
2556
2.23M
      xmlXPathObjectPtr ret;
2557
2558
2.23M
      ret = (xmlXPathObjectPtr)
2559
2.23M
    cache->stringObjs->items[--cache->stringObjs->number];
2560
2.23M
      ret->type = XPATH_STRING;
2561
2.23M
      if (val != NULL)
2562
2.23M
    ret->stringval = xmlStrdup(val);
2563
0
      else
2564
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2565
#ifdef XP_DEBUG_OBJ_USAGE
2566
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2567
#endif
2568
2.23M
      return(ret);
2569
2.23M
  } else if ((cache->miscObjs != NULL) &&
2570
3.77k
      (cache->miscObjs->number != 0))
2571
183
  {
2572
183
      xmlXPathObjectPtr ret;
2573
2574
183
      ret = (xmlXPathObjectPtr)
2575
183
    cache->miscObjs->items[--cache->miscObjs->number];
2576
2577
183
      ret->type = XPATH_STRING;
2578
183
      if (val != NULL)
2579
183
    ret->stringval = xmlStrdup(val);
2580
0
      else
2581
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2582
#ifdef XP_DEBUG_OBJ_USAGE
2583
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2584
#endif
2585
183
      return(ret);
2586
183
  }
2587
2.23M
    }
2588
3.58k
    return(xmlXPathNewString(val));
2589
2.23M
}
2590
2591
/**
2592
 * xmlXPathCacheNewBoolean:
2593
 * @ctxt: the XPath context
2594
 * @val:  the boolean value
2595
 *
2596
 * This is the cached version of xmlXPathNewBoolean().
2597
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2598
 *
2599
 * Returns the created or reused object.
2600
 */
2601
static xmlXPathObjectPtr
2602
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2603
7.44M
{
2604
7.44M
    if ((ctxt != NULL) && (ctxt->cache)) {
2605
7.44M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606
2607
7.44M
  if ((cache->booleanObjs != NULL) &&
2608
7.44M
      (cache->booleanObjs->number != 0))
2609
7.43M
  {
2610
7.43M
      xmlXPathObjectPtr ret;
2611
2612
7.43M
      ret = (xmlXPathObjectPtr)
2613
7.43M
    cache->booleanObjs->items[--cache->booleanObjs->number];
2614
7.43M
      ret->type = XPATH_BOOLEAN;
2615
7.43M
      ret->boolval = (val != 0);
2616
#ifdef XP_DEBUG_OBJ_USAGE
2617
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2618
#endif
2619
7.43M
      return(ret);
2620
7.43M
  } else if ((cache->miscObjs != NULL) &&
2621
7.19k
      (cache->miscObjs->number != 0))
2622
853
  {
2623
853
      xmlXPathObjectPtr ret;
2624
2625
853
      ret = (xmlXPathObjectPtr)
2626
853
    cache->miscObjs->items[--cache->miscObjs->number];
2627
2628
853
      ret->type = XPATH_BOOLEAN;
2629
853
      ret->boolval = (val != 0);
2630
#ifdef XP_DEBUG_OBJ_USAGE
2631
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2632
#endif
2633
853
      return(ret);
2634
853
  }
2635
7.44M
    }
2636
6.34k
    return(xmlXPathNewBoolean(val));
2637
7.44M
}
2638
2639
/**
2640
 * xmlXPathCacheNewFloat:
2641
 * @ctxt: the XPath context
2642
 * @val:  the double value
2643
 *
2644
 * This is the cached version of xmlXPathNewFloat().
2645
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2646
 *
2647
 * Returns the created or reused object.
2648
 */
2649
static xmlXPathObjectPtr
2650
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2651
9.37M
{
2652
9.37M
     if ((ctxt != NULL) && (ctxt->cache)) {
2653
9.37M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2654
2655
9.37M
  if ((cache->numberObjs != NULL) &&
2656
9.37M
      (cache->numberObjs->number != 0))
2657
9.35M
  {
2658
9.35M
      xmlXPathObjectPtr ret;
2659
2660
9.35M
      ret = (xmlXPathObjectPtr)
2661
9.35M
    cache->numberObjs->items[--cache->numberObjs->number];
2662
9.35M
      ret->type = XPATH_NUMBER;
2663
9.35M
      ret->floatval = val;
2664
#ifdef XP_DEBUG_OBJ_USAGE
2665
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2666
#endif
2667
9.35M
      return(ret);
2668
9.35M
  } else if ((cache->miscObjs != NULL) &&
2669
25.1k
      (cache->miscObjs->number != 0))
2670
1.13k
  {
2671
1.13k
      xmlXPathObjectPtr ret;
2672
2673
1.13k
      ret = (xmlXPathObjectPtr)
2674
1.13k
    cache->miscObjs->items[--cache->miscObjs->number];
2675
2676
1.13k
      ret->type = XPATH_NUMBER;
2677
1.13k
      ret->floatval = val;
2678
#ifdef XP_DEBUG_OBJ_USAGE
2679
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2680
#endif
2681
1.13k
      return(ret);
2682
1.13k
  }
2683
9.37M
    }
2684
24.0k
    return(xmlXPathNewFloat(val));
2685
9.37M
}
2686
2687
/**
2688
 * xmlXPathCacheConvertString:
2689
 * @ctxt: the XPath context
2690
 * @val:  an XPath object
2691
 *
2692
 * This is the cached version of xmlXPathConvertString().
2693
 * Converts an existing object to its string() equivalent
2694
 *
2695
 * Returns a created or reused object, the old one is freed (cached)
2696
 *         (or the operation is done directly on @val)
2697
 */
2698
2699
static xmlXPathObjectPtr
2700
62.8k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2701
62.8k
    xmlChar *res = NULL;
2702
2703
62.8k
    if (val == NULL)
2704
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2705
2706
62.8k
    switch (val->type) {
2707
0
    case XPATH_UNDEFINED:
2708
#ifdef DEBUG_EXPR
2709
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2710
#endif
2711
0
  break;
2712
0
    case XPATH_NODESET:
2713
0
    case XPATH_XSLT_TREE:
2714
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2715
0
  break;
2716
2.19k
    case XPATH_STRING:
2717
2.19k
  return(val);
2718
2.15k
    case XPATH_BOOLEAN:
2719
2.15k
  res = xmlXPathCastBooleanToString(val->boolval);
2720
2.15k
  break;
2721
58.4k
    case XPATH_NUMBER:
2722
58.4k
  res = xmlXPathCastNumberToString(val->floatval);
2723
58.4k
  break;
2724
0
    case XPATH_USERS:
2725
#ifdef LIBXML_XPTR_LOCS_ENABLED
2726
    case XPATH_POINT:
2727
    case XPATH_RANGE:
2728
    case XPATH_LOCATIONSET:
2729
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2730
0
  TODO;
2731
0
  break;
2732
62.8k
    }
2733
60.6k
    xmlXPathReleaseObject(ctxt, val);
2734
60.6k
    if (res == NULL)
2735
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2736
60.6k
    return(xmlXPathCacheWrapString(ctxt, res));
2737
60.6k
}
2738
2739
/**
2740
 * xmlXPathCacheObjectCopy:
2741
 * @ctxt: the XPath context
2742
 * @val:  the original object
2743
 *
2744
 * This is the cached version of xmlXPathObjectCopy().
2745
 * Acquire a copy of a given object
2746
 *
2747
 * Returns a created or reused created object.
2748
 */
2749
static xmlXPathObjectPtr
2750
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2751
2.54M
{
2752
2.54M
    if (val == NULL)
2753
2
  return(NULL);
2754
2755
2.54M
    if (XP_HAS_CACHE(ctxt)) {
2756
2.54M
  switch (val->type) {
2757
0
      case XPATH_NODESET:
2758
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2759
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2760
681k
      case XPATH_STRING:
2761
681k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2762
0
      case XPATH_BOOLEAN:
2763
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2764
1.85M
      case XPATH_NUMBER:
2765
1.85M
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2766
0
      default:
2767
0
    break;
2768
2.54M
  }
2769
2.54M
    }
2770
0
    return(xmlXPathObjectCopy(val));
2771
2.54M
}
2772
2773
/**
2774
 * xmlXPathCacheConvertBoolean:
2775
 * @ctxt: the XPath context
2776
 * @val:  an XPath object
2777
 *
2778
 * This is the cached version of xmlXPathConvertBoolean().
2779
 * Converts an existing object to its boolean() equivalent
2780
 *
2781
 * Returns a created or reused object, the old one is freed (or the operation
2782
 *         is done directly on @val)
2783
 */
2784
static xmlXPathObjectPtr
2785
1.21M
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2786
1.21M
    xmlXPathObjectPtr ret;
2787
2788
1.21M
    if (val == NULL)
2789
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2790
1.21M
    if (val->type == XPATH_BOOLEAN)
2791
151k
  return(val);
2792
1.06M
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2793
1.06M
    xmlXPathReleaseObject(ctxt, val);
2794
1.06M
    return(ret);
2795
1.21M
}
2796
2797
/**
2798
 * xmlXPathCacheConvertNumber:
2799
 * @ctxt: the XPath context
2800
 * @val:  an XPath object
2801
 *
2802
 * This is the cached version of xmlXPathConvertNumber().
2803
 * Converts an existing object to its number() equivalent
2804
 *
2805
 * Returns a created or reused object, the old one is freed (or the operation
2806
 *         is done directly on @val)
2807
 */
2808
static xmlXPathObjectPtr
2809
7.50M
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2810
7.50M
    xmlXPathObjectPtr ret;
2811
2812
7.50M
    if (val == NULL)
2813
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2814
7.50M
    if (val->type == XPATH_NUMBER)
2815
0
  return(val);
2816
7.50M
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2817
7.50M
    xmlXPathReleaseObject(ctxt, val);
2818
7.50M
    return(ret);
2819
7.50M
}
2820
2821
/************************************************************************
2822
 *                  *
2823
 *    Parser stacks related functions and macros    *
2824
 *                  *
2825
 ************************************************************************/
2826
2827
/**
2828
 * xmlXPathSetFrame:
2829
 * @ctxt: an XPath parser context
2830
 *
2831
 * Set the callee evaluation frame
2832
 *
2833
 * Returns the previous frame value to be restored once done
2834
 */
2835
static int
2836
159k
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2837
159k
    int ret;
2838
2839
159k
    if (ctxt == NULL)
2840
0
        return(0);
2841
159k
    ret = ctxt->valueFrame;
2842
159k
    ctxt->valueFrame = ctxt->valueNr;
2843
159k
    return(ret);
2844
159k
}
2845
2846
/**
2847
 * xmlXPathPopFrame:
2848
 * @ctxt: an XPath parser context
2849
 * @frame: the previous frame value
2850
 *
2851
 * Remove the callee evaluation frame
2852
 */
2853
static void
2854
159k
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2855
159k
    if (ctxt == NULL)
2856
0
        return;
2857
159k
    if (ctxt->valueNr < ctxt->valueFrame) {
2858
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2859
0
    }
2860
159k
    ctxt->valueFrame = frame;
2861
159k
}
2862
2863
/**
2864
 * valuePop:
2865
 * @ctxt: an XPath evaluation context
2866
 *
2867
 * Pops the top XPath object from the value stack
2868
 *
2869
 * Returns the XPath object just removed
2870
 */
2871
xmlXPathObjectPtr
2872
valuePop(xmlXPathParserContextPtr ctxt)
2873
60.5M
{
2874
60.5M
    xmlXPathObjectPtr ret;
2875
2876
60.5M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2877
0
        return (NULL);
2878
2879
60.5M
    if (ctxt->valueNr <= ctxt->valueFrame) {
2880
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2881
0
        return (NULL);
2882
0
    }
2883
2884
60.5M
    ctxt->valueNr--;
2885
60.5M
    if (ctxt->valueNr > 0)
2886
60.4M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2887
103k
    else
2888
103k
        ctxt->value = NULL;
2889
60.5M
    ret = ctxt->valueTab[ctxt->valueNr];
2890
60.5M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2891
60.5M
    return (ret);
2892
60.5M
}
2893
/**
2894
 * valuePush:
2895
 * @ctxt:  an XPath evaluation context
2896
 * @value:  the XPath object
2897
 *
2898
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2899
 * a memory error is recorded in the parser context.
2900
 *
2901
 * Returns the number of items on the value stack, or -1 in case of error.
2902
 */
2903
int
2904
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2905
60.6M
{
2906
60.6M
    if (ctxt == NULL) return(-1);
2907
60.6M
    if (value == NULL) {
2908
        /*
2909
         * A NULL value typically indicates that a memory allocation failed,
2910
         * so we set ctxt->error here to propagate the error.
2911
         */
2912
0
  ctxt->error = XPATH_MEMORY_ERROR;
2913
0
        return(-1);
2914
0
    }
2915
60.6M
    if (ctxt->valueNr >= ctxt->valueMax) {
2916
650
        xmlXPathObjectPtr *tmp;
2917
2918
650
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2919
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2920
0
            return (-1);
2921
0
        }
2922
650
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2923
650
                                             2 * ctxt->valueMax *
2924
650
                                             sizeof(ctxt->valueTab[0]));
2925
650
        if (tmp == NULL) {
2926
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2927
0
            return (-1);
2928
0
        }
2929
650
        ctxt->valueMax *= 2;
2930
650
  ctxt->valueTab = tmp;
2931
650
    }
2932
60.6M
    ctxt->valueTab[ctxt->valueNr] = value;
2933
60.6M
    ctxt->value = value;
2934
60.6M
    return (ctxt->valueNr++);
2935
60.6M
}
2936
2937
/**
2938
 * xmlXPathPopBoolean:
2939
 * @ctxt:  an XPath parser context
2940
 *
2941
 * Pops a boolean from the stack, handling conversion if needed.
2942
 * Check error with #xmlXPathCheckError.
2943
 *
2944
 * Returns the boolean
2945
 */
2946
int
2947
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2948
0
    xmlXPathObjectPtr obj;
2949
0
    int ret;
2950
2951
0
    obj = valuePop(ctxt);
2952
0
    if (obj == NULL) {
2953
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2954
0
  return(0);
2955
0
    }
2956
0
    if (obj->type != XPATH_BOOLEAN)
2957
0
  ret = xmlXPathCastToBoolean(obj);
2958
0
    else
2959
0
        ret = obj->boolval;
2960
0
    xmlXPathReleaseObject(ctxt->context, obj);
2961
0
    return(ret);
2962
0
}
2963
2964
/**
2965
 * xmlXPathPopNumber:
2966
 * @ctxt:  an XPath parser context
2967
 *
2968
 * Pops a number from the stack, handling conversion if needed.
2969
 * Check error with #xmlXPathCheckError.
2970
 *
2971
 * Returns the number
2972
 */
2973
double
2974
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2975
0
    xmlXPathObjectPtr obj;
2976
0
    double ret;
2977
2978
0
    obj = valuePop(ctxt);
2979
0
    if (obj == NULL) {
2980
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2981
0
  return(0);
2982
0
    }
2983
0
    if (obj->type != XPATH_NUMBER)
2984
0
  ret = xmlXPathCastToNumber(obj);
2985
0
    else
2986
0
        ret = obj->floatval;
2987
0
    xmlXPathReleaseObject(ctxt->context, obj);
2988
0
    return(ret);
2989
0
}
2990
2991
/**
2992
 * xmlXPathPopString:
2993
 * @ctxt:  an XPath parser context
2994
 *
2995
 * Pops a string from the stack, handling conversion if needed.
2996
 * Check error with #xmlXPathCheckError.
2997
 *
2998
 * Returns the string
2999
 */
3000
xmlChar *
3001
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
3002
0
    xmlXPathObjectPtr obj;
3003
0
    xmlChar * ret;
3004
3005
0
    obj = valuePop(ctxt);
3006
0
    if (obj == NULL) {
3007
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3008
0
  return(NULL);
3009
0
    }
3010
0
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
3011
    /* TODO: needs refactoring somewhere else */
3012
0
    if (obj->stringval == ret)
3013
0
  obj->stringval = NULL;
3014
0
    xmlXPathReleaseObject(ctxt->context, obj);
3015
0
    return(ret);
3016
0
}
3017
3018
/**
3019
 * xmlXPathPopNodeSet:
3020
 * @ctxt:  an XPath parser context
3021
 *
3022
 * Pops a node-set from the stack, handling conversion if needed.
3023
 * Check error with #xmlXPathCheckError.
3024
 *
3025
 * Returns the node-set
3026
 */
3027
xmlNodeSetPtr
3028
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3029
0
    xmlXPathObjectPtr obj;
3030
0
    xmlNodeSetPtr ret;
3031
3032
0
    if (ctxt == NULL) return(NULL);
3033
0
    if (ctxt->value == NULL) {
3034
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3035
0
  return(NULL);
3036
0
    }
3037
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3038
0
  xmlXPathSetTypeError(ctxt);
3039
0
  return(NULL);
3040
0
    }
3041
0
    obj = valuePop(ctxt);
3042
0
    ret = obj->nodesetval;
3043
#if 0
3044
    /* to fix memory leak of not clearing obj->user */
3045
    if (obj->boolval && obj->user != NULL)
3046
        xmlFreeNodeList((xmlNodePtr) obj->user);
3047
#endif
3048
0
    obj->nodesetval = NULL;
3049
0
    xmlXPathReleaseObject(ctxt->context, obj);
3050
0
    return(ret);
3051
0
}
3052
3053
/**
3054
 * xmlXPathPopExternal:
3055
 * @ctxt:  an XPath parser context
3056
 *
3057
 * Pops an external object from the stack, handling conversion if needed.
3058
 * Check error with #xmlXPathCheckError.
3059
 *
3060
 * Returns the object
3061
 */
3062
void *
3063
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3064
0
    xmlXPathObjectPtr obj;
3065
0
    void * ret;
3066
3067
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3068
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3069
0
  return(NULL);
3070
0
    }
3071
0
    if (ctxt->value->type != XPATH_USERS) {
3072
0
  xmlXPathSetTypeError(ctxt);
3073
0
  return(NULL);
3074
0
    }
3075
0
    obj = valuePop(ctxt);
3076
0
    ret = obj->user;
3077
0
    obj->user = NULL;
3078
0
    xmlXPathReleaseObject(ctxt->context, obj);
3079
0
    return(ret);
3080
0
}
3081
3082
/*
3083
 * Macros for accessing the content. Those should be used only by the parser,
3084
 * and not exported.
3085
 *
3086
 * Dirty macros, i.e. one need to make assumption on the context to use them
3087
 *
3088
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3089
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3090
 *           in ISO-Latin or UTF-8.
3091
 *           This should be used internally by the parser
3092
 *           only to compare to ASCII values otherwise it would break when
3093
 *           running with UTF-8 encoding.
3094
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3095
 *           to compare on ASCII based substring.
3096
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3097
 *           strings within the parser.
3098
 *   CURRENT Returns the current char value, with the full decoding of
3099
 *           UTF-8 if we are using this mode. It returns an int.
3100
 *   NEXT    Skip to the next character, this does the proper decoding
3101
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3102
 *           It returns the pointer to the current xmlChar.
3103
 */
3104
3105
5.19M
#define CUR (*ctxt->cur)
3106
60.9k
#define SKIP(val) ctxt->cur += (val)
3107
604k
#define NXT(val) ctxt->cur[(val)]
3108
4.09k
#define CUR_PTR ctxt->cur
3109
505k
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3110
3111
#define COPY_BUF(l,b,i,v)                                              \
3112
194k
    if (l == 1) b[i++] = v;                                            \
3113
194k
    else i += xmlCopyChar(l,&b[i],v)
3114
3115
378k
#define NEXTL(l)  ctxt->cur += l
3116
3117
#define SKIP_BLANKS             \
3118
2.71M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3119
3120
#define CURRENT (*ctxt->cur)
3121
2.03M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3122
3123
3124
#ifndef DBL_DIG
3125
#define DBL_DIG 16
3126
#endif
3127
#ifndef DBL_EPSILON
3128
#define DBL_EPSILON 1E-9
3129
#endif
3130
3131
8.98k
#define UPPER_DOUBLE 1E9
3132
884
#define LOWER_DOUBLE 1E-5
3133
#define LOWER_DOUBLE_EXP 5
3134
3135
#define INTEGER_DIGITS DBL_DIG
3136
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3137
8.32k
#define EXPONENT_DIGITS (3 + 2)
3138
3139
/**
3140
 * xmlXPathFormatNumber:
3141
 * @number:     number to format
3142
 * @buffer:     output buffer
3143
 * @buffersize: size of output buffer
3144
 *
3145
 * Convert the number into a string representation.
3146
 */
3147
static void
3148
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3149
42.8k
{
3150
42.8k
    switch (xmlXPathIsInf(number)) {
3151
0
    case 1:
3152
0
  if (buffersize > (int)sizeof("Infinity"))
3153
0
      snprintf(buffer, buffersize, "Infinity");
3154
0
  break;
3155
0
    case -1:
3156
0
  if (buffersize > (int)sizeof("-Infinity"))
3157
0
      snprintf(buffer, buffersize, "-Infinity");
3158
0
  break;
3159
42.8k
    default:
3160
42.8k
  if (xmlXPathIsNaN(number)) {
3161
0
      if (buffersize > (int)sizeof("NaN"))
3162
0
    snprintf(buffer, buffersize, "NaN");
3163
42.8k
  } else if (number == 0) {
3164
            /* Omit sign for negative zero. */
3165
0
      snprintf(buffer, buffersize, "0");
3166
42.8k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3167
42.8k
                   (number == (int) number)) {
3168
33.8k
      char work[30];
3169
33.8k
      char *ptr, *cur;
3170
33.8k
      int value = (int) number;
3171
3172
33.8k
            ptr = &buffer[0];
3173
33.8k
      if (value == 0) {
3174
0
    *ptr++ = '0';
3175
33.8k
      } else {
3176
33.8k
    snprintf(work, 29, "%d", value);
3177
33.8k
    cur = &work[0];
3178
135k
    while ((*cur) && (ptr - buffer < buffersize)) {
3179
101k
        *ptr++ = *cur++;
3180
101k
    }
3181
33.8k
      }
3182
33.8k
      if (ptr - buffer < buffersize) {
3183
33.8k
    *ptr = 0;
3184
33.8k
      } else if (buffersize > 0) {
3185
0
    ptr--;
3186
0
    *ptr = 0;
3187
0
      }
3188
33.8k
  } else {
3189
      /*
3190
        For the dimension of work,
3191
            DBL_DIG is number of significant digits
3192
      EXPONENT is only needed for "scientific notation"
3193
            3 is sign, decimal point, and terminating zero
3194
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3195
        Note that this dimension is slightly (a few characters)
3196
        larger than actually necessary.
3197
      */
3198
8.98k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3199
8.98k
      int integer_place, fraction_place;
3200
8.98k
      char *ptr;
3201
8.98k
      char *after_fraction;
3202
8.98k
      double absolute_value;
3203
8.98k
      int size;
3204
3205
8.98k
      absolute_value = fabs(number);
3206
3207
      /*
3208
       * First choose format - scientific or regular floating point.
3209
       * In either case, result is in work, and after_fraction points
3210
       * just past the fractional part.
3211
      */
3212
8.98k
      if ( ((absolute_value > UPPER_DOUBLE) ||
3213
8.98k
      (absolute_value < LOWER_DOUBLE)) &&
3214
8.98k
     (absolute_value != 0.0) ) {
3215
    /* Use scientific notation */
3216
8.32k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3217
8.32k
    fraction_place = DBL_DIG - 1;
3218
8.32k
    size = snprintf(work, sizeof(work),"%*.*e",
3219
8.32k
       integer_place, fraction_place, number);
3220
43.0k
    while ((size > 0) && (work[size] != 'e')) size--;
3221
3222
8.32k
      }
3223
658
      else {
3224
    /* Use regular notation */
3225
658
    if (absolute_value > 0.0) {
3226
658
        integer_place = (int)log10(absolute_value);
3227
658
        if (integer_place > 0)
3228
242
            fraction_place = DBL_DIG - integer_place - 1;
3229
416
        else
3230
416
            fraction_place = DBL_DIG - integer_place;
3231
658
    } else {
3232
0
        fraction_place = 1;
3233
0
    }
3234
658
    size = snprintf(work, sizeof(work), "%0.*f",
3235
658
        fraction_place, number);
3236
658
      }
3237
3238
      /* Remove leading spaces sometimes inserted by snprintf */
3239
10.9k
      while (work[0] == ' ') {
3240
40.4k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3241
1.92k
    size--;
3242
1.92k
      }
3243
3244
      /* Remove fractional trailing zeroes */
3245
8.98k
      after_fraction = work + size;
3246
8.98k
      ptr = after_fraction;
3247
67.3k
      while (*(--ptr) == '0')
3248
58.3k
    ;
3249
8.98k
      if (*ptr != '.')
3250
6.30k
          ptr++;
3251
43.7k
      while ((*ptr++ = *after_fraction++) != 0);
3252
3253
      /* Finally copy result back to caller */
3254
8.98k
      size = strlen(work) + 1;
3255
8.98k
      if (size > buffersize) {
3256
0
    work[buffersize - 1] = 0;
3257
0
    size = buffersize;
3258
0
      }
3259
8.98k
      memmove(buffer, work, size);
3260
8.98k
  }
3261
42.8k
  break;
3262
42.8k
    }
3263
42.8k
}
3264
3265
3266
/************************************************************************
3267
 *                  *
3268
 *      Routines to handle NodeSets     *
3269
 *                  *
3270
 ************************************************************************/
3271
3272
/**
3273
 * xmlXPathOrderDocElems:
3274
 * @doc:  an input document
3275
 *
3276
 * Call this routine to speed up XPath computation on static documents.
3277
 * This stamps all the element nodes with the document order
3278
 * Like for line information, the order is kept in the element->content
3279
 * field, the value stored is actually - the node number (starting at -1)
3280
 * to be able to differentiate from line numbers.
3281
 *
3282
 * Returns the number of elements found in the document or -1 in case
3283
 *    of error.
3284
 */
3285
long
3286
363
xmlXPathOrderDocElems(xmlDocPtr doc) {
3287
363
    ptrdiff_t count = 0;
3288
363
    xmlNodePtr cur;
3289
3290
363
    if (doc == NULL)
3291
0
  return(-1);
3292
363
    cur = doc->children;
3293
14.5k
    while (cur != NULL) {
3294
14.1k
  if (cur->type == XML_ELEMENT_NODE) {
3295
4.35k
      cur->content = (void *) (-(++count));
3296
4.35k
      if (cur->children != NULL) {
3297
3.26k
    cur = cur->children;
3298
3.26k
    continue;
3299
3.26k
      }
3300
4.35k
  }
3301
10.8k
  if (cur->next != NULL) {
3302
7.62k
      cur = cur->next;
3303
7.62k
      continue;
3304
7.62k
  }
3305
3.63k
  do {
3306
3.63k
      cur = cur->parent;
3307
3.63k
      if (cur == NULL)
3308
0
    break;
3309
3.63k
      if (cur == (xmlNodePtr) doc) {
3310
363
    cur = NULL;
3311
363
    break;
3312
363
      }
3313
3.26k
      if (cur->next != NULL) {
3314
2.90k
    cur = cur->next;
3315
2.90k
    break;
3316
2.90k
      }
3317
3.26k
  } while (cur != NULL);
3318
3.26k
    }
3319
363
    return(count);
3320
363
}
3321
3322
/**
3323
 * xmlXPathCmpNodes:
3324
 * @node1:  the first node
3325
 * @node2:  the second node
3326
 *
3327
 * Compare two nodes w.r.t document order
3328
 *
3329
 * Returns -2 in case of error 1 if first point < second point, 0 if
3330
 *         it's the same node, -1 otherwise
3331
 */
3332
int
3333
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3334
0
    int depth1, depth2;
3335
0
    int attr1 = 0, attr2 = 0;
3336
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3337
0
    xmlNodePtr cur, root;
3338
3339
0
    if ((node1 == NULL) || (node2 == NULL))
3340
0
  return(-2);
3341
    /*
3342
     * a couple of optimizations which will avoid computations in most cases
3343
     */
3344
0
    if (node1 == node2)   /* trivial case */
3345
0
  return(0);
3346
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
3347
0
  attr1 = 1;
3348
0
  attrNode1 = node1;
3349
0
  node1 = node1->parent;
3350
0
    }
3351
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
3352
0
  attr2 = 1;
3353
0
  attrNode2 = node2;
3354
0
  node2 = node2->parent;
3355
0
    }
3356
0
    if (node1 == node2) {
3357
0
  if (attr1 == attr2) {
3358
      /* not required, but we keep attributes in order */
3359
0
      if (attr1 != 0) {
3360
0
          cur = attrNode2->prev;
3361
0
    while (cur != NULL) {
3362
0
        if (cur == attrNode1)
3363
0
            return (1);
3364
0
        cur = cur->prev;
3365
0
    }
3366
0
    return (-1);
3367
0
      }
3368
0
      return(0);
3369
0
  }
3370
0
  if (attr2 == 1)
3371
0
      return(1);
3372
0
  return(-1);
3373
0
    }
3374
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
3375
0
        (node2->type == XML_NAMESPACE_DECL))
3376
0
  return(1);
3377
0
    if (node1 == node2->prev)
3378
0
  return(1);
3379
0
    if (node1 == node2->next)
3380
0
  return(-1);
3381
3382
    /*
3383
     * Speedup using document order if available.
3384
     */
3385
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3386
0
  (node2->type == XML_ELEMENT_NODE) &&
3387
0
  (0 > (ptrdiff_t) node1->content) &&
3388
0
  (0 > (ptrdiff_t) node2->content) &&
3389
0
  (node1->doc == node2->doc)) {
3390
0
  ptrdiff_t l1, l2;
3391
3392
0
  l1 = -((ptrdiff_t) node1->content);
3393
0
  l2 = -((ptrdiff_t) node2->content);
3394
0
  if (l1 < l2)
3395
0
      return(1);
3396
0
  if (l1 > l2)
3397
0
      return(-1);
3398
0
    }
3399
3400
    /*
3401
     * compute depth to root
3402
     */
3403
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3404
0
  if (cur->parent == node1)
3405
0
      return(1);
3406
0
  depth2++;
3407
0
    }
3408
0
    root = cur;
3409
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3410
0
  if (cur->parent == node2)
3411
0
      return(-1);
3412
0
  depth1++;
3413
0
    }
3414
    /*
3415
     * Distinct document (or distinct entities :-( ) case.
3416
     */
3417
0
    if (root != cur) {
3418
0
  return(-2);
3419
0
    }
3420
    /*
3421
     * get the nearest common ancestor.
3422
     */
3423
0
    while (depth1 > depth2) {
3424
0
  depth1--;
3425
0
  node1 = node1->parent;
3426
0
    }
3427
0
    while (depth2 > depth1) {
3428
0
  depth2--;
3429
0
  node2 = node2->parent;
3430
0
    }
3431
0
    while (node1->parent != node2->parent) {
3432
0
  node1 = node1->parent;
3433
0
  node2 = node2->parent;
3434
  /* should not happen but just in case ... */
3435
0
  if ((node1 == NULL) || (node2 == NULL))
3436
0
      return(-2);
3437
0
    }
3438
    /*
3439
     * Find who's first.
3440
     */
3441
0
    if (node1 == node2->prev)
3442
0
  return(1);
3443
0
    if (node1 == node2->next)
3444
0
  return(-1);
3445
    /*
3446
     * Speedup using document order if available.
3447
     */
3448
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3449
0
  (node2->type == XML_ELEMENT_NODE) &&
3450
0
  (0 > (ptrdiff_t) node1->content) &&
3451
0
  (0 > (ptrdiff_t) node2->content) &&
3452
0
  (node1->doc == node2->doc)) {
3453
0
  ptrdiff_t l1, l2;
3454
3455
0
  l1 = -((ptrdiff_t) node1->content);
3456
0
  l2 = -((ptrdiff_t) node2->content);
3457
0
  if (l1 < l2)
3458
0
      return(1);
3459
0
  if (l1 > l2)
3460
0
      return(-1);
3461
0
    }
3462
3463
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
3464
0
  if (cur == node2)
3465
0
      return(1);
3466
0
    return(-1); /* assume there is no sibling list corruption */
3467
0
}
3468
3469
/**
3470
 * xmlXPathNodeSetSort:
3471
 * @set:  the node set
3472
 *
3473
 * Sort the node set in document order
3474
 */
3475
void
3476
1.22M
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3477
#ifndef WITH_TIM_SORT
3478
    int i, j, incr, len;
3479
    xmlNodePtr tmp;
3480
#endif
3481
3482
1.22M
    if (set == NULL)
3483
0
  return;
3484
3485
#ifndef WITH_TIM_SORT
3486
    /*
3487
     * Use the old Shell's sort implementation to sort the node-set
3488
     * Timsort ought to be quite faster
3489
     */
3490
    len = set->nodeNr;
3491
    for (incr = len / 2; incr > 0; incr /= 2) {
3492
  for (i = incr; i < len; i++) {
3493
      j = i - incr;
3494
      while (j >= 0) {
3495
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3496
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3497
      set->nodeTab[j + incr]) == -1)
3498
#else
3499
    if (xmlXPathCmpNodes(set->nodeTab[j],
3500
      set->nodeTab[j + incr]) == -1)
3501
#endif
3502
    {
3503
        tmp = set->nodeTab[j];
3504
        set->nodeTab[j] = set->nodeTab[j + incr];
3505
        set->nodeTab[j + incr] = tmp;
3506
        j -= incr;
3507
    } else
3508
        break;
3509
      }
3510
  }
3511
    }
3512
#else /* WITH_TIM_SORT */
3513
1.22M
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3514
1.22M
#endif /* WITH_TIM_SORT */
3515
1.22M
}
3516
3517
22.3M
#define XML_NODESET_DEFAULT 10
3518
/**
3519
 * xmlXPathNodeSetDupNs:
3520
 * @node:  the parent node of the namespace XPath node
3521
 * @ns:  the libxml namespace declaration node.
3522
 *
3523
 * Namespace node in libxml don't match the XPath semantic. In a node set
3524
 * the namespace nodes are duplicated and the next pointer is set to the
3525
 * parent node in the XPath semantic.
3526
 *
3527
 * Returns the newly created object.
3528
 */
3529
static xmlNodePtr
3530
1.75M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3531
1.75M
    xmlNsPtr cur;
3532
3533
1.75M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3534
0
  return(NULL);
3535
1.75M
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3536
0
  return((xmlNodePtr) ns);
3537
3538
    /*
3539
     * Allocate a new Namespace and fill the fields.
3540
     */
3541
1.75M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3542
1.75M
    if (cur == NULL) {
3543
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3544
0
  return(NULL);
3545
0
    }
3546
1.75M
    memset(cur, 0, sizeof(xmlNs));
3547
1.75M
    cur->type = XML_NAMESPACE_DECL;
3548
1.75M
    if (ns->href != NULL)
3549
1.75M
  cur->href = xmlStrdup(ns->href);
3550
1.75M
    if (ns->prefix != NULL)
3551
1.75M
  cur->prefix = xmlStrdup(ns->prefix);
3552
1.75M
    cur->next = (xmlNsPtr) node;
3553
1.75M
    return((xmlNodePtr) cur);
3554
1.75M
}
3555
3556
/**
3557
 * xmlXPathNodeSetFreeNs:
3558
 * @ns:  the XPath namespace node found in a nodeset.
3559
 *
3560
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3561
 * the namespace nodes are duplicated and the next pointer is set to the
3562
 * parent node in the XPath semantic. Check if such a node needs to be freed
3563
 */
3564
void
3565
1.75M
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3566
1.75M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3567
0
  return;
3568
3569
1.75M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3570
1.75M
  if (ns->href != NULL)
3571
1.75M
      xmlFree((xmlChar *)ns->href);
3572
1.75M
  if (ns->prefix != NULL)
3573
1.75M
      xmlFree((xmlChar *)ns->prefix);
3574
1.75M
  xmlFree(ns);
3575
1.75M
    }
3576
1.75M
}
3577
3578
/**
3579
 * xmlXPathNodeSetCreate:
3580
 * @val:  an initial xmlNodePtr, or NULL
3581
 *
3582
 * Create a new xmlNodeSetPtr of type double and of value @val
3583
 *
3584
 * Returns the newly created object.
3585
 */
3586
xmlNodeSetPtr
3587
17.0M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3588
17.0M
    xmlNodeSetPtr ret;
3589
3590
17.0M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3591
17.0M
    if (ret == NULL) {
3592
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3593
0
  return(NULL);
3594
0
    }
3595
17.0M
    memset(ret, 0 , sizeof(xmlNodeSet));
3596
17.0M
    if (val != NULL) {
3597
12.9k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3598
12.9k
               sizeof(xmlNodePtr));
3599
12.9k
  if (ret->nodeTab == NULL) {
3600
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3601
0
      xmlFree(ret);
3602
0
      return(NULL);
3603
0
  }
3604
12.9k
  memset(ret->nodeTab, 0 ,
3605
12.9k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3606
12.9k
        ret->nodeMax = XML_NODESET_DEFAULT;
3607
12.9k
  if (val->type == XML_NAMESPACE_DECL) {
3608
11
      xmlNsPtr ns = (xmlNsPtr) val;
3609
3610
            /* TODO: Check memory error. */
3611
11
      ret->nodeTab[ret->nodeNr++] =
3612
11
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3613
11
  } else
3614
12.9k
      ret->nodeTab[ret->nodeNr++] = val;
3615
12.9k
    }
3616
17.0M
    return(ret);
3617
17.0M
}
3618
3619
/**
3620
 * xmlXPathNodeSetContains:
3621
 * @cur:  the node-set
3622
 * @val:  the node
3623
 *
3624
 * checks whether @cur contains @val
3625
 *
3626
 * Returns true (1) if @cur contains @val, false (0) otherwise
3627
 */
3628
int
3629
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3630
0
    int i;
3631
3632
0
    if ((cur == NULL) || (val == NULL)) return(0);
3633
0
    if (val->type == XML_NAMESPACE_DECL) {
3634
0
  for (i = 0; i < cur->nodeNr; i++) {
3635
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3636
0
    xmlNsPtr ns1, ns2;
3637
3638
0
    ns1 = (xmlNsPtr) val;
3639
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3640
0
    if (ns1 == ns2)
3641
0
        return(1);
3642
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3643
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3644
0
        return(1);
3645
0
      }
3646
0
  }
3647
0
    } else {
3648
0
  for (i = 0; i < cur->nodeNr; i++) {
3649
0
      if (cur->nodeTab[i] == val)
3650
0
    return(1);
3651
0
  }
3652
0
    }
3653
0
    return(0);
3654
0
}
3655
3656
/**
3657
 * xmlXPathNodeSetAddNs:
3658
 * @cur:  the initial node set
3659
 * @node:  the hosting node
3660
 * @ns:  a the namespace node
3661
 *
3662
 * add a new namespace node to an existing NodeSet
3663
 *
3664
 * Returns 0 in case of success and -1 in case of error
3665
 */
3666
int
3667
938k
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3668
938k
    int i;
3669
3670
3671
938k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3672
938k
        (ns->type != XML_NAMESPACE_DECL) ||
3673
938k
  (node->type != XML_ELEMENT_NODE))
3674
0
  return(-1);
3675
3676
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3677
    /*
3678
     * prevent duplicates
3679
     */
3680
1.72M
    for (i = 0;i < cur->nodeNr;i++) {
3681
789k
        if ((cur->nodeTab[i] != NULL) &&
3682
789k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3683
789k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3684
789k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3685
0
      return(0);
3686
789k
    }
3687
3688
    /*
3689
     * grow the nodeTab if needed
3690
     */
3691
938k
    if (cur->nodeMax == 0) {
3692
86.7k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3693
86.7k
               sizeof(xmlNodePtr));
3694
86.7k
  if (cur->nodeTab == NULL) {
3695
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3696
0
      return(-1);
3697
0
  }
3698
86.7k
  memset(cur->nodeTab, 0 ,
3699
86.7k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3700
86.7k
        cur->nodeMax = XML_NODESET_DEFAULT;
3701
851k
    } else if (cur->nodeNr == cur->nodeMax) {
3702
0
        xmlNodePtr *temp;
3703
3704
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3705
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3706
0
            return(-1);
3707
0
        }
3708
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3709
0
              sizeof(xmlNodePtr));
3710
0
  if (temp == NULL) {
3711
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3712
0
      return(-1);
3713
0
  }
3714
0
        cur->nodeMax *= 2;
3715
0
  cur->nodeTab = temp;
3716
0
    }
3717
    /* TODO: Check memory error. */
3718
938k
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3719
938k
    return(0);
3720
938k
}
3721
3722
/**
3723
 * xmlXPathNodeSetAdd:
3724
 * @cur:  the initial node set
3725
 * @val:  a new xmlNodePtr
3726
 *
3727
 * add a new xmlNodePtr to an existing NodeSet
3728
 *
3729
 * Returns 0 in case of success, and -1 in case of error
3730
 */
3731
int
3732
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3733
0
    int i;
3734
3735
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3736
3737
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3738
    /*
3739
     * prevent duplicates
3740
     */
3741
0
    for (i = 0;i < cur->nodeNr;i++)
3742
0
        if (cur->nodeTab[i] == val) return(0);
3743
3744
    /*
3745
     * grow the nodeTab if needed
3746
     */
3747
0
    if (cur->nodeMax == 0) {
3748
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3749
0
               sizeof(xmlNodePtr));
3750
0
  if (cur->nodeTab == NULL) {
3751
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3752
0
      return(-1);
3753
0
  }
3754
0
  memset(cur->nodeTab, 0 ,
3755
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3756
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3757
0
    } else if (cur->nodeNr == cur->nodeMax) {
3758
0
        xmlNodePtr *temp;
3759
3760
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3761
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3762
0
            return(-1);
3763
0
        }
3764
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3765
0
              sizeof(xmlNodePtr));
3766
0
  if (temp == NULL) {
3767
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3768
0
      return(-1);
3769
0
  }
3770
0
        cur->nodeMax *= 2;
3771
0
  cur->nodeTab = temp;
3772
0
    }
3773
0
    if (val->type == XML_NAMESPACE_DECL) {
3774
0
  xmlNsPtr ns = (xmlNsPtr) val;
3775
3776
        /* TODO: Check memory error. */
3777
0
  cur->nodeTab[cur->nodeNr++] =
3778
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3779
0
    } else
3780
0
  cur->nodeTab[cur->nodeNr++] = val;
3781
0
    return(0);
3782
0
}
3783
3784
/**
3785
 * xmlXPathNodeSetAddUnique:
3786
 * @cur:  the initial node set
3787
 * @val:  a new xmlNodePtr
3788
 *
3789
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3790
 * when we are sure the node is not already in the set.
3791
 *
3792
 * Returns 0 in case of success and -1 in case of failure
3793
 */
3794
int
3795
78.4M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3796
78.4M
    if ((cur == NULL) || (val == NULL)) return(-1);
3797
3798
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3799
    /*
3800
     * grow the nodeTab if needed
3801
     */
3802
78.4M
    if (cur->nodeMax == 0) {
3803
6.77M
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3804
6.77M
               sizeof(xmlNodePtr));
3805
6.77M
  if (cur->nodeTab == NULL) {
3806
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3807
0
      return(-1);
3808
0
  }
3809
6.77M
  memset(cur->nodeTab, 0 ,
3810
6.77M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3811
6.77M
        cur->nodeMax = XML_NODESET_DEFAULT;
3812
71.6M
    } else if (cur->nodeNr == cur->nodeMax) {
3813
3.23M
        xmlNodePtr *temp;
3814
3815
3.23M
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3816
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3817
0
            return(-1);
3818
0
        }
3819
3.23M
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3820
3.23M
              sizeof(xmlNodePtr));
3821
3.23M
  if (temp == NULL) {
3822
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3823
0
      return(-1);
3824
0
  }
3825
3.23M
  cur->nodeTab = temp;
3826
3.23M
        cur->nodeMax *= 2;
3827
3.23M
    }
3828
78.4M
    if (val->type == XML_NAMESPACE_DECL) {
3829
201k
  xmlNsPtr ns = (xmlNsPtr) val;
3830
3831
        /* TODO: Check memory error. */
3832
201k
  cur->nodeTab[cur->nodeNr++] =
3833
201k
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3834
201k
    } else
3835
78.2M
  cur->nodeTab[cur->nodeNr++] = val;
3836
78.4M
    return(0);
3837
78.4M
}
3838
3839
/**
3840
 * xmlXPathNodeSetMerge:
3841
 * @val1:  the first NodeSet or NULL
3842
 * @val2:  the second NodeSet
3843
 *
3844
 * Merges two nodesets, all nodes from @val2 are added to @val1
3845
 * if @val1 is NULL, a new set is created and copied from @val2
3846
 *
3847
 * Returns @val1 once extended or NULL in case of error.
3848
 */
3849
xmlNodeSetPtr
3850
1.37M
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3851
1.37M
    int i, j, initNr, skip;
3852
1.37M
    xmlNodePtr n1, n2;
3853
3854
1.37M
    if (val2 == NULL) return(val1);
3855
1.27M
    if (val1 == NULL) {
3856
366k
  val1 = xmlXPathNodeSetCreate(NULL);
3857
366k
    if (val1 == NULL)
3858
0
        return (NULL);
3859
#if 0
3860
  /*
3861
  * TODO: The optimization won't work in every case, since
3862
  *  those nasty namespace nodes need to be added with
3863
  *  xmlXPathNodeSetDupNs() to the set; thus a pure
3864
  *  memcpy is not possible.
3865
  *  If there was a flag on the nodesetval, indicating that
3866
  *  some temporary nodes are in, that would be helpful.
3867
  */
3868
  /*
3869
  * Optimization: Create an equally sized node-set
3870
  * and memcpy the content.
3871
  */
3872
  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3873
  if (val1 == NULL)
3874
      return(NULL);
3875
  if (val2->nodeNr != 0) {
3876
      if (val2->nodeNr == 1)
3877
    *(val1->nodeTab) = *(val2->nodeTab);
3878
      else {
3879
    memcpy(val1->nodeTab, val2->nodeTab,
3880
        val2->nodeNr * sizeof(xmlNodePtr));
3881
      }
3882
      val1->nodeNr = val2->nodeNr;
3883
  }
3884
  return(val1);
3885
#endif
3886
366k
    }
3887
3888
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3889
1.27M
    initNr = val1->nodeNr;
3890
3891
7.47M
    for (i = 0;i < val2->nodeNr;i++) {
3892
6.20M
  n2 = val2->nodeTab[i];
3893
  /*
3894
   * check against duplicates
3895
   */
3896
6.20M
  skip = 0;
3897
44.7M
  for (j = 0; j < initNr; j++) {
3898
39.6M
      n1 = val1->nodeTab[j];
3899
39.6M
      if (n1 == n2) {
3900
1.11M
    skip = 1;
3901
1.11M
    break;
3902
38.5M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3903
38.5M
           (n2->type == XML_NAMESPACE_DECL)) {
3904
58.5k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3905
58.5k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3906
6.70k
      ((xmlNsPtr) n2)->prefix)))
3907
3.36k
    {
3908
3.36k
        skip = 1;
3909
3.36k
        break;
3910
3.36k
    }
3911
58.5k
      }
3912
39.6M
  }
3913
6.20M
  if (skip)
3914
1.11M
      continue;
3915
3916
  /*
3917
   * grow the nodeTab if needed
3918
   */
3919
5.09M
  if (val1->nodeMax == 0) {
3920
303k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3921
303k
                sizeof(xmlNodePtr));
3922
303k
      if (val1->nodeTab == NULL) {
3923
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3924
0
    return(NULL);
3925
0
      }
3926
303k
      memset(val1->nodeTab, 0 ,
3927
303k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3928
303k
      val1->nodeMax = XML_NODESET_DEFAULT;
3929
4.78M
  } else if (val1->nodeNr == val1->nodeMax) {
3930
250k
      xmlNodePtr *temp;
3931
3932
250k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3933
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3934
0
                return(NULL);
3935
0
            }
3936
250k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3937
250k
               sizeof(xmlNodePtr));
3938
250k
      if (temp == NULL) {
3939
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3940
0
    return(NULL);
3941
0
      }
3942
250k
      val1->nodeTab = temp;
3943
250k
      val1->nodeMax *= 2;
3944
250k
  }
3945
5.09M
  if (n2->type == XML_NAMESPACE_DECL) {
3946
613k
      xmlNsPtr ns = (xmlNsPtr) n2;
3947
3948
            /* TODO: Check memory error. */
3949
613k
      val1->nodeTab[val1->nodeNr++] =
3950
613k
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3951
613k
  } else
3952
4.47M
      val1->nodeTab[val1->nodeNr++] = n2;
3953
5.09M
    }
3954
3955
1.27M
    return(val1);
3956
1.27M
}
3957
3958
3959
/**
3960
 * xmlXPathNodeSetMergeAndClear:
3961
 * @set1:  the first NodeSet or NULL
3962
 * @set2:  the second NodeSet
3963
 *
3964
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3965
 * Checks for duplicate nodes. Clears set2.
3966
 *
3967
 * Returns @set1 once extended or NULL in case of error.
3968
 */
3969
static xmlNodeSetPtr
3970
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3971
6.18M
{
3972
6.18M
    {
3973
6.18M
  int i, j, initNbSet1;
3974
6.18M
  xmlNodePtr n1, n2;
3975
3976
6.18M
  initNbSet1 = set1->nodeNr;
3977
17.1M
  for (i = 0;i < set2->nodeNr;i++) {
3978
11.0M
      n2 = set2->nodeTab[i];
3979
      /*
3980
      * Skip duplicates.
3981
      */
3982
120M
      for (j = 0; j < initNbSet1; j++) {
3983
118M
    n1 = set1->nodeTab[j];
3984
118M
    if (n1 == n2) {
3985
8.76M
        goto skip_node;
3986
109M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3987
109M
        (n2->type == XML_NAMESPACE_DECL))
3988
314k
    {
3989
314k
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3990
314k
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3991
19.1k
      ((xmlNsPtr) n2)->prefix)))
3992
0
        {
3993
      /*
3994
      * Free the namespace node.
3995
      */
3996
0
      set2->nodeTab[i] = NULL;
3997
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3998
0
      goto skip_node;
3999
0
        }
4000
314k
    }
4001
118M
      }
4002
      /*
4003
      * grow the nodeTab if needed
4004
      */
4005
2.24M
      if (set1->nodeMax == 0) {
4006
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008
0
    if (set1->nodeTab == NULL) {
4009
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4010
0
        return(NULL);
4011
0
    }
4012
0
    memset(set1->nodeTab, 0,
4013
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4014
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4015
2.24M
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
75.4k
    xmlNodePtr *temp;
4017
4018
75.4k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    return(NULL);
4021
0
                }
4022
75.4k
    temp = (xmlNodePtr *) xmlRealloc(
4023
75.4k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
75.4k
    if (temp == NULL) {
4025
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
0
        return(NULL);
4027
0
    }
4028
75.4k
    set1->nodeTab = temp;
4029
75.4k
    set1->nodeMax *= 2;
4030
75.4k
      }
4031
2.24M
      set1->nodeTab[set1->nodeNr++] = n2;
4032
11.0M
skip_node:
4033
11.0M
      {}
4034
11.0M
  }
4035
6.18M
    }
4036
6.18M
    set2->nodeNr = 0;
4037
6.18M
    return(set1);
4038
6.18M
}
4039
4040
/**
4041
 * xmlXPathNodeSetMergeAndClearNoDupls:
4042
 * @set1:  the first NodeSet or NULL
4043
 * @set2:  the second NodeSet
4044
 *
4045
 * Merges two nodesets, all nodes from @set2 are added to @set1.
4046
 * Doesn't check for duplicate nodes. Clears set2.
4047
 *
4048
 * Returns @set1 once extended or NULL in case of error.
4049
 */
4050
static xmlNodeSetPtr
4051
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4052
2.86M
{
4053
2.86M
    {
4054
2.86M
  int i;
4055
2.86M
  xmlNodePtr n2;
4056
4057
7.99M
  for (i = 0;i < set2->nodeNr;i++) {
4058
5.13M
      n2 = set2->nodeTab[i];
4059
5.13M
      if (set1->nodeMax == 0) {
4060
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4061
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4062
0
    if (set1->nodeTab == NULL) {
4063
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4064
0
        return(NULL);
4065
0
    }
4066
0
    memset(set1->nodeTab, 0,
4067
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4068
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4069
5.13M
      } else if (set1->nodeNr >= set1->nodeMax) {
4070
338k
    xmlNodePtr *temp;
4071
4072
338k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4073
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4074
0
                    return(NULL);
4075
0
                }
4076
338k
    temp = (xmlNodePtr *) xmlRealloc(
4077
338k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4078
338k
    if (temp == NULL) {
4079
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4080
0
        return(NULL);
4081
0
    }
4082
338k
    set1->nodeTab = temp;
4083
338k
    set1->nodeMax *= 2;
4084
338k
      }
4085
5.13M
      set1->nodeTab[set1->nodeNr++] = n2;
4086
5.13M
  }
4087
2.86M
    }
4088
2.86M
    set2->nodeNr = 0;
4089
2.86M
    return(set1);
4090
2.86M
}
4091
4092
/**
4093
 * xmlXPathNodeSetDel:
4094
 * @cur:  the initial node set
4095
 * @val:  an xmlNodePtr
4096
 *
4097
 * Removes an xmlNodePtr from an existing NodeSet
4098
 */
4099
void
4100
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4101
0
    int i;
4102
4103
0
    if (cur == NULL) return;
4104
0
    if (val == NULL) return;
4105
4106
    /*
4107
     * find node in nodeTab
4108
     */
4109
0
    for (i = 0;i < cur->nodeNr;i++)
4110
0
        if (cur->nodeTab[i] == val) break;
4111
4112
0
    if (i >= cur->nodeNr) { /* not found */
4113
#ifdef DEBUG
4114
        xmlGenericError(xmlGenericErrorContext,
4115
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4116
    val->name);
4117
#endif
4118
0
        return;
4119
0
    }
4120
0
    if ((cur->nodeTab[i] != NULL) &&
4121
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4122
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4123
0
    cur->nodeNr--;
4124
0
    for (;i < cur->nodeNr;i++)
4125
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4126
0
    cur->nodeTab[cur->nodeNr] = NULL;
4127
0
}
4128
4129
/**
4130
 * xmlXPathNodeSetRemove:
4131
 * @cur:  the initial node set
4132
 * @val:  the index to remove
4133
 *
4134
 * Removes an entry from an existing NodeSet list.
4135
 */
4136
void
4137
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4138
0
    if (cur == NULL) return;
4139
0
    if (val >= cur->nodeNr) return;
4140
0
    if ((cur->nodeTab[val] != NULL) &&
4141
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4142
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4143
0
    cur->nodeNr--;
4144
0
    for (;val < cur->nodeNr;val++)
4145
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4146
0
    cur->nodeTab[cur->nodeNr] = NULL;
4147
0
}
4148
4149
/**
4150
 * xmlXPathFreeNodeSet:
4151
 * @obj:  the xmlNodeSetPtr to free
4152
 *
4153
 * Free the NodeSet compound (not the actual nodes !).
4154
 */
4155
void
4156
16.8M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4157
16.8M
    if (obj == NULL) return;
4158
16.8M
    if (obj->nodeTab != NULL) {
4159
6.99M
  int i;
4160
4161
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4162
77.5M
  for (i = 0;i < obj->nodeNr;i++)
4163
70.5M
      if ((obj->nodeTab[i] != NULL) &&
4164
70.5M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4165
1.50M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4166
6.99M
  xmlFree(obj->nodeTab);
4167
6.99M
    }
4168
16.8M
    xmlFree(obj);
4169
16.8M
}
4170
4171
/**
4172
 * xmlXPathNodeSetClearFromPos:
4173
 * @set: the node set to be cleared
4174
 * @pos: the start position to clear from
4175
 *
4176
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4177
 * are feed) starting with the entry at @pos, but does *not* free the list
4178
 * itself. Sets the length of the list to @pos.
4179
 */
4180
static void
4181
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4182
51.5k
{
4183
51.5k
    if ((set == NULL) || (pos >= set->nodeNr))
4184
0
  return;
4185
51.5k
    else if ((hasNsNodes)) {
4186
13.9k
  int i;
4187
13.9k
  xmlNodePtr node;
4188
4189
48.1k
  for (i = pos; i < set->nodeNr; i++) {
4190
34.2k
      node = set->nodeTab[i];
4191
34.2k
      if ((node != NULL) &&
4192
34.2k
    (node->type == XML_NAMESPACE_DECL))
4193
18.4k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4194
34.2k
  }
4195
13.9k
    }
4196
51.5k
    set->nodeNr = pos;
4197
51.5k
}
4198
4199
/**
4200
 * xmlXPathNodeSetClear:
4201
 * @set:  the node set to clear
4202
 *
4203
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4204
 * are feed), but does *not* free the list itself. Sets the length of the
4205
 * list to 0.
4206
 */
4207
static void
4208
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4209
44.3k
{
4210
44.3k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4211
44.3k
}
4212
4213
/**
4214
 * xmlXPathNodeSetKeepLast:
4215
 * @set: the node set to be cleared
4216
 *
4217
 * Move the last node to the first position and clear temporary XPath objects
4218
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4219
 * to 1.
4220
 */
4221
static void
4222
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4223
0
{
4224
0
    int i;
4225
0
    xmlNodePtr node;
4226
4227
0
    if ((set == NULL) || (set->nodeNr <= 1))
4228
0
  return;
4229
0
    for (i = 0; i < set->nodeNr - 1; i++) {
4230
0
        node = set->nodeTab[i];
4231
0
        if ((node != NULL) &&
4232
0
            (node->type == XML_NAMESPACE_DECL))
4233
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4234
0
    }
4235
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4236
0
    set->nodeNr = 1;
4237
0
}
4238
4239
/**
4240
 * xmlXPathFreeValueTree:
4241
 * @obj:  the xmlNodeSetPtr to free
4242
 *
4243
 * Free the NodeSet compound and the actual tree, this is different
4244
 * from xmlXPathFreeNodeSet()
4245
 */
4246
static void
4247
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4248
0
    int i;
4249
4250
0
    if (obj == NULL) return;
4251
4252
0
    if (obj->nodeTab != NULL) {
4253
0
  for (i = 0;i < obj->nodeNr;i++) {
4254
0
      if (obj->nodeTab[i] != NULL) {
4255
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4256
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4257
0
    } else {
4258
0
        xmlFreeNodeList(obj->nodeTab[i]);
4259
0
    }
4260
0
      }
4261
0
  }
4262
0
  xmlFree(obj->nodeTab);
4263
0
    }
4264
0
    xmlFree(obj);
4265
0
}
4266
4267
#if defined(DEBUG) || defined(DEBUG_STEP)
4268
/**
4269
 * xmlGenericErrorContextNodeSet:
4270
 * @output:  a FILE * for the output
4271
 * @obj:  the xmlNodeSetPtr to display
4272
 *
4273
 * Quick display of a NodeSet
4274
 */
4275
void
4276
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4277
    int i;
4278
4279
    if (output == NULL) output = xmlGenericErrorContext;
4280
    if (obj == NULL)  {
4281
        fprintf(output, "NodeSet == NULL !\n");
4282
  return;
4283
    }
4284
    if (obj->nodeNr == 0) {
4285
        fprintf(output, "NodeSet is empty\n");
4286
  return;
4287
    }
4288
    if (obj->nodeTab == NULL) {
4289
  fprintf(output, " nodeTab == NULL !\n");
4290
  return;
4291
    }
4292
    for (i = 0; i < obj->nodeNr; i++) {
4293
        if (obj->nodeTab[i] == NULL) {
4294
      fprintf(output, " NULL !\n");
4295
      return;
4296
        }
4297
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4298
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4299
      fprintf(output, " /");
4300
  else if (obj->nodeTab[i]->name == NULL)
4301
      fprintf(output, " noname!");
4302
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4303
    }
4304
    fprintf(output, "\n");
4305
}
4306
#endif
4307
4308
/**
4309
 * xmlXPathNewNodeSet:
4310
 * @val:  the NodePtr value
4311
 *
4312
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4313
 * it with the single Node @val
4314
 *
4315
 * Returns the newly created object.
4316
 */
4317
xmlXPathObjectPtr
4318
9.33k
xmlXPathNewNodeSet(xmlNodePtr val) {
4319
9.33k
    xmlXPathObjectPtr ret;
4320
4321
9.33k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4322
9.33k
    if (ret == NULL) {
4323
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4324
0
  return(NULL);
4325
0
    }
4326
9.33k
    memset(ret, 0 , sizeof(xmlXPathObject));
4327
9.33k
    ret->type = XPATH_NODESET;
4328
9.33k
    ret->boolval = 0;
4329
    /* TODO: Check memory error. */
4330
9.33k
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4331
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4332
#ifdef XP_DEBUG_OBJ_USAGE
4333
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4334
#endif
4335
9.33k
    return(ret);
4336
9.33k
}
4337
4338
/**
4339
 * xmlXPathNewValueTree:
4340
 * @val:  the NodePtr value
4341
 *
4342
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4343
 * it with the tree root @val
4344
 *
4345
 * Returns the newly created object.
4346
 */
4347
xmlXPathObjectPtr
4348
0
xmlXPathNewValueTree(xmlNodePtr val) {
4349
0
    xmlXPathObjectPtr ret;
4350
4351
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4352
0
    if (ret == NULL) {
4353
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4354
0
  return(NULL);
4355
0
    }
4356
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4357
0
    ret->type = XPATH_XSLT_TREE;
4358
0
    ret->boolval = 1;
4359
0
    ret->user = (void *) val;
4360
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4361
#ifdef XP_DEBUG_OBJ_USAGE
4362
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4363
#endif
4364
0
    return(ret);
4365
0
}
4366
4367
/**
4368
 * xmlXPathNewNodeSetList:
4369
 * @val:  an existing NodeSet
4370
 *
4371
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4372
 * it with the Nodeset @val
4373
 *
4374
 * Returns the newly created object.
4375
 */
4376
xmlXPathObjectPtr
4377
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4378
0
{
4379
0
    xmlXPathObjectPtr ret;
4380
0
    int i;
4381
4382
0
    if (val == NULL)
4383
0
        ret = NULL;
4384
0
    else if (val->nodeTab == NULL)
4385
0
        ret = xmlXPathNewNodeSet(NULL);
4386
0
    else {
4387
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4388
0
        if (ret) {
4389
0
            for (i = 1; i < val->nodeNr; ++i) {
4390
                /* TODO: Propagate memory error. */
4391
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4392
0
        < 0) break;
4393
0
      }
4394
0
  }
4395
0
    }
4396
4397
0
    return (ret);
4398
0
}
4399
4400
/**
4401
 * xmlXPathWrapNodeSet:
4402
 * @val:  the NodePtr value
4403
 *
4404
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4405
 *
4406
 * Returns the newly created object.
4407
 */
4408
xmlXPathObjectPtr
4409
2.11M
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4410
2.11M
    xmlXPathObjectPtr ret;
4411
4412
2.11M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4413
2.11M
    if (ret == NULL) {
4414
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4415
0
  return(NULL);
4416
0
    }
4417
2.11M
    memset(ret, 0 , sizeof(xmlXPathObject));
4418
2.11M
    ret->type = XPATH_NODESET;
4419
2.11M
    ret->nodesetval = val;
4420
#ifdef XP_DEBUG_OBJ_USAGE
4421
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4422
#endif
4423
2.11M
    return(ret);
4424
2.11M
}
4425
4426
/**
4427
 * xmlXPathFreeNodeSetList:
4428
 * @obj:  an existing NodeSetList object
4429
 *
4430
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4431
 * the list contrary to xmlXPathFreeObject().
4432
 */
4433
void
4434
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4435
0
    if (obj == NULL) return;
4436
#ifdef XP_DEBUG_OBJ_USAGE
4437
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4438
#endif
4439
0
    xmlFree(obj);
4440
0
}
4441
4442
/**
4443
 * xmlXPathDifference:
4444
 * @nodes1:  a node-set
4445
 * @nodes2:  a node-set
4446
 *
4447
 * Implements the EXSLT - Sets difference() function:
4448
 *    node-set set:difference (node-set, node-set)
4449
 *
4450
 * Returns the difference between the two node sets, or nodes1 if
4451
 *         nodes2 is empty
4452
 */
4453
xmlNodeSetPtr
4454
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4455
0
    xmlNodeSetPtr ret;
4456
0
    int i, l1;
4457
0
    xmlNodePtr cur;
4458
4459
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4460
0
  return(nodes1);
4461
4462
    /* TODO: Check memory error. */
4463
0
    ret = xmlXPathNodeSetCreate(NULL);
4464
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4465
0
  return(ret);
4466
4467
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4468
4469
0
    for (i = 0; i < l1; i++) {
4470
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4471
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4472
            /* TODO: Propagate memory error. */
4473
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4474
0
          break;
4475
0
  }
4476
0
    }
4477
0
    return(ret);
4478
0
}
4479
4480
/**
4481
 * xmlXPathIntersection:
4482
 * @nodes1:  a node-set
4483
 * @nodes2:  a node-set
4484
 *
4485
 * Implements the EXSLT - Sets intersection() function:
4486
 *    node-set set:intersection (node-set, node-set)
4487
 *
4488
 * Returns a node set comprising the nodes that are within both the
4489
 *         node sets passed as arguments
4490
 */
4491
xmlNodeSetPtr
4492
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4493
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4494
0
    int i, l1;
4495
0
    xmlNodePtr cur;
4496
4497
0
    if (ret == NULL)
4498
0
        return(ret);
4499
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4500
0
  return(ret);
4501
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4502
0
  return(ret);
4503
4504
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4505
4506
0
    for (i = 0; i < l1; i++) {
4507
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4508
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4509
            /* TODO: Propagate memory error. */
4510
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4511
0
          break;
4512
0
  }
4513
0
    }
4514
0
    return(ret);
4515
0
}
4516
4517
/**
4518
 * xmlXPathDistinctSorted:
4519
 * @nodes:  a node-set, sorted by document order
4520
 *
4521
 * Implements the EXSLT - Sets distinct() function:
4522
 *    node-set set:distinct (node-set)
4523
 *
4524
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4525
 *         it is empty
4526
 */
4527
xmlNodeSetPtr
4528
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4529
0
    xmlNodeSetPtr ret;
4530
0
    xmlHashTablePtr hash;
4531
0
    int i, l;
4532
0
    xmlChar * strval;
4533
0
    xmlNodePtr cur;
4534
4535
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
0
  return(nodes);
4537
4538
0
    ret = xmlXPathNodeSetCreate(NULL);
4539
0
    if (ret == NULL)
4540
0
        return(ret);
4541
0
    l = xmlXPathNodeSetGetLength(nodes);
4542
0
    hash = xmlHashCreate (l);
4543
0
    for (i = 0; i < l; i++) {
4544
0
  cur = xmlXPathNodeSetItem(nodes, i);
4545
0
  strval = xmlXPathCastNodeToString(cur);
4546
0
  if (xmlHashLookup(hash, strval) == NULL) {
4547
0
      xmlHashAddEntry(hash, strval, strval);
4548
            /* TODO: Propagate memory error. */
4549
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4550
0
          break;
4551
0
  } else {
4552
0
      xmlFree(strval);
4553
0
  }
4554
0
    }
4555
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4556
0
    return(ret);
4557
0
}
4558
4559
/**
4560
 * xmlXPathDistinct:
4561
 * @nodes:  a node-set
4562
 *
4563
 * Implements the EXSLT - Sets distinct() function:
4564
 *    node-set set:distinct (node-set)
4565
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4566
 * is called with the sorted node-set
4567
 *
4568
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4569
 *         it is empty
4570
 */
4571
xmlNodeSetPtr
4572
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4573
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4574
0
  return(nodes);
4575
4576
0
    xmlXPathNodeSetSort(nodes);
4577
0
    return(xmlXPathDistinctSorted(nodes));
4578
0
}
4579
4580
/**
4581
 * xmlXPathHasSameNodes:
4582
 * @nodes1:  a node-set
4583
 * @nodes2:  a node-set
4584
 *
4585
 * Implements the EXSLT - Sets has-same-nodes function:
4586
 *    boolean set:has-same-node(node-set, node-set)
4587
 *
4588
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4589
 *         otherwise
4590
 */
4591
int
4592
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4593
0
    int i, l;
4594
0
    xmlNodePtr cur;
4595
4596
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4597
0
  xmlXPathNodeSetIsEmpty(nodes2))
4598
0
  return(0);
4599
4600
0
    l = xmlXPathNodeSetGetLength(nodes1);
4601
0
    for (i = 0; i < l; i++) {
4602
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4603
0
  if (xmlXPathNodeSetContains(nodes2, cur))
4604
0
      return(1);
4605
0
    }
4606
0
    return(0);
4607
0
}
4608
4609
/**
4610
 * xmlXPathNodeLeadingSorted:
4611
 * @nodes: a node-set, sorted by document order
4612
 * @node: a node
4613
 *
4614
 * Implements the EXSLT - Sets leading() function:
4615
 *    node-set set:leading (node-set, node-set)
4616
 *
4617
 * Returns the nodes in @nodes that precede @node in document order,
4618
 *         @nodes if @node is NULL or an empty node-set if @nodes
4619
 *         doesn't contain @node
4620
 */
4621
xmlNodeSetPtr
4622
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4623
0
    int i, l;
4624
0
    xmlNodePtr cur;
4625
0
    xmlNodeSetPtr ret;
4626
4627
0
    if (node == NULL)
4628
0
  return(nodes);
4629
4630
0
    ret = xmlXPathNodeSetCreate(NULL);
4631
0
    if (ret == NULL)
4632
0
        return(ret);
4633
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4634
0
  (!xmlXPathNodeSetContains(nodes, node)))
4635
0
  return(ret);
4636
4637
0
    l = xmlXPathNodeSetGetLength(nodes);
4638
0
    for (i = 0; i < l; i++) {
4639
0
  cur = xmlXPathNodeSetItem(nodes, i);
4640
0
  if (cur == node)
4641
0
      break;
4642
        /* TODO: Propagate memory error. */
4643
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4644
0
      break;
4645
0
    }
4646
0
    return(ret);
4647
0
}
4648
4649
/**
4650
 * xmlXPathNodeLeading:
4651
 * @nodes:  a node-set
4652
 * @node:  a node
4653
 *
4654
 * Implements the EXSLT - Sets leading() function:
4655
 *    node-set set:leading (node-set, node-set)
4656
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4657
 * is called.
4658
 *
4659
 * Returns the nodes in @nodes that precede @node in document order,
4660
 *         @nodes if @node is NULL or an empty node-set if @nodes
4661
 *         doesn't contain @node
4662
 */
4663
xmlNodeSetPtr
4664
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4665
0
    xmlXPathNodeSetSort(nodes);
4666
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4667
0
}
4668
4669
/**
4670
 * xmlXPathLeadingSorted:
4671
 * @nodes1:  a node-set, sorted by document order
4672
 * @nodes2:  a node-set, sorted by document order
4673
 *
4674
 * Implements the EXSLT - Sets leading() function:
4675
 *    node-set set:leading (node-set, node-set)
4676
 *
4677
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4678
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4679
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4680
 */
4681
xmlNodeSetPtr
4682
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4683
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4684
0
  return(nodes1);
4685
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4686
0
             xmlXPathNodeSetItem(nodes2, 1)));
4687
0
}
4688
4689
/**
4690
 * xmlXPathLeading:
4691
 * @nodes1:  a node-set
4692
 * @nodes2:  a node-set
4693
 *
4694
 * Implements the EXSLT - Sets leading() function:
4695
 *    node-set set:leading (node-set, node-set)
4696
 * @nodes1 and @nodes2 are sorted by document order, then
4697
 * #exslSetsLeadingSorted is called.
4698
 *
4699
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4700
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4701
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4702
 */
4703
xmlNodeSetPtr
4704
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4705
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4706
0
  return(nodes1);
4707
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4708
0
  return(xmlXPathNodeSetCreate(NULL));
4709
0
    xmlXPathNodeSetSort(nodes1);
4710
0
    xmlXPathNodeSetSort(nodes2);
4711
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4712
0
             xmlXPathNodeSetItem(nodes2, 1)));
4713
0
}
4714
4715
/**
4716
 * xmlXPathNodeTrailingSorted:
4717
 * @nodes: a node-set, sorted by document order
4718
 * @node: a node
4719
 *
4720
 * Implements the EXSLT - Sets trailing() function:
4721
 *    node-set set:trailing (node-set, node-set)
4722
 *
4723
 * Returns the nodes in @nodes that follow @node in document order,
4724
 *         @nodes if @node is NULL or an empty node-set if @nodes
4725
 *         doesn't contain @node
4726
 */
4727
xmlNodeSetPtr
4728
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4729
0
    int i, l;
4730
0
    xmlNodePtr cur;
4731
0
    xmlNodeSetPtr ret;
4732
4733
0
    if (node == NULL)
4734
0
  return(nodes);
4735
4736
0
    ret = xmlXPathNodeSetCreate(NULL);
4737
0
    if (ret == NULL)
4738
0
        return(ret);
4739
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4740
0
  (!xmlXPathNodeSetContains(nodes, node)))
4741
0
  return(ret);
4742
4743
0
    l = xmlXPathNodeSetGetLength(nodes);
4744
0
    for (i = l - 1; i >= 0; i--) {
4745
0
  cur = xmlXPathNodeSetItem(nodes, i);
4746
0
  if (cur == node)
4747
0
      break;
4748
        /* TODO: Propagate memory error. */
4749
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4750
0
      break;
4751
0
    }
4752
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4753
0
    return(ret);
4754
0
}
4755
4756
/**
4757
 * xmlXPathNodeTrailing:
4758
 * @nodes:  a node-set
4759
 * @node:  a node
4760
 *
4761
 * Implements the EXSLT - Sets trailing() function:
4762
 *    node-set set:trailing (node-set, node-set)
4763
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4764
 * is called.
4765
 *
4766
 * Returns the nodes in @nodes that follow @node in document order,
4767
 *         @nodes if @node is NULL or an empty node-set if @nodes
4768
 *         doesn't contain @node
4769
 */
4770
xmlNodeSetPtr
4771
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4772
0
    xmlXPathNodeSetSort(nodes);
4773
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4774
0
}
4775
4776
/**
4777
 * xmlXPathTrailingSorted:
4778
 * @nodes1:  a node-set, sorted by document order
4779
 * @nodes2:  a node-set, sorted by document order
4780
 *
4781
 * Implements the EXSLT - Sets trailing() function:
4782
 *    node-set set:trailing (node-set, node-set)
4783
 *
4784
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4785
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4786
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4787
 */
4788
xmlNodeSetPtr
4789
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4790
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4791
0
  return(nodes1);
4792
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4793
0
              xmlXPathNodeSetItem(nodes2, 0)));
4794
0
}
4795
4796
/**
4797
 * xmlXPathTrailing:
4798
 * @nodes1:  a node-set
4799
 * @nodes2:  a node-set
4800
 *
4801
 * Implements the EXSLT - Sets trailing() function:
4802
 *    node-set set:trailing (node-set, node-set)
4803
 * @nodes1 and @nodes2 are sorted by document order, then
4804
 * #xmlXPathTrailingSorted is called.
4805
 *
4806
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4807
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4808
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4809
 */
4810
xmlNodeSetPtr
4811
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4812
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4813
0
  return(nodes1);
4814
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4815
0
  return(xmlXPathNodeSetCreate(NULL));
4816
0
    xmlXPathNodeSetSort(nodes1);
4817
0
    xmlXPathNodeSetSort(nodes2);
4818
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4819
0
              xmlXPathNodeSetItem(nodes2, 0)));
4820
0
}
4821
4822
/************************************************************************
4823
 *                  *
4824
 *    Routines to handle extra functions      *
4825
 *                  *
4826
 ************************************************************************/
4827
4828
/**
4829
 * xmlXPathRegisterFunc:
4830
 * @ctxt:  the XPath context
4831
 * @name:  the function name
4832
 * @f:  the function implementation or NULL
4833
 *
4834
 * Register a new function. If @f is NULL it unregisters the function
4835
 *
4836
 * Returns 0 in case of success, -1 in case of error
4837
 */
4838
int
4839
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4840
22.8k
         xmlXPathFunction f) {
4841
22.8k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4842
22.8k
}
4843
4844
/**
4845
 * xmlXPathRegisterFuncNS:
4846
 * @ctxt:  the XPath context
4847
 * @name:  the function name
4848
 * @ns_uri:  the function namespace URI
4849
 * @f:  the function implementation or NULL
4850
 *
4851
 * Register a new function. If @f is NULL it unregisters the function
4852
 *
4853
 * Returns 0 in case of success, -1 in case of error
4854
 */
4855
int
4856
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4857
23.5k
           const xmlChar *ns_uri, xmlXPathFunction f) {
4858
23.5k
    if (ctxt == NULL)
4859
0
  return(-1);
4860
23.5k
    if (name == NULL)
4861
0
  return(-1);
4862
4863
23.5k
    if (ctxt->funcHash == NULL)
4864
0
  ctxt->funcHash = xmlHashCreate(0);
4865
23.5k
    if (ctxt->funcHash == NULL)
4866
0
  return(-1);
4867
23.5k
    if (f == NULL)
4868
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4869
23.5k
XML_IGNORE_FPTR_CAST_WARNINGS
4870
23.5k
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4871
23.5k
XML_POP_WARNINGS
4872
23.5k
}
4873
4874
/**
4875
 * xmlXPathRegisterFuncLookup:
4876
 * @ctxt:  the XPath context
4877
 * @f:  the lookup function
4878
 * @funcCtxt:  the lookup data
4879
 *
4880
 * Registers an external mechanism to do function lookup.
4881
 */
4882
void
4883
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4884
          xmlXPathFuncLookupFunc f,
4885
363
          void *funcCtxt) {
4886
363
    if (ctxt == NULL)
4887
0
  return;
4888
363
    ctxt->funcLookupFunc = f;
4889
363
    ctxt->funcLookupData = funcCtxt;
4890
363
}
4891
4892
/**
4893
 * xmlXPathFunctionLookup:
4894
 * @ctxt:  the XPath context
4895
 * @name:  the function name
4896
 *
4897
 * Search in the Function array of the context for the given
4898
 * function.
4899
 *
4900
 * Returns the xmlXPathFunction or NULL if not found
4901
 */
4902
xmlXPathFunction
4903
1.17k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4904
1.17k
    if (ctxt == NULL)
4905
0
  return (NULL);
4906
4907
1.17k
    if (ctxt->funcLookupFunc != NULL) {
4908
1.17k
  xmlXPathFunction ret;
4909
1.17k
  xmlXPathFuncLookupFunc f;
4910
4911
1.17k
  f = ctxt->funcLookupFunc;
4912
1.17k
  ret = f(ctxt->funcLookupData, name, NULL);
4913
1.17k
  if (ret != NULL)
4914
0
      return(ret);
4915
1.17k
    }
4916
1.17k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4917
1.17k
}
4918
4919
/**
4920
 * xmlXPathFunctionLookupNS:
4921
 * @ctxt:  the XPath context
4922
 * @name:  the function name
4923
 * @ns_uri:  the function namespace URI
4924
 *
4925
 * Search in the Function array of the context for the given
4926
 * function.
4927
 *
4928
 * Returns the xmlXPathFunction or NULL if not found
4929
 */
4930
xmlXPathFunction
4931
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4932
1.18k
       const xmlChar *ns_uri) {
4933
1.18k
    xmlXPathFunction ret;
4934
4935
1.18k
    if (ctxt == NULL)
4936
0
  return(NULL);
4937
1.18k
    if (name == NULL)
4938
0
  return(NULL);
4939
4940
1.18k
    if (ctxt->funcLookupFunc != NULL) {
4941
1.18k
  xmlXPathFuncLookupFunc f;
4942
4943
1.18k
  f = ctxt->funcLookupFunc;
4944
1.18k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4945
1.18k
  if (ret != NULL)
4946
0
      return(ret);
4947
1.18k
    }
4948
4949
1.18k
    if (ctxt->funcHash == NULL)
4950
0
  return(NULL);
4951
4952
1.18k
XML_IGNORE_FPTR_CAST_WARNINGS
4953
1.18k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4954
1.18k
XML_POP_WARNINGS
4955
1.18k
    return(ret);
4956
1.18k
}
4957
4958
/**
4959
 * xmlXPathRegisteredFuncsCleanup:
4960
 * @ctxt:  the XPath context
4961
 *
4962
 * Cleanup the XPath context data associated to registered functions
4963
 */
4964
void
4965
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4966
0
    if (ctxt == NULL)
4967
0
  return;
4968
4969
0
    xmlHashFree(ctxt->funcHash, NULL);
4970
0
    ctxt->funcHash = NULL;
4971
0
}
4972
4973
/************************************************************************
4974
 *                  *
4975
 *      Routines to handle Variables      *
4976
 *                  *
4977
 ************************************************************************/
4978
4979
/**
4980
 * xmlXPathRegisterVariable:
4981
 * @ctxt:  the XPath context
4982
 * @name:  the variable name
4983
 * @value:  the variable value or NULL
4984
 *
4985
 * Register a new variable value. If @value is NULL it unregisters
4986
 * the variable
4987
 *
4988
 * Returns 0 in case of success, -1 in case of error
4989
 */
4990
int
4991
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4992
1.45k
       xmlXPathObjectPtr value) {
4993
1.45k
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4994
1.45k
}
4995
4996
/**
4997
 * xmlXPathRegisterVariableNS:
4998
 * @ctxt:  the XPath context
4999
 * @name:  the variable name
5000
 * @ns_uri:  the variable namespace URI
5001
 * @value:  the variable value or NULL
5002
 *
5003
 * Register a new variable value. If @value is NULL it unregisters
5004
 * the variable
5005
 *
5006
 * Returns 0 in case of success, -1 in case of error
5007
 */
5008
int
5009
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5010
         const xmlChar *ns_uri,
5011
1.45k
         xmlXPathObjectPtr value) {
5012
1.45k
    if (ctxt == NULL)
5013
0
  return(-1);
5014
1.45k
    if (name == NULL)
5015
0
  return(-1);
5016
5017
1.45k
    if (ctxt->varHash == NULL)
5018
363
  ctxt->varHash = xmlHashCreate(0);
5019
1.45k
    if (ctxt->varHash == NULL)
5020
0
  return(-1);
5021
1.45k
    if (value == NULL)
5022
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5023
0
                             xmlXPathFreeObjectEntry));
5024
1.45k
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5025
1.45k
             (void *) value, xmlXPathFreeObjectEntry));
5026
1.45k
}
5027
5028
/**
5029
 * xmlXPathRegisterVariableLookup:
5030
 * @ctxt:  the XPath context
5031
 * @f:  the lookup function
5032
 * @data:  the lookup data
5033
 *
5034
 * register an external mechanism to do variable lookup
5035
 */
5036
void
5037
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5038
363
   xmlXPathVariableLookupFunc f, void *data) {
5039
363
    if (ctxt == NULL)
5040
0
  return;
5041
363
    ctxt->varLookupFunc = f;
5042
363
    ctxt->varLookupData = data;
5043
363
}
5044
5045
/**
5046
 * xmlXPathVariableLookup:
5047
 * @ctxt:  the XPath context
5048
 * @name:  the variable name
5049
 *
5050
 * Search in the Variable array of the context for the given
5051
 * variable value.
5052
 *
5053
 * Returns a copy of the value or NULL if not found
5054
 */
5055
xmlXPathObjectPtr
5056
53
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5057
53
    if (ctxt == NULL)
5058
0
  return(NULL);
5059
5060
53
    if (ctxt->varLookupFunc != NULL) {
5061
53
  xmlXPathObjectPtr ret;
5062
5063
53
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5064
53
          (ctxt->varLookupData, name, NULL);
5065
53
  return(ret);
5066
53
    }
5067
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5068
53
}
5069
5070
/**
5071
 * xmlXPathVariableLookupNS:
5072
 * @ctxt:  the XPath context
5073
 * @name:  the variable name
5074
 * @ns_uri:  the variable namespace URI
5075
 *
5076
 * Search in the Variable array of the context for the given
5077
 * variable value.
5078
 *
5079
 * Returns the a copy of the value or NULL if not found
5080
 */
5081
xmlXPathObjectPtr
5082
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5083
2
       const xmlChar *ns_uri) {
5084
2
    if (ctxt == NULL)
5085
0
  return(NULL);
5086
5087
2
    if (ctxt->varLookupFunc != NULL) {
5088
2
  xmlXPathObjectPtr ret;
5089
5090
2
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5091
2
          (ctxt->varLookupData, name, ns_uri);
5092
2
  if (ret != NULL) return(ret);
5093
2
    }
5094
5095
2
    if (ctxt->varHash == NULL)
5096
0
  return(NULL);
5097
2
    if (name == NULL)
5098
0
  return(NULL);
5099
5100
2
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5101
2
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5102
2
}
5103
5104
/**
5105
 * xmlXPathRegisteredVariablesCleanup:
5106
 * @ctxt:  the XPath context
5107
 *
5108
 * Cleanup the XPath context data associated to registered variables
5109
 */
5110
void
5111
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5112
0
    if (ctxt == NULL)
5113
0
  return;
5114
5115
0
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5116
0
    ctxt->varHash = NULL;
5117
0
}
5118
5119
/**
5120
 * xmlXPathRegisterNs:
5121
 * @ctxt:  the XPath context
5122
 * @prefix:  the namespace prefix cannot be NULL or empty string
5123
 * @ns_uri:  the namespace name
5124
 *
5125
 * Register a new namespace. If @ns_uri is NULL it unregisters
5126
 * the namespace
5127
 *
5128
 * Returns 0 in case of success, -1 in case of error
5129
 */
5130
int
5131
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5132
3.99k
         const xmlChar *ns_uri) {
5133
3.99k
    if (ctxt == NULL)
5134
0
  return(-1);
5135
3.99k
    if (prefix == NULL)
5136
0
  return(-1);
5137
3.99k
    if (prefix[0] == 0)
5138
0
  return(-1);
5139
5140
3.99k
    if (ctxt->nsHash == NULL)
5141
363
  ctxt->nsHash = xmlHashCreate(10);
5142
3.99k
    if (ctxt->nsHash == NULL)
5143
0
  return(-1);
5144
3.99k
    if (ns_uri == NULL)
5145
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5146
0
                            xmlHashDefaultDeallocator));
5147
3.99k
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5148
3.99k
            xmlHashDefaultDeallocator));
5149
3.99k
}
5150
5151
/**
5152
 * xmlXPathNsLookup:
5153
 * @ctxt:  the XPath context
5154
 * @prefix:  the namespace prefix value
5155
 *
5156
 * Search in the namespace declaration array of the context for the given
5157
 * namespace name associated to the given prefix
5158
 *
5159
 * Returns the value or NULL if not found
5160
 */
5161
const xmlChar *
5162
54.1k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5163
54.1k
    if (ctxt == NULL)
5164
0
  return(NULL);
5165
54.1k
    if (prefix == NULL)
5166
0
  return(NULL);
5167
5168
54.1k
#ifdef XML_XML_NAMESPACE
5169
54.1k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5170
534
  return(XML_XML_NAMESPACE);
5171
53.5k
#endif
5172
5173
53.5k
    if (ctxt->namespaces != NULL) {
5174
0
  int i;
5175
5176
0
  for (i = 0;i < ctxt->nsNr;i++) {
5177
0
      if ((ctxt->namespaces[i] != NULL) &&
5178
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5179
0
    return(ctxt->namespaces[i]->href);
5180
0
  }
5181
0
    }
5182
5183
53.5k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5184
53.5k
}
5185
5186
/**
5187
 * xmlXPathRegisteredNsCleanup:
5188
 * @ctxt:  the XPath context
5189
 *
5190
 * Cleanup the XPath context data associated to registered variables
5191
 */
5192
void
5193
0
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5194
0
    if (ctxt == NULL)
5195
0
  return;
5196
5197
0
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5198
0
    ctxt->nsHash = NULL;
5199
0
}
5200
5201
/************************************************************************
5202
 *                  *
5203
 *      Routines to handle Values     *
5204
 *                  *
5205
 ************************************************************************/
5206
5207
/* Allocations are terrible, one needs to optimize all this !!! */
5208
5209
/**
5210
 * xmlXPathNewFloat:
5211
 * @val:  the double value
5212
 *
5213
 * Create a new xmlXPathObjectPtr of type double and of value @val
5214
 *
5215
 * Returns the newly created object.
5216
 */
5217
xmlXPathObjectPtr
5218
24.4k
xmlXPathNewFloat(double val) {
5219
24.4k
    xmlXPathObjectPtr ret;
5220
5221
24.4k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5222
24.4k
    if (ret == NULL) {
5223
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5224
0
  return(NULL);
5225
0
    }
5226
24.4k
    memset(ret, 0 , sizeof(xmlXPathObject));
5227
24.4k
    ret->type = XPATH_NUMBER;
5228
24.4k
    ret->floatval = val;
5229
#ifdef XP_DEBUG_OBJ_USAGE
5230
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5231
#endif
5232
24.4k
    return(ret);
5233
24.4k
}
5234
5235
/**
5236
 * xmlXPathNewBoolean:
5237
 * @val:  the boolean value
5238
 *
5239
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5240
 *
5241
 * Returns the newly created object.
5242
 */
5243
xmlXPathObjectPtr
5244
6.70k
xmlXPathNewBoolean(int val) {
5245
6.70k
    xmlXPathObjectPtr ret;
5246
5247
6.70k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5248
6.70k
    if (ret == NULL) {
5249
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5250
0
  return(NULL);
5251
0
    }
5252
6.70k
    memset(ret, 0 , sizeof(xmlXPathObject));
5253
6.70k
    ret->type = XPATH_BOOLEAN;
5254
6.70k
    ret->boolval = (val != 0);
5255
#ifdef XP_DEBUG_OBJ_USAGE
5256
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5257
#endif
5258
6.70k
    return(ret);
5259
6.70k
}
5260
5261
/**
5262
 * xmlXPathNewString:
5263
 * @val:  the xmlChar * value
5264
 *
5265
 * Create a new xmlXPathObjectPtr of type string and of value @val
5266
 *
5267
 * Returns the newly created object.
5268
 */
5269
xmlXPathObjectPtr
5270
3.95k
xmlXPathNewString(const xmlChar *val) {
5271
3.95k
    xmlXPathObjectPtr ret;
5272
5273
3.95k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5274
3.95k
    if (ret == NULL) {
5275
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5276
0
  return(NULL);
5277
0
    }
5278
3.95k
    memset(ret, 0 , sizeof(xmlXPathObject));
5279
3.95k
    ret->type = XPATH_STRING;
5280
3.95k
    if (val != NULL)
5281
3.95k
  ret->stringval = xmlStrdup(val);
5282
0
    else
5283
0
  ret->stringval = xmlStrdup((const xmlChar *)"");
5284
#ifdef XP_DEBUG_OBJ_USAGE
5285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5286
#endif
5287
3.95k
    return(ret);
5288
3.95k
}
5289
5290
/**
5291
 * xmlXPathWrapString:
5292
 * @val:  the xmlChar * value
5293
 *
5294
 * Wraps the @val string into an XPath object.
5295
 *
5296
 * Returns the newly created object.
5297
 */
5298
xmlXPathObjectPtr
5299
109
xmlXPathWrapString (xmlChar *val) {
5300
109
    xmlXPathObjectPtr ret;
5301
5302
109
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5303
109
    if (ret == NULL) {
5304
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5305
0
  return(NULL);
5306
0
    }
5307
109
    memset(ret, 0 , sizeof(xmlXPathObject));
5308
109
    ret->type = XPATH_STRING;
5309
109
    ret->stringval = val;
5310
#ifdef XP_DEBUG_OBJ_USAGE
5311
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5312
#endif
5313
109
    return(ret);
5314
109
}
5315
5316
/**
5317
 * xmlXPathNewCString:
5318
 * @val:  the char * value
5319
 *
5320
 * Create a new xmlXPathObjectPtr of type string and of value @val
5321
 *
5322
 * Returns the newly created object.
5323
 */
5324
xmlXPathObjectPtr
5325
43
xmlXPathNewCString(const char *val) {
5326
43
    xmlXPathObjectPtr ret;
5327
5328
43
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5329
43
    if (ret == NULL) {
5330
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5331
0
  return(NULL);
5332
0
    }
5333
43
    memset(ret, 0 , sizeof(xmlXPathObject));
5334
43
    ret->type = XPATH_STRING;
5335
43
    ret->stringval = xmlStrdup(BAD_CAST val);
5336
#ifdef XP_DEBUG_OBJ_USAGE
5337
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5338
#endif
5339
43
    return(ret);
5340
43
}
5341
5342
/**
5343
 * xmlXPathWrapCString:
5344
 * @val:  the char * value
5345
 *
5346
 * Wraps a string into an XPath object.
5347
 *
5348
 * Returns the newly created object.
5349
 */
5350
xmlXPathObjectPtr
5351
0
xmlXPathWrapCString (char * val) {
5352
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5353
0
}
5354
5355
/**
5356
 * xmlXPathWrapExternal:
5357
 * @val:  the user data
5358
 *
5359
 * Wraps the @val data into an XPath object.
5360
 *
5361
 * Returns the newly created object.
5362
 */
5363
xmlXPathObjectPtr
5364
0
xmlXPathWrapExternal (void *val) {
5365
0
    xmlXPathObjectPtr ret;
5366
5367
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5368
0
    if (ret == NULL) {
5369
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5370
0
  return(NULL);
5371
0
    }
5372
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5373
0
    ret->type = XPATH_USERS;
5374
0
    ret->user = val;
5375
#ifdef XP_DEBUG_OBJ_USAGE
5376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5377
#endif
5378
0
    return(ret);
5379
0
}
5380
5381
/**
5382
 * xmlXPathObjectCopy:
5383
 * @val:  the original object
5384
 *
5385
 * allocate a new copy of a given object
5386
 *
5387
 * Returns the newly created object.
5388
 */
5389
xmlXPathObjectPtr
5390
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5391
0
    xmlXPathObjectPtr ret;
5392
5393
0
    if (val == NULL)
5394
0
  return(NULL);
5395
5396
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5397
0
    if (ret == NULL) {
5398
0
        xmlXPathErrMemory(NULL, "copying object\n");
5399
0
  return(NULL);
5400
0
    }
5401
0
    memcpy(ret, val , sizeof(xmlXPathObject));
5402
#ifdef XP_DEBUG_OBJ_USAGE
5403
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5404
#endif
5405
0
    switch (val->type) {
5406
0
  case XPATH_BOOLEAN:
5407
0
  case XPATH_NUMBER:
5408
#ifdef LIBXML_XPTR_LOCS_ENABLED
5409
  case XPATH_POINT:
5410
  case XPATH_RANGE:
5411
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5412
0
      break;
5413
0
  case XPATH_STRING:
5414
0
      ret->stringval = xmlStrdup(val->stringval);
5415
0
      break;
5416
0
  case XPATH_XSLT_TREE:
5417
#if 0
5418
/*
5419
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5420
  this previous handling is no longer correct, and can cause some serious
5421
  problems (ref. bug 145547)
5422
*/
5423
      if ((val->nodesetval != NULL) &&
5424
    (val->nodesetval->nodeTab != NULL)) {
5425
    xmlNodePtr cur, tmp;
5426
    xmlDocPtr top;
5427
5428
    ret->boolval = 1;
5429
    top =  xmlNewDoc(NULL);
5430
    top->name = (char *)
5431
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5432
    ret->user = top;
5433
    if (top != NULL) {
5434
        top->doc = top;
5435
        cur = val->nodesetval->nodeTab[0]->children;
5436
        while (cur != NULL) {
5437
      tmp = xmlDocCopyNode(cur, top, 1);
5438
      xmlAddChild((xmlNodePtr) top, tmp);
5439
      cur = cur->next;
5440
        }
5441
    }
5442
5443
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5444
      } else
5445
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5446
      /* Deallocate the copied tree value */
5447
      break;
5448
#endif
5449
0
  case XPATH_NODESET:
5450
            /* TODO: Check memory error. */
5451
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452
      /* Do not deallocate the copied tree value */
5453
0
      ret->boolval = 0;
5454
0
      break;
5455
#ifdef LIBXML_XPTR_LOCS_ENABLED
5456
  case XPATH_LOCATIONSET:
5457
  {
5458
      xmlLocationSetPtr loc = val->user;
5459
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5460
      break;
5461
  }
5462
#endif
5463
0
        case XPATH_USERS:
5464
0
      ret->user = val->user;
5465
0
      break;
5466
0
        case XPATH_UNDEFINED:
5467
0
      xmlGenericError(xmlGenericErrorContext,
5468
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5469
0
        val->type);
5470
0
      break;
5471
0
    }
5472
0
    return(ret);
5473
0
}
5474
5475
/**
5476
 * xmlXPathFreeObject:
5477
 * @obj:  the object to free
5478
 *
5479
 * Free up an xmlXPathObjectPtr object.
5480
 */
5481
void
5482
1.92M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483
1.92M
    if (obj == NULL) return;
5484
1.92M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485
1.90M
  if (obj->boolval) {
5486
#if 0
5487
      if (obj->user != NULL) {
5488
                xmlXPathFreeNodeSet(obj->nodesetval);
5489
    xmlFreeNodeList((xmlNodePtr) obj->user);
5490
      } else
5491
#endif
5492
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5493
0
      if (obj->nodesetval != NULL)
5494
0
    xmlXPathFreeValueTree(obj->nodesetval);
5495
1.90M
  } else {
5496
1.90M
      if (obj->nodesetval != NULL)
5497
1.36M
    xmlXPathFreeNodeSet(obj->nodesetval);
5498
1.90M
  }
5499
#ifdef LIBXML_XPTR_LOCS_ENABLED
5500
    } else if (obj->type == XPATH_LOCATIONSET) {
5501
  if (obj->user != NULL)
5502
      xmlXPtrFreeLocationSet(obj->user);
5503
#endif
5504
1.90M
    } else if (obj->type == XPATH_STRING) {
5505
1.93k
  if (obj->stringval != NULL)
5506
1.93k
      xmlFree(obj->stringval);
5507
1.93k
    }
5508
#ifdef XP_DEBUG_OBJ_USAGE
5509
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510
#endif
5511
1.92M
    xmlFree(obj);
5512
1.92M
}
5513
5514
static void
5515
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5516
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5517
0
}
5518
5519
/**
5520
 * xmlXPathReleaseObject:
5521
 * @obj:  the xmlXPathObjectPtr to free or to cache
5522
 *
5523
 * Depending on the state of the cache this frees the given
5524
 * XPath object or stores it in the cache.
5525
 */
5526
static void
5527
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5528
51.5M
{
5529
51.5M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5530
14.8k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5531
51.5M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5532
5533
65.6M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5534
5535
51.5M
    if (obj == NULL)
5536
0
  return;
5537
51.5M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5538
0
   xmlXPathFreeObject(obj);
5539
51.5M
    } else {
5540
51.5M
  xmlXPathContextCachePtr cache =
5541
51.5M
      (xmlXPathContextCachePtr) ctxt->cache;
5542
5543
51.5M
  switch (obj->type) {
5544
32.3M
      case XPATH_NODESET:
5545
32.3M
      case XPATH_XSLT_TREE:
5546
32.3M
    if (obj->nodesetval != NULL) {
5547
28.8M
        if (obj->boolval) {
5548
      /*
5549
      * It looks like the @boolval is used for
5550
      * evaluation if this an XSLT Result Tree Fragment.
5551
      * TODO: Check if this assumption is correct.
5552
      */
5553
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5554
0
      xmlXPathFreeValueTree(obj->nodesetval);
5555
0
      obj->nodesetval = NULL;
5556
28.8M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5557
28.8M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5558
28.8M
          cache->maxNodeset)))
5559
14.7M
        {
5560
14.7M
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5561
14.7M
      goto obj_cached;
5562
14.7M
        } else {
5563
14.1M
      xmlXPathFreeNodeSet(obj->nodesetval);
5564
14.1M
      obj->nodesetval = NULL;
5565
14.1M
        }
5566
28.8M
    }
5567
17.6M
    break;
5568
17.6M
      case XPATH_STRING:
5569
2.33M
    if (obj->stringval != NULL)
5570
2.33M
        xmlFree(obj->stringval);
5571
5572
2.33M
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5573
2.33M
        XP_CACHE_ADD(cache->stringObjs, obj);
5574
2.33M
        goto obj_cached;
5575
2.33M
    }
5576
0
    break;
5577
7.44M
      case XPATH_BOOLEAN:
5578
7.44M
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5579
7.44M
        XP_CACHE_ADD(cache->booleanObjs, obj);
5580
7.44M
        goto obj_cached;
5581
7.44M
    }
5582
0
    break;
5583
9.36M
      case XPATH_NUMBER:
5584
9.36M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5585
9.36M
        XP_CACHE_ADD(cache->numberObjs, obj);
5586
9.36M
        goto obj_cached;
5587
9.36M
    }
5588
0
    break;
5589
#ifdef LIBXML_XPTR_LOCS_ENABLED
5590
      case XPATH_LOCATIONSET:
5591
    if (obj->user != NULL) {
5592
        xmlXPtrFreeLocationSet(obj->user);
5593
    }
5594
    goto free_obj;
5595
#endif
5596
0
      default:
5597
0
    goto free_obj;
5598
51.5M
  }
5599
5600
  /*
5601
  * Fallback to adding to the misc-objects slot.
5602
  */
5603
17.6M
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5604
17.6M
      XP_CACHE_ADD(cache->miscObjs, obj);
5605
17.6M
  } else
5606
196
      goto free_obj;
5607
5608
51.5M
obj_cached:
5609
5610
#ifdef XP_DEBUG_OBJ_USAGE
5611
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5612
#endif
5613
5614
51.5M
  if (obj->nodesetval != NULL) {
5615
14.7M
      xmlNodeSetPtr tmpset = obj->nodesetval;
5616
5617
      /*
5618
      * TODO: Due to those nasty ns-nodes, we need to traverse
5619
      *  the list and free the ns-nodes.
5620
      * URGENT TODO: Check if it's actually slowing things down.
5621
      *  Maybe we shouldn't try to preserve the list.
5622
      */
5623
14.7M
      if (tmpset->nodeNr > 1) {
5624
163k
    int i;
5625
163k
    xmlNodePtr node;
5626
5627
3.13M
    for (i = 0; i < tmpset->nodeNr; i++) {
5628
2.97M
        node = tmpset->nodeTab[i];
5629
2.97M
        if ((node != NULL) &&
5630
2.97M
      (node->type == XML_NAMESPACE_DECL))
5631
25.6k
        {
5632
25.6k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5633
25.6k
        }
5634
2.97M
    }
5635
14.5M
      } else if (tmpset->nodeNr == 1) {
5636
14.1M
    if ((tmpset->nodeTab[0] != NULL) &&
5637
14.1M
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5638
175k
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5639
14.1M
      }
5640
14.7M
      tmpset->nodeNr = 0;
5641
14.7M
      memset(obj, 0, sizeof(xmlXPathObject));
5642
14.7M
      obj->nodesetval = tmpset;
5643
14.7M
  } else
5644
36.7M
      memset(obj, 0, sizeof(xmlXPathObject));
5645
5646
51.5M
  return;
5647
5648
196
free_obj:
5649
  /*
5650
  * Cache is full; free the object.
5651
  */
5652
196
  if (obj->nodesetval != NULL)
5653
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5654
#ifdef XP_DEBUG_OBJ_USAGE
5655
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5656
#endif
5657
196
  xmlFree(obj);
5658
196
    }
5659
196
    return;
5660
51.5M
}
5661
5662
5663
/************************************************************************
5664
 *                  *
5665
 *      Type Casting Routines       *
5666
 *                  *
5667
 ************************************************************************/
5668
5669
/**
5670
 * xmlXPathCastBooleanToString:
5671
 * @val:  a boolean
5672
 *
5673
 * Converts a boolean to its string value.
5674
 *
5675
 * Returns a newly allocated string.
5676
 */
5677
xmlChar *
5678
2.15k
xmlXPathCastBooleanToString (int val) {
5679
2.15k
    xmlChar *ret;
5680
2.15k
    if (val)
5681
1.72k
  ret = xmlStrdup((const xmlChar *) "true");
5682
424
    else
5683
424
  ret = xmlStrdup((const xmlChar *) "false");
5684
2.15k
    return(ret);
5685
2.15k
}
5686
5687
/**
5688
 * xmlXPathCastNumberToString:
5689
 * @val:  a number
5690
 *
5691
 * Converts a number to its string value.
5692
 *
5693
 * Returns a newly allocated string.
5694
 */
5695
xmlChar *
5696
58.4k
xmlXPathCastNumberToString (double val) {
5697
58.4k
    xmlChar *ret;
5698
58.4k
    switch (xmlXPathIsInf(val)) {
5699
1.54k
    case 1:
5700
1.54k
  ret = xmlStrdup((const xmlChar *) "Infinity");
5701
1.54k
  break;
5702
7.38k
    case -1:
5703
7.38k
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5704
7.38k
  break;
5705
49.5k
    default:
5706
49.5k
  if (xmlXPathIsNaN(val)) {
5707
372
      ret = xmlStrdup((const xmlChar *) "NaN");
5708
49.1k
  } else if (val == 0) {
5709
            /* Omit sign for negative zero. */
5710
6.35k
      ret = xmlStrdup((const xmlChar *) "0");
5711
42.8k
  } else {
5712
      /* could be improved */
5713
42.8k
      char buf[100];
5714
42.8k
      xmlXPathFormatNumber(val, buf, 99);
5715
42.8k
      buf[99] = 0;
5716
42.8k
      ret = xmlStrdup((const xmlChar *) buf);
5717
42.8k
  }
5718
58.4k
    }
5719
58.4k
    return(ret);
5720
58.4k
}
5721
5722
/**
5723
 * xmlXPathCastNodeToString:
5724
 * @node:  a node
5725
 *
5726
 * Converts a node to its string value.
5727
 *
5728
 * Returns a newly allocated string.
5729
 */
5730
xmlChar *
5731
4.84M
xmlXPathCastNodeToString (xmlNodePtr node) {
5732
4.84M
xmlChar *ret;
5733
4.84M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5734
0
  ret = xmlStrdup((const xmlChar *) "");
5735
4.84M
    return(ret);
5736
4.84M
}
5737
5738
/**
5739
 * xmlXPathCastNodeSetToString:
5740
 * @ns:  a node-set
5741
 *
5742
 * Converts a node-set to its string value.
5743
 *
5744
 * Returns a newly allocated string.
5745
 */
5746
xmlChar *
5747
5.38M
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5748
5.38M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5749
3.53M
  return(xmlStrdup((const xmlChar *) ""));
5750
5751
1.85M
    if (ns->nodeNr > 1)
5752
1.17M
  xmlXPathNodeSetSort(ns);
5753
1.85M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5754
5.38M
}
5755
5756
/**
5757
 * xmlXPathCastToString:
5758
 * @val:  an XPath object
5759
 *
5760
 * Converts an existing object to its string() equivalent
5761
 *
5762
 * Returns the allocated string value of the object, NULL in case of error.
5763
 *         It's up to the caller to free the string memory with xmlFree().
5764
 */
5765
xmlChar *
5766
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
5767
0
    xmlChar *ret = NULL;
5768
5769
0
    if (val == NULL)
5770
0
  return(xmlStrdup((const xmlChar *) ""));
5771
0
    switch (val->type) {
5772
0
  case XPATH_UNDEFINED:
5773
#ifdef DEBUG_EXPR
5774
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5775
#endif
5776
0
      ret = xmlStrdup((const xmlChar *) "");
5777
0
      break;
5778
0
        case XPATH_NODESET:
5779
0
        case XPATH_XSLT_TREE:
5780
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5781
0
      break;
5782
0
  case XPATH_STRING:
5783
0
      return(xmlStrdup(val->stringval));
5784
0
        case XPATH_BOOLEAN:
5785
0
      ret = xmlXPathCastBooleanToString(val->boolval);
5786
0
      break;
5787
0
  case XPATH_NUMBER: {
5788
0
      ret = xmlXPathCastNumberToString(val->floatval);
5789
0
      break;
5790
0
  }
5791
0
  case XPATH_USERS:
5792
#ifdef LIBXML_XPTR_LOCS_ENABLED
5793
  case XPATH_POINT:
5794
  case XPATH_RANGE:
5795
  case XPATH_LOCATIONSET:
5796
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5797
0
      TODO
5798
0
      ret = xmlStrdup((const xmlChar *) "");
5799
0
      break;
5800
0
    }
5801
0
    return(ret);
5802
0
}
5803
5804
/**
5805
 * xmlXPathConvertString:
5806
 * @val:  an XPath object
5807
 *
5808
 * Converts an existing object to its string() equivalent
5809
 *
5810
 * Returns the new object, the old one is freed (or the operation
5811
 *         is done directly on @val)
5812
 */
5813
xmlXPathObjectPtr
5814
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
5815
0
    xmlChar *res = NULL;
5816
5817
0
    if (val == NULL)
5818
0
  return(xmlXPathNewCString(""));
5819
5820
0
    switch (val->type) {
5821
0
    case XPATH_UNDEFINED:
5822
#ifdef DEBUG_EXPR
5823
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5824
#endif
5825
0
  break;
5826
0
    case XPATH_NODESET:
5827
0
    case XPATH_XSLT_TREE:
5828
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5829
0
  break;
5830
0
    case XPATH_STRING:
5831
0
  return(val);
5832
0
    case XPATH_BOOLEAN:
5833
0
  res = xmlXPathCastBooleanToString(val->boolval);
5834
0
  break;
5835
0
    case XPATH_NUMBER:
5836
0
  res = xmlXPathCastNumberToString(val->floatval);
5837
0
  break;
5838
0
    case XPATH_USERS:
5839
#ifdef LIBXML_XPTR_LOCS_ENABLED
5840
    case XPATH_POINT:
5841
    case XPATH_RANGE:
5842
    case XPATH_LOCATIONSET:
5843
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5844
0
  TODO;
5845
0
  break;
5846
0
    }
5847
0
    xmlXPathFreeObject(val);
5848
0
    if (res == NULL)
5849
0
  return(xmlXPathNewCString(""));
5850
0
    return(xmlXPathWrapString(res));
5851
0
}
5852
5853
/**
5854
 * xmlXPathCastBooleanToNumber:
5855
 * @val:  a boolean
5856
 *
5857
 * Converts a boolean to its number value
5858
 *
5859
 * Returns the number value
5860
 */
5861
double
5862
2.36M
xmlXPathCastBooleanToNumber(int val) {
5863
2.36M
    if (val)
5864
650k
  return(1.0);
5865
1.71M
    return(0.0);
5866
2.36M
}
5867
5868
/**
5869
 * xmlXPathCastStringToNumber:
5870
 * @val:  a string
5871
 *
5872
 * Converts a string to its number value
5873
 *
5874
 * Returns the number value
5875
 */
5876
double
5877
8.67M
xmlXPathCastStringToNumber(const xmlChar * val) {
5878
8.67M
    return(xmlXPathStringEvalNumber(val));
5879
8.67M
}
5880
5881
/**
5882
 * xmlXPathCastNodeToNumber:
5883
 * @node:  a node
5884
 *
5885
 * Converts a node to its number value
5886
 *
5887
 * Returns the number value
5888
 */
5889
double
5890
1.34M
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5891
1.34M
    xmlChar *strval;
5892
1.34M
    double ret;
5893
5894
1.34M
    if (node == NULL)
5895
0
  return(xmlXPathNAN);
5896
1.34M
    strval = xmlXPathCastNodeToString(node);
5897
1.34M
    if (strval == NULL)
5898
0
  return(xmlXPathNAN);
5899
1.34M
    ret = xmlXPathCastStringToNumber(strval);
5900
1.34M
    xmlFree(strval);
5901
5902
1.34M
    return(ret);
5903
1.34M
}
5904
5905
/**
5906
 * xmlXPathCastNodeSetToNumber:
5907
 * @ns:  a node-set
5908
 *
5909
 * Converts a node-set to its number value
5910
 *
5911
 * Returns the number value
5912
 */
5913
double
5914
6.62M
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5915
6.62M
    xmlChar *str;
5916
6.62M
    double ret;
5917
5918
6.62M
    if (ns == NULL)
5919
1.24M
  return(xmlXPathNAN);
5920
5.38M
    str = xmlXPathCastNodeSetToString(ns);
5921
5.38M
    ret = xmlXPathCastStringToNumber(str);
5922
5.38M
    xmlFree(str);
5923
5.38M
    return(ret);
5924
6.62M
}
5925
5926
/**
5927
 * xmlXPathCastToNumber:
5928
 * @val:  an XPath object
5929
 *
5930
 * Converts an XPath object to its number value
5931
 *
5932
 * Returns the number value
5933
 */
5934
double
5935
12.3M
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5936
12.3M
    double ret = 0.0;
5937
5938
12.3M
    if (val == NULL)
5939
0
  return(xmlXPathNAN);
5940
12.3M
    switch (val->type) {
5941
0
    case XPATH_UNDEFINED:
5942
#ifdef DEBUG_EXPR
5943
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5944
#endif
5945
0
  ret = xmlXPathNAN;
5946
0
  break;
5947
6.62M
    case XPATH_NODESET:
5948
6.62M
    case XPATH_XSLT_TREE:
5949
6.62M
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5950
6.62M
  break;
5951
1.94M
    case XPATH_STRING:
5952
1.94M
  ret = xmlXPathCastStringToNumber(val->stringval);
5953
1.94M
  break;
5954
1.40M
    case XPATH_NUMBER:
5955
1.40M
  ret = val->floatval;
5956
1.40M
  break;
5957
2.36M
    case XPATH_BOOLEAN:
5958
2.36M
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5959
2.36M
  break;
5960
0
    case XPATH_USERS:
5961
#ifdef LIBXML_XPTR_LOCS_ENABLED
5962
    case XPATH_POINT:
5963
    case XPATH_RANGE:
5964
    case XPATH_LOCATIONSET:
5965
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5966
0
  TODO;
5967
0
  ret = xmlXPathNAN;
5968
0
  break;
5969
12.3M
    }
5970
12.3M
    return(ret);
5971
12.3M
}
5972
5973
/**
5974
 * xmlXPathConvertNumber:
5975
 * @val:  an XPath object
5976
 *
5977
 * Converts an existing object to its number() equivalent
5978
 *
5979
 * Returns the new object, the old one is freed (or the operation
5980
 *         is done directly on @val)
5981
 */
5982
xmlXPathObjectPtr
5983
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5984
0
    xmlXPathObjectPtr ret;
5985
5986
0
    if (val == NULL)
5987
0
  return(xmlXPathNewFloat(0.0));
5988
0
    if (val->type == XPATH_NUMBER)
5989
0
  return(val);
5990
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5991
0
    xmlXPathFreeObject(val);
5992
0
    return(ret);
5993
0
}
5994
5995
/**
5996
 * xmlXPathCastNumberToBoolean:
5997
 * @val:  a number
5998
 *
5999
 * Converts a number to its boolean value
6000
 *
6001
 * Returns the boolean value
6002
 */
6003
int
6004
563k
xmlXPathCastNumberToBoolean (double val) {
6005
563k
     if (xmlXPathIsNaN(val) || (val == 0.0))
6006
493k
   return(0);
6007
70.0k
     return(1);
6008
563k
}
6009
6010
/**
6011
 * xmlXPathCastStringToBoolean:
6012
 * @val:  a string
6013
 *
6014
 * Converts a string to its boolean value
6015
 *
6016
 * Returns the boolean value
6017
 */
6018
int
6019
451
xmlXPathCastStringToBoolean (const xmlChar *val) {
6020
451
    if ((val == NULL) || (xmlStrlen(val) == 0))
6021
213
  return(0);
6022
238
    return(1);
6023
451
}
6024
6025
/**
6026
 * xmlXPathCastNodeSetToBoolean:
6027
 * @ns:  a node-set
6028
 *
6029
 * Converts a node-set to its boolean value
6030
 *
6031
 * Returns the boolean value
6032
 */
6033
int
6034
1.02M
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6035
1.02M
    if ((ns == NULL) || (ns->nodeNr == 0))
6036
584k
  return(0);
6037
437k
    return(1);
6038
1.02M
}
6039
6040
/**
6041
 * xmlXPathCastToBoolean:
6042
 * @val:  an XPath object
6043
 *
6044
 * Converts an XPath object to its boolean value
6045
 *
6046
 * Returns the boolean value
6047
 */
6048
int
6049
1.06M
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6050
1.06M
    int ret = 0;
6051
6052
1.06M
    if (val == NULL)
6053
0
  return(0);
6054
1.06M
    switch (val->type) {
6055
0
    case XPATH_UNDEFINED:
6056
#ifdef DEBUG_EXPR
6057
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6058
#endif
6059
0
  ret = 0;
6060
0
  break;
6061
1.02M
    case XPATH_NODESET:
6062
1.02M
    case XPATH_XSLT_TREE:
6063
1.02M
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6064
1.02M
  break;
6065
451
    case XPATH_STRING:
6066
451
  ret = xmlXPathCastStringToBoolean(val->stringval);
6067
451
  break;
6068
38.6k
    case XPATH_NUMBER:
6069
38.6k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6070
38.6k
  break;
6071
0
    case XPATH_BOOLEAN:
6072
0
  ret = val->boolval;
6073
0
  break;
6074
0
    case XPATH_USERS:
6075
#ifdef LIBXML_XPTR_LOCS_ENABLED
6076
    case XPATH_POINT:
6077
    case XPATH_RANGE:
6078
    case XPATH_LOCATIONSET:
6079
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6080
0
  TODO;
6081
0
  ret = 0;
6082
0
  break;
6083
1.06M
    }
6084
1.06M
    return(ret);
6085
1.06M
}
6086
6087
6088
/**
6089
 * xmlXPathConvertBoolean:
6090
 * @val:  an XPath object
6091
 *
6092
 * Converts an existing object to its boolean() equivalent
6093
 *
6094
 * Returns the new object, the old one is freed (or the operation
6095
 *         is done directly on @val)
6096
 */
6097
xmlXPathObjectPtr
6098
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6099
0
    xmlXPathObjectPtr ret;
6100
6101
0
    if (val == NULL)
6102
0
  return(xmlXPathNewBoolean(0));
6103
0
    if (val->type == XPATH_BOOLEAN)
6104
0
  return(val);
6105
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6106
0
    xmlXPathFreeObject(val);
6107
0
    return(ret);
6108
0
}
6109
6110
/************************************************************************
6111
 *                  *
6112
 *    Routines to handle XPath contexts     *
6113
 *                  *
6114
 ************************************************************************/
6115
6116
/**
6117
 * xmlXPathNewContext:
6118
 * @doc:  the XML document
6119
 *
6120
 * Create a new xmlXPathContext
6121
 *
6122
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6123
 */
6124
xmlXPathContextPtr
6125
726
xmlXPathNewContext(xmlDocPtr doc) {
6126
726
    xmlXPathContextPtr ret;
6127
6128
726
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6129
726
    if (ret == NULL) {
6130
0
        xmlXPathErrMemory(NULL, "creating context\n");
6131
0
  return(NULL);
6132
0
    }
6133
726
    memset(ret, 0 , sizeof(xmlXPathContext));
6134
726
    ret->doc = doc;
6135
726
    ret->node = NULL;
6136
6137
726
    ret->varHash = NULL;
6138
6139
726
    ret->nb_types = 0;
6140
726
    ret->max_types = 0;
6141
726
    ret->types = NULL;
6142
6143
726
    ret->funcHash = xmlHashCreate(0);
6144
6145
726
    ret->nb_axis = 0;
6146
726
    ret->max_axis = 0;
6147
726
    ret->axis = NULL;
6148
6149
726
    ret->nsHash = NULL;
6150
726
    ret->user = NULL;
6151
6152
726
    ret->contextSize = -1;
6153
726
    ret->proximityPosition = -1;
6154
6155
#ifdef XP_DEFAULT_CACHE_ON
6156
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6157
  xmlXPathFreeContext(ret);
6158
  return(NULL);
6159
    }
6160
#endif
6161
6162
726
    xmlXPathRegisterAllFunctions(ret);
6163
6164
726
    return(ret);
6165
726
}
6166
6167
/**
6168
 * xmlXPathFreeContext:
6169
 * @ctxt:  the context to free
6170
 *
6171
 * Free up an xmlXPathContext
6172
 */
6173
void
6174
0
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6175
0
    if (ctxt == NULL) return;
6176
6177
0
    if (ctxt->cache != NULL)
6178
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6179
0
    xmlXPathRegisteredNsCleanup(ctxt);
6180
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
6181
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
6182
0
    xmlResetError(&ctxt->lastError);
6183
0
    xmlFree(ctxt);
6184
0
}
6185
6186
/************************************************************************
6187
 *                  *
6188
 *    Routines to handle XPath parser contexts    *
6189
 *                  *
6190
 ************************************************************************/
6191
6192
#define CHECK_CTXT(ctxt)            \
6193
363
    if (ctxt == NULL) {           \
6194
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6195
0
    NULL, NULL, XML_FROM_XPATH,       \
6196
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6197
0
    __FILE__, __LINE__,         \
6198
0
    NULL, NULL, NULL, 0, 0,         \
6199
0
    "NULL context pointer\n");        \
6200
0
  return(NULL);             \
6201
0
    }                  \
6202
6203
#define CHECK_CTXT_NEG(ctxt)            \
6204
5.18k
    if (ctxt == NULL) {           \
6205
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6206
0
    NULL, NULL, XML_FROM_XPATH,       \
6207
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6208
0
    __FILE__, __LINE__,         \
6209
0
    NULL, NULL, NULL, 0, 0,         \
6210
0
    "NULL context pointer\n");        \
6211
0
  return(-1);             \
6212
0
    }                  \
6213
6214
6215
#define CHECK_CONTEXT(ctxt)           \
6216
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6217
        (ctxt->doc->children == NULL)) {        \
6218
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6219
  return(NULL);             \
6220
    }
6221
6222
6223
/**
6224
 * xmlXPathNewParserContext:
6225
 * @str:  the XPath expression
6226
 * @ctxt:  the XPath context
6227
 *
6228
 * Create a new xmlXPathParserContext
6229
 *
6230
 * Returns the xmlXPathParserContext just allocated.
6231
 */
6232
xmlXPathParserContextPtr
6233
7.18k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6234
7.18k
    xmlXPathParserContextPtr ret;
6235
6236
7.18k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6237
7.18k
    if (ret == NULL) {
6238
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6239
0
  return(NULL);
6240
0
    }
6241
7.18k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6242
7.18k
    ret->cur = ret->base = str;
6243
7.18k
    ret->context = ctxt;
6244
6245
7.18k
    ret->comp = xmlXPathNewCompExpr();
6246
7.18k
    if (ret->comp == NULL) {
6247
0
  xmlFree(ret->valueTab);
6248
0
  xmlFree(ret);
6249
0
  return(NULL);
6250
0
    }
6251
7.18k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6252
0
        ret->comp->dict = ctxt->dict;
6253
0
  xmlDictReference(ret->comp->dict);
6254
0
    }
6255
6256
7.18k
    return(ret);
6257
7.18k
}
6258
6259
/**
6260
 * xmlXPathCompParserContext:
6261
 * @comp:  the XPath compiled expression
6262
 * @ctxt:  the XPath context
6263
 *
6264
 * Create a new xmlXPathParserContext when processing a compiled expression
6265
 *
6266
 * Returns the xmlXPathParserContext just allocated.
6267
 */
6268
static xmlXPathParserContextPtr
6269
5.18k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6270
5.18k
    xmlXPathParserContextPtr ret;
6271
6272
5.18k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6273
5.18k
    if (ret == NULL) {
6274
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6275
0
  return(NULL);
6276
0
    }
6277
5.18k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6278
6279
    /* Allocate the value stack */
6280
5.18k
    ret->valueTab = (xmlXPathObjectPtr *)
6281
5.18k
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6282
5.18k
    if (ret->valueTab == NULL) {
6283
0
  xmlFree(ret);
6284
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6285
0
  return(NULL);
6286
0
    }
6287
5.18k
    ret->valueNr = 0;
6288
5.18k
    ret->valueMax = 10;
6289
5.18k
    ret->value = NULL;
6290
5.18k
    ret->valueFrame = 0;
6291
6292
5.18k
    ret->context = ctxt;
6293
5.18k
    ret->comp = comp;
6294
6295
5.18k
    return(ret);
6296
5.18k
}
6297
6298
/**
6299
 * xmlXPathFreeParserContext:
6300
 * @ctxt:  the context to free
6301
 *
6302
 * Free up an xmlXPathParserContext
6303
 */
6304
void
6305
12.3k
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6306
12.3k
    int i;
6307
6308
12.3k
    if (ctxt->valueTab != NULL) {
6309
17.0k
        for (i = 0; i < ctxt->valueNr; i++) {
6310
11.5k
            if (ctxt->context)
6311
11.5k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6312
0
            else
6313
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6314
11.5k
        }
6315
5.54k
        xmlFree(ctxt->valueTab);
6316
5.54k
    }
6317
12.3k
    if (ctxt->comp != NULL) {
6318
2.50k
#ifdef XPATH_STREAMING
6319
2.50k
  if (ctxt->comp->stream != NULL) {
6320
0
      xmlFreePatternList(ctxt->comp->stream);
6321
0
      ctxt->comp->stream = NULL;
6322
0
  }
6323
2.50k
#endif
6324
2.50k
  xmlXPathFreeCompExpr(ctxt->comp);
6325
2.50k
    }
6326
12.3k
    xmlFree(ctxt);
6327
12.3k
}
6328
6329
/************************************************************************
6330
 *                  *
6331
 *    The implicit core function library      *
6332
 *                  *
6333
 ************************************************************************/
6334
6335
/**
6336
 * xmlXPathNodeValHash:
6337
 * @node:  a node pointer
6338
 *
6339
 * Function computing the beginning of the string value of the node,
6340
 * used to speed up comparisons
6341
 *
6342
 * Returns an int usable as a hash
6343
 */
6344
static unsigned int
6345
808k
xmlXPathNodeValHash(xmlNodePtr node) {
6346
808k
    int len = 2;
6347
808k
    const xmlChar * string = NULL;
6348
808k
    xmlNodePtr tmp = NULL;
6349
808k
    unsigned int ret = 0;
6350
6351
808k
    if (node == NULL)
6352
0
  return(0);
6353
6354
808k
    if (node->type == XML_DOCUMENT_NODE) {
6355
10.4k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6356
10.4k
  if (tmp == NULL)
6357
0
      node = node->children;
6358
10.4k
  else
6359
10.4k
      node = tmp;
6360
6361
10.4k
  if (node == NULL)
6362
0
      return(0);
6363
10.4k
    }
6364
6365
808k
    switch (node->type) {
6366
19.8k
  case XML_COMMENT_NODE:
6367
20.0k
  case XML_PI_NODE:
6368
40.0k
  case XML_CDATA_SECTION_NODE:
6369
338k
  case XML_TEXT_NODE:
6370
338k
      string = node->content;
6371
338k
      if (string == NULL)
6372
0
    return(0);
6373
338k
      if (string[0] == 0)
6374
0
    return(0);
6375
338k
      return(string[0] + (string[1] << 8));
6376
303
  case XML_NAMESPACE_DECL:
6377
303
      string = ((xmlNsPtr)node)->href;
6378
303
      if (string == NULL)
6379
0
    return(0);
6380
303
      if (string[0] == 0)
6381
0
    return(0);
6382
303
      return(string[0] + (string[1] << 8));
6383
5.17k
  case XML_ATTRIBUTE_NODE:
6384
5.17k
      tmp = ((xmlAttrPtr) node)->children;
6385
5.17k
      break;
6386
464k
  case XML_ELEMENT_NODE:
6387
464k
      tmp = node->children;
6388
464k
      break;
6389
0
  default:
6390
0
      return(0);
6391
808k
    }
6392
474k
    while (tmp != NULL) {
6393
360k
  switch (tmp->type) {
6394
35.7k
      case XML_CDATA_SECTION_NODE:
6395
360k
      case XML_TEXT_NODE:
6396
360k
    string = tmp->content;
6397
360k
    break;
6398
0
      default:
6399
0
                string = NULL;
6400
0
    break;
6401
360k
  }
6402
360k
  if ((string != NULL) && (string[0] != 0)) {
6403
360k
      if (len == 1) {
6404
0
    return(ret + (string[0] << 8));
6405
0
      }
6406
360k
      if (string[1] == 0) {
6407
4.70k
    len = 1;
6408
4.70k
    ret = string[0];
6409
356k
      } else {
6410
356k
    return(string[0] + (string[1] << 8));
6411
356k
      }
6412
360k
  }
6413
  /*
6414
   * Skip to next node
6415
   */
6416
4.70k
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6417
0
      if (tmp->children->type != XML_ENTITY_DECL) {
6418
0
    tmp = tmp->children;
6419
0
    continue;
6420
0
      }
6421
0
  }
6422
4.70k
  if (tmp == node)
6423
0
      break;
6424
6425
4.70k
  if (tmp->next != NULL) {
6426
0
      tmp = tmp->next;
6427
0
      continue;
6428
0
  }
6429
6430
4.70k
  do {
6431
4.70k
      tmp = tmp->parent;
6432
4.70k
      if (tmp == NULL)
6433
0
    break;
6434
4.70k
      if (tmp == node) {
6435
4.70k
    tmp = NULL;
6436
4.70k
    break;
6437
4.70k
      }
6438
0
      if (tmp->next != NULL) {
6439
0
    tmp = tmp->next;
6440
0
    break;
6441
0
      }
6442
0
  } while (tmp != NULL);
6443
4.70k
    }
6444
113k
    return(ret);
6445
469k
}
6446
6447
/**
6448
 * xmlXPathStringHash:
6449
 * @string:  a string
6450
 *
6451
 * Function computing the beginning of the string value of the node,
6452
 * used to speed up comparisons
6453
 *
6454
 * Returns an int usable as a hash
6455
 */
6456
static unsigned int
6457
57.7k
xmlXPathStringHash(const xmlChar * string) {
6458
57.7k
    if (string == NULL)
6459
0
  return(0);
6460
57.7k
    if (string[0] == 0)
6461
17.5k
  return(0);
6462
40.2k
    return(string[0] + (string[1] << 8));
6463
57.7k
}
6464
6465
/**
6466
 * xmlXPathCompareNodeSetFloat:
6467
 * @ctxt:  the XPath Parser context
6468
 * @inf:  less than (1) or greater than (0)
6469
 * @strict:  is the comparison strict
6470
 * @arg:  the node set
6471
 * @f:  the value
6472
 *
6473
 * Implement the compare operation between a nodeset and a number
6474
 *     @ns < @val    (1, 1, ...
6475
 *     @ns <= @val   (1, 0, ...
6476
 *     @ns > @val    (0, 1, ...
6477
 *     @ns >= @val   (0, 0, ...
6478
 *
6479
 * If one object to be compared is a node-set and the other is a number,
6480
 * then the comparison will be true if and only if there is a node in the
6481
 * node-set such that the result of performing the comparison on the number
6482
 * to be compared and on the result of converting the string-value of that
6483
 * node to a number using the number function is true.
6484
 *
6485
 * Returns 0 or 1 depending on the results of the test.
6486
 */
6487
static int
6488
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6489
419k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6490
419k
    int i, ret = 0;
6491
419k
    xmlNodeSetPtr ns;
6492
419k
    xmlChar *str2;
6493
6494
419k
    if ((f == NULL) || (arg == NULL) ||
6495
419k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6496
0
  xmlXPathReleaseObject(ctxt->context, arg);
6497
0
  xmlXPathReleaseObject(ctxt->context, f);
6498
0
        return(0);
6499
0
    }
6500
419k
    ns = arg->nodesetval;
6501
419k
    if (ns != NULL) {
6502
1.25M
  for (i = 0;i < ns->nodeNr;i++) {
6503
914k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6504
914k
       if (str2 != NULL) {
6505
914k
     valuePush(ctxt,
6506
914k
         xmlXPathCacheNewString(ctxt->context, str2));
6507
914k
     xmlFree(str2);
6508
914k
     xmlXPathNumberFunction(ctxt, 1);
6509
914k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6510
914k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6511
914k
     if (ret)
6512
1.43k
         break;
6513
914k
       }
6514
914k
  }
6515
345k
    }
6516
419k
    xmlXPathReleaseObject(ctxt->context, arg);
6517
419k
    xmlXPathReleaseObject(ctxt->context, f);
6518
419k
    return(ret);
6519
419k
}
6520
6521
/**
6522
 * xmlXPathCompareNodeSetString:
6523
 * @ctxt:  the XPath Parser context
6524
 * @inf:  less than (1) or greater than (0)
6525
 * @strict:  is the comparison strict
6526
 * @arg:  the node set
6527
 * @s:  the value
6528
 *
6529
 * Implement the compare operation between a nodeset and a string
6530
 *     @ns < @val    (1, 1, ...
6531
 *     @ns <= @val   (1, 0, ...
6532
 *     @ns > @val    (0, 1, ...
6533
 *     @ns >= @val   (0, 0, ...
6534
 *
6535
 * If one object to be compared is a node-set and the other is a string,
6536
 * then the comparison will be true if and only if there is a node in
6537
 * the node-set such that the result of performing the comparison on the
6538
 * string-value of the node and the other string is true.
6539
 *
6540
 * Returns 0 or 1 depending on the results of the test.
6541
 */
6542
static int
6543
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6544
98.2k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6545
98.2k
    int i, ret = 0;
6546
98.2k
    xmlNodeSetPtr ns;
6547
98.2k
    xmlChar *str2;
6548
6549
98.2k
    if ((s == NULL) || (arg == NULL) ||
6550
98.2k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6551
0
  xmlXPathReleaseObject(ctxt->context, arg);
6552
0
  xmlXPathReleaseObject(ctxt->context, s);
6553
0
        return(0);
6554
0
    }
6555
98.2k
    ns = arg->nodesetval;
6556
98.2k
    if (ns != NULL) {
6557
246k
  for (i = 0;i < ns->nodeNr;i++) {
6558
156k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6559
156k
       if (str2 != NULL) {
6560
156k
     valuePush(ctxt,
6561
156k
         xmlXPathCacheNewString(ctxt->context, str2));
6562
156k
     xmlFree(str2);
6563
156k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6564
156k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6565
156k
     if (ret)
6566
2.13k
         break;
6567
156k
       }
6568
156k
  }
6569
93.0k
    }
6570
98.2k
    xmlXPathReleaseObject(ctxt->context, arg);
6571
98.2k
    xmlXPathReleaseObject(ctxt->context, s);
6572
98.2k
    return(ret);
6573
98.2k
}
6574
6575
/**
6576
 * xmlXPathCompareNodeSets:
6577
 * @inf:  less than (1) or greater than (0)
6578
 * @strict:  is the comparison strict
6579
 * @arg1:  the first node set object
6580
 * @arg2:  the second node set object
6581
 *
6582
 * Implement the compare operation on nodesets:
6583
 *
6584
 * If both objects to be compared are node-sets, then the comparison
6585
 * will be true if and only if there is a node in the first node-set
6586
 * and a node in the second node-set such that the result of performing
6587
 * the comparison on the string-values of the two nodes is true.
6588
 * ....
6589
 * When neither object to be compared is a node-set and the operator
6590
 * is <=, <, >= or >, then the objects are compared by converting both
6591
 * objects to numbers and comparing the numbers according to IEEE 754.
6592
 * ....
6593
 * The number function converts its argument to a number as follows:
6594
 *  - a string that consists of optional whitespace followed by an
6595
 *    optional minus sign followed by a Number followed by whitespace
6596
 *    is converted to the IEEE 754 number that is nearest (according
6597
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6598
 *    represented by the string; any other string is converted to NaN
6599
 *
6600
 * Conclusion all nodes need to be converted first to their string value
6601
 * and then the comparison must be done when possible
6602
 */
6603
static int
6604
xmlXPathCompareNodeSets(int inf, int strict,
6605
953k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6606
953k
    int i, j, init = 0;
6607
953k
    double val1;
6608
953k
    double *values2;
6609
953k
    int ret = 0;
6610
953k
    xmlNodeSetPtr ns1;
6611
953k
    xmlNodeSetPtr ns2;
6612
6613
953k
    if ((arg1 == NULL) ||
6614
953k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6615
0
  xmlXPathFreeObject(arg2);
6616
0
        return(0);
6617
0
    }
6618
953k
    if ((arg2 == NULL) ||
6619
953k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6620
0
  xmlXPathFreeObject(arg1);
6621
0
  xmlXPathFreeObject(arg2);
6622
0
        return(0);
6623
0
    }
6624
6625
953k
    ns1 = arg1->nodesetval;
6626
953k
    ns2 = arg2->nodesetval;
6627
6628
953k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6629
642k
  xmlXPathFreeObject(arg1);
6630
642k
  xmlXPathFreeObject(arg2);
6631
642k
  return(0);
6632
642k
    }
6633
310k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6634
140k
  xmlXPathFreeObject(arg1);
6635
140k
  xmlXPathFreeObject(arg2);
6636
140k
  return(0);
6637
140k
    }
6638
6639
169k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6640
169k
    if (values2 == NULL) {
6641
        /* TODO: Propagate memory error. */
6642
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6643
0
  xmlXPathFreeObject(arg1);
6644
0
  xmlXPathFreeObject(arg2);
6645
0
  return(0);
6646
0
    }
6647
959k
    for (i = 0;i < ns1->nodeNr;i++) {
6648
843k
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6649
843k
  if (xmlXPathIsNaN(val1))
6650
714k
      continue;
6651
864k
  for (j = 0;j < ns2->nodeNr;j++) {
6652
789k
      if (init == 0) {
6653
491k
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6654
491k
      }
6655
789k
      if (xmlXPathIsNaN(values2[j]))
6656
561k
    continue;
6657
228k
      if (inf && strict)
6658
25.1k
    ret = (val1 < values2[j]);
6659
203k
      else if (inf && !strict)
6660
166k
    ret = (val1 <= values2[j]);
6661
37.0k
      else if (!inf && strict)
6662
15.6k
    ret = (val1 > values2[j]);
6663
21.4k
      else if (!inf && !strict)
6664
21.4k
    ret = (val1 >= values2[j]);
6665
228k
      if (ret)
6666
54.3k
    break;
6667
228k
  }
6668
129k
  if (ret)
6669
54.3k
      break;
6670
74.9k
  init = 1;
6671
74.9k
    }
6672
169k
    xmlFree(values2);
6673
169k
    xmlXPathFreeObject(arg1);
6674
169k
    xmlXPathFreeObject(arg2);
6675
169k
    return(ret);
6676
169k
}
6677
6678
/**
6679
 * xmlXPathCompareNodeSetValue:
6680
 * @ctxt:  the XPath Parser context
6681
 * @inf:  less than (1) or greater than (0)
6682
 * @strict:  is the comparison strict
6683
 * @arg:  the node set
6684
 * @val:  the value
6685
 *
6686
 * Implement the compare operation between a nodeset and a value
6687
 *     @ns < @val    (1, 1, ...
6688
 *     @ns <= @val   (1, 0, ...
6689
 *     @ns > @val    (0, 1, ...
6690
 *     @ns >= @val   (0, 0, ...
6691
 *
6692
 * If one object to be compared is a node-set and the other is a boolean,
6693
 * then the comparison will be true if and only if the result of performing
6694
 * the comparison on the boolean and on the result of converting
6695
 * the node-set to a boolean using the boolean function is true.
6696
 *
6697
 * Returns 0 or 1 depending on the results of the test.
6698
 */
6699
static int
6700
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6701
1.51M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6702
1.51M
    if ((val == NULL) || (arg == NULL) ||
6703
1.51M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6704
0
        return(0);
6705
6706
1.51M
    switch(val->type) {
6707
419k
        case XPATH_NUMBER:
6708
419k
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6709
0
        case XPATH_NODESET:
6710
0
        case XPATH_XSLT_TREE:
6711
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6712
98.2k
        case XPATH_STRING:
6713
98.2k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6714
996k
        case XPATH_BOOLEAN:
6715
996k
      valuePush(ctxt, arg);
6716
996k
      xmlXPathBooleanFunction(ctxt, 1);
6717
996k
      valuePush(ctxt, val);
6718
996k
      return(xmlXPathCompareValues(ctxt, inf, strict));
6719
0
  default:
6720
0
            xmlGenericError(xmlGenericErrorContext,
6721
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6722
0
                    "and object of type %d\n",
6723
0
                    val->type);
6724
0
            xmlXPathReleaseObject(ctxt->context, arg);
6725
0
            xmlXPathReleaseObject(ctxt->context, val);
6726
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6727
1.51M
    }
6728
0
    return(0);
6729
1.51M
}
6730
6731
/**
6732
 * xmlXPathEqualNodeSetString:
6733
 * @arg:  the nodeset object argument
6734
 * @str:  the string to compare to.
6735
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6736
 *
6737
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6738
 * If one object to be compared is a node-set and the other is a string,
6739
 * then the comparison will be true if and only if there is a node in
6740
 * the node-set such that the result of performing the comparison on the
6741
 * string-value of the node and the other string is true.
6742
 *
6743
 * Returns 0 or 1 depending on the results of the test.
6744
 */
6745
static int
6746
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6747
181k
{
6748
181k
    int i;
6749
181k
    xmlNodeSetPtr ns;
6750
181k
    xmlChar *str2;
6751
181k
    unsigned int hash;
6752
6753
181k
    if ((str == NULL) || (arg == NULL) ||
6754
181k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6755
0
        return (0);
6756
181k
    ns = arg->nodesetval;
6757
    /*
6758
     * A NULL nodeset compared with a string is always false
6759
     * (since there is no node equal, and no node not equal)
6760
     */
6761
181k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6762
124k
        return (0);
6763
57.7k
    hash = xmlXPathStringHash(str);
6764
221k
    for (i = 0; i < ns->nodeNr; i++) {
6765
176k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6766
12.7k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6767
12.7k
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6768
6.89k
                xmlFree(str2);
6769
6.89k
    if (neq)
6770
2.94k
        continue;
6771
3.95k
                return (1);
6772
6.89k
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6773
0
    if (neq)
6774
0
        continue;
6775
0
                return (1);
6776
5.86k
            } else if (neq) {
6777
0
    if (str2 != NULL)
6778
0
        xmlFree(str2);
6779
0
    return (1);
6780
0
      }
6781
5.86k
            if (str2 != NULL)
6782
5.86k
                xmlFree(str2);
6783
163k
        } else if (neq)
6784
9.09k
      return (1);
6785
176k
    }
6786
44.7k
    return (0);
6787
57.7k
}
6788
6789
/**
6790
 * xmlXPathEqualNodeSetFloat:
6791
 * @arg:  the nodeset object argument
6792
 * @f:  the float to compare to
6793
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6794
 *
6795
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6796
 * If one object to be compared is a node-set and the other is a number,
6797
 * then the comparison will be true if and only if there is a node in
6798
 * the node-set such that the result of performing the comparison on the
6799
 * number to be compared and on the result of converting the string-value
6800
 * of that node to a number using the number function is true.
6801
 *
6802
 * Returns 0 or 1 depending on the results of the test.
6803
 */
6804
static int
6805
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6806
222k
    xmlXPathObjectPtr arg, double f, int neq) {
6807
222k
  int i, ret=0;
6808
222k
  xmlNodeSetPtr ns;
6809
222k
  xmlChar *str2;
6810
222k
  xmlXPathObjectPtr val;
6811
222k
  double v;
6812
6813
222k
    if ((arg == NULL) ||
6814
222k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6815
0
        return(0);
6816
6817
222k
    ns = arg->nodesetval;
6818
222k
    if (ns != NULL) {
6819
657k
  for (i=0;i<ns->nodeNr;i++) {
6820
453k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6821
453k
      if (str2 != NULL) {
6822
453k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6823
453k
    xmlFree(str2);
6824
453k
    xmlXPathNumberFunction(ctxt, 1);
6825
453k
    val = valuePop(ctxt);
6826
453k
    v = val->floatval;
6827
453k
    xmlXPathReleaseObject(ctxt->context, val);
6828
453k
    if (!xmlXPathIsNaN(v)) {
6829
248k
        if ((!neq) && (v==f)) {
6830
2.58k
      ret = 1;
6831
2.58k
      break;
6832
245k
        } else if ((neq) && (v!=f)) {
6833
767
      ret = 1;
6834
767
      break;
6835
767
        }
6836
248k
    } else { /* NaN is unequal to any value */
6837
205k
        if (neq)
6838
47.9k
      ret = 1;
6839
205k
    }
6840
453k
      }
6841
453k
  }
6842
207k
    }
6843
6844
222k
    return(ret);
6845
222k
}
6846
6847
6848
/**
6849
 * xmlXPathEqualNodeSets:
6850
 * @arg1:  first nodeset object argument
6851
 * @arg2:  second nodeset object argument
6852
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6853
 *
6854
 * Implement the equal / not equal operation on XPath nodesets:
6855
 * @arg1 == @arg2  or  @arg1 != @arg2
6856
 * If both objects to be compared are node-sets, then the comparison
6857
 * will be true if and only if there is a node in the first node-set and
6858
 * a node in the second node-set such that the result of performing the
6859
 * comparison on the string-values of the two nodes is true.
6860
 *
6861
 * (needless to say, this is a costly operation)
6862
 *
6863
 * Returns 0 or 1 depending on the results of the test.
6864
 */
6865
static int
6866
105k
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6867
105k
    int i, j;
6868
105k
    unsigned int *hashs1;
6869
105k
    unsigned int *hashs2;
6870
105k
    xmlChar **values1;
6871
105k
    xmlChar **values2;
6872
105k
    int ret = 0;
6873
105k
    xmlNodeSetPtr ns1;
6874
105k
    xmlNodeSetPtr ns2;
6875
6876
105k
    if ((arg1 == NULL) ||
6877
105k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6878
0
        return(0);
6879
105k
    if ((arg2 == NULL) ||
6880
105k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6881
0
        return(0);
6882
6883
105k
    ns1 = arg1->nodesetval;
6884
105k
    ns2 = arg2->nodesetval;
6885
6886
105k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6887
44.3k
  return(0);
6888
61.5k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6889
14.0k
  return(0);
6890
6891
    /*
6892
     * for equal, check if there is a node pertaining to both sets
6893
     */
6894
47.4k
    if (neq == 0)
6895
599k
  for (i = 0;i < ns1->nodeNr;i++)
6896
1.16M
      for (j = 0;j < ns2->nodeNr;j++)
6897
598k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6898
5.13k
        return(1);
6899
6900
42.2k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6901
42.2k
    if (values1 == NULL) {
6902
        /* TODO: Propagate memory error. */
6903
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6904
0
  return(0);
6905
0
    }
6906
42.2k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6907
42.2k
    if (hashs1 == NULL) {
6908
        /* TODO: Propagate memory error. */
6909
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910
0
  xmlFree(values1);
6911
0
  return(0);
6912
0
    }
6913
42.2k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6914
42.2k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6915
42.2k
    if (values2 == NULL) {
6916
        /* TODO: Propagate memory error. */
6917
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918
0
  xmlFree(hashs1);
6919
0
  xmlFree(values1);
6920
0
  return(0);
6921
0
    }
6922
42.2k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6923
42.2k
    if (hashs2 == NULL) {
6924
        /* TODO: Propagate memory error. */
6925
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6926
0
  xmlFree(hashs1);
6927
0
  xmlFree(values1);
6928
0
  xmlFree(values2);
6929
0
  return(0);
6930
0
    }
6931
42.2k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6932
611k
    for (i = 0;i < ns1->nodeNr;i++) {
6933
578k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6934
1.16M
  for (j = 0;j < ns2->nodeNr;j++) {
6935
593k
      if (i == 0)
6936
53.7k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6937
593k
      if (hashs1[i] != hashs2[j]) {
6938
328k
    if (neq) {
6939
803
        ret = 1;
6940
803
        break;
6941
803
    }
6942
328k
      }
6943
264k
      else {
6944
264k
    if (values1[i] == NULL)
6945
259k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6946
264k
    if (values2[j] == NULL)
6947
44.2k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6948
264k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6949
264k
    if (ret)
6950
7.90k
        break;
6951
264k
      }
6952
593k
  }
6953
578k
  if (ret)
6954
8.70k
      break;
6955
578k
    }
6956
702k
    for (i = 0;i < ns1->nodeNr;i++)
6957
659k
  if (values1[i] != NULL)
6958
259k
      xmlFree(values1[i]);
6959
121k
    for (j = 0;j < ns2->nodeNr;j++)
6960
79.5k
  if (values2[j] != NULL)
6961
44.2k
      xmlFree(values2[j]);
6962
42.2k
    xmlFree(values1);
6963
42.2k
    xmlFree(values2);
6964
42.2k
    xmlFree(hashs1);
6965
42.2k
    xmlFree(hashs2);
6966
42.2k
    return(ret);
6967
42.2k
}
6968
6969
static int
6970
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6971
1.95M
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6972
1.95M
    int ret = 0;
6973
    /*
6974
     *At this point we are assured neither arg1 nor arg2
6975
     *is a nodeset, so we can just pick the appropriate routine.
6976
     */
6977
1.95M
    switch (arg1->type) {
6978
0
        case XPATH_UNDEFINED:
6979
#ifdef DEBUG_EXPR
6980
      xmlGenericError(xmlGenericErrorContext,
6981
        "Equal: undefined\n");
6982
#endif
6983
0
      break;
6984
1.52M
        case XPATH_BOOLEAN:
6985
1.52M
      switch (arg2->type) {
6986
0
          case XPATH_UNDEFINED:
6987
#ifdef DEBUG_EXPR
6988
        xmlGenericError(xmlGenericErrorContext,
6989
          "Equal: undefined\n");
6990
#endif
6991
0
        break;
6992
1.10M
    case XPATH_BOOLEAN:
6993
#ifdef DEBUG_EXPR
6994
        xmlGenericError(xmlGenericErrorContext,
6995
          "Equal: %d boolean %d \n",
6996
          arg1->boolval, arg2->boolval);
6997
#endif
6998
1.10M
        ret = (arg1->boolval == arg2->boolval);
6999
1.10M
        break;
7000
409k
    case XPATH_NUMBER:
7001
409k
        ret = (arg1->boolval ==
7002
409k
         xmlXPathCastNumberToBoolean(arg2->floatval));
7003
409k
        break;
7004
6.83k
    case XPATH_STRING:
7005
6.83k
        if ((arg2->stringval == NULL) ||
7006
6.83k
      (arg2->stringval[0] == 0)) ret = 0;
7007
4.78k
        else
7008
4.78k
      ret = 1;
7009
6.83k
        ret = (arg1->boolval == ret);
7010
6.83k
        break;
7011
0
    case XPATH_USERS:
7012
#ifdef LIBXML_XPTR_LOCS_ENABLED
7013
    case XPATH_POINT:
7014
    case XPATH_RANGE:
7015
    case XPATH_LOCATIONSET:
7016
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7017
0
        TODO
7018
0
        break;
7019
0
    case XPATH_NODESET:
7020
0
    case XPATH_XSLT_TREE:
7021
0
        break;
7022
1.52M
      }
7023
1.52M
      break;
7024
1.52M
        case XPATH_NUMBER:
7025
359k
      switch (arg2->type) {
7026
0
          case XPATH_UNDEFINED:
7027
#ifdef DEBUG_EXPR
7028
        xmlGenericError(xmlGenericErrorContext,
7029
          "Equal: undefined\n");
7030
#endif
7031
0
        break;
7032
114k
    case XPATH_BOOLEAN:
7033
114k
        ret = (arg2->boolval==
7034
114k
         xmlXPathCastNumberToBoolean(arg1->floatval));
7035
114k
        break;
7036
9.92k
    case XPATH_STRING:
7037
9.92k
        valuePush(ctxt, arg2);
7038
9.92k
        xmlXPathNumberFunction(ctxt, 1);
7039
9.92k
        arg2 = valuePop(ctxt);
7040
                    /* Falls through. */
7041
244k
    case XPATH_NUMBER:
7042
        /* Hand check NaN and Infinity equalities */
7043
244k
        if (xmlXPathIsNaN(arg1->floatval) ||
7044
244k
          xmlXPathIsNaN(arg2->floatval)) {
7045
222k
            ret = 0;
7046
222k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7047
4.85k
            if (xmlXPathIsInf(arg2->floatval) == 1)
7048
1.54k
          ret = 1;
7049
3.31k
      else
7050
3.31k
          ret = 0;
7051
17.1k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7052
13.9k
      if (xmlXPathIsInf(arg2->floatval) == -1)
7053
6.68k
          ret = 1;
7054
7.28k
      else
7055
7.28k
          ret = 0;
7056
13.9k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7057
2.58k
      if (xmlXPathIsInf(arg1->floatval) == 1)
7058
0
          ret = 1;
7059
2.58k
      else
7060
2.58k
          ret = 0;
7061
2.58k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7062
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7063
0
          ret = 1;
7064
0
      else
7065
0
          ret = 0;
7066
647
        } else {
7067
647
            ret = (arg1->floatval == arg2->floatval);
7068
647
        }
7069
244k
        break;
7070
0
    case XPATH_USERS:
7071
#ifdef LIBXML_XPTR_LOCS_ENABLED
7072
    case XPATH_POINT:
7073
    case XPATH_RANGE:
7074
    case XPATH_LOCATIONSET:
7075
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7076
0
        TODO
7077
0
        break;
7078
0
    case XPATH_NODESET:
7079
0
    case XPATH_XSLT_TREE:
7080
0
        break;
7081
359k
      }
7082
359k
      break;
7083
359k
        case XPATH_STRING:
7084
74.2k
      switch (arg2->type) {
7085
0
          case XPATH_UNDEFINED:
7086
#ifdef DEBUG_EXPR
7087
        xmlGenericError(xmlGenericErrorContext,
7088
          "Equal: undefined\n");
7089
#endif
7090
0
        break;
7091
46.9k
    case XPATH_BOOLEAN:
7092
46.9k
        if ((arg1->stringval == NULL) ||
7093
46.9k
      (arg1->stringval[0] == 0)) ret = 0;
7094
46.7k
        else
7095
46.7k
      ret = 1;
7096
46.9k
        ret = (arg2->boolval == ret);
7097
46.9k
        break;
7098
451
    case XPATH_STRING:
7099
451
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7100
451
        break;
7101
26.8k
    case XPATH_NUMBER:
7102
26.8k
        valuePush(ctxt, arg1);
7103
26.8k
        xmlXPathNumberFunction(ctxt, 1);
7104
26.8k
        arg1 = valuePop(ctxt);
7105
        /* Hand check NaN and Infinity equalities */
7106
26.8k
        if (xmlXPathIsNaN(arg1->floatval) ||
7107
26.8k
          xmlXPathIsNaN(arg2->floatval)) {
7108
1.83k
            ret = 0;
7109
25.0k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7110
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7111
0
          ret = 1;
7112
0
      else
7113
0
          ret = 0;
7114
25.0k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7115
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7116
0
          ret = 1;
7117
0
      else
7118
0
          ret = 0;
7119
25.0k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7120
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7121
0
          ret = 1;
7122
0
      else
7123
0
          ret = 0;
7124
25.0k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7125
10.8k
      if (xmlXPathIsInf(arg1->floatval) == -1)
7126
0
          ret = 1;
7127
10.8k
      else
7128
10.8k
          ret = 0;
7129
14.1k
        } else {
7130
14.1k
            ret = (arg1->floatval == arg2->floatval);
7131
14.1k
        }
7132
26.8k
        break;
7133
0
    case XPATH_USERS:
7134
#ifdef LIBXML_XPTR_LOCS_ENABLED
7135
    case XPATH_POINT:
7136
    case XPATH_RANGE:
7137
    case XPATH_LOCATIONSET:
7138
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7139
0
        TODO
7140
0
        break;
7141
0
    case XPATH_NODESET:
7142
0
    case XPATH_XSLT_TREE:
7143
0
        break;
7144
74.2k
      }
7145
74.2k
      break;
7146
74.2k
        case XPATH_USERS:
7147
#ifdef LIBXML_XPTR_LOCS_ENABLED
7148
  case XPATH_POINT:
7149
  case XPATH_RANGE:
7150
  case XPATH_LOCATIONSET:
7151
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7152
0
      TODO
7153
0
      break;
7154
0
  case XPATH_NODESET:
7155
0
  case XPATH_XSLT_TREE:
7156
0
      break;
7157
1.95M
    }
7158
1.95M
    xmlXPathReleaseObject(ctxt->context, arg1);
7159
1.95M
    xmlXPathReleaseObject(ctxt->context, arg2);
7160
1.95M
    return(ret);
7161
1.95M
}
7162
7163
/**
7164
 * xmlXPathEqualValues:
7165
 * @ctxt:  the XPath Parser context
7166
 *
7167
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7168
 *
7169
 * Returns 0 or 1 depending on the results of the test.
7170
 */
7171
int
7172
2.83M
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7173
2.83M
    xmlXPathObjectPtr arg1, arg2, argtmp;
7174
2.83M
    int ret = 0;
7175
7176
2.83M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7177
2.83M
    arg2 = valuePop(ctxt);
7178
2.83M
    arg1 = valuePop(ctxt);
7179
2.83M
    if ((arg1 == NULL) || (arg2 == NULL)) {
7180
0
  if (arg1 != NULL)
7181
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7182
0
  else
7183
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7184
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7185
0
    }
7186
7187
2.83M
    if (arg1 == arg2) {
7188
#ifdef DEBUG_EXPR
7189
        xmlGenericError(xmlGenericErrorContext,
7190
    "Equal: by pointer\n");
7191
#endif
7192
0
  xmlXPathFreeObject(arg1);
7193
0
        return(1);
7194
0
    }
7195
7196
    /*
7197
     *If either argument is a nodeset, it's a 'special case'
7198
     */
7199
2.83M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7200
2.83M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7201
  /*
7202
   *Hack it to assure arg1 is the nodeset
7203
   */
7204
1.03M
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7205
678k
    argtmp = arg2;
7206
678k
    arg2 = arg1;
7207
678k
    arg1 = argtmp;
7208
678k
  }
7209
1.03M
  switch (arg2->type) {
7210
0
      case XPATH_UNDEFINED:
7211
#ifdef DEBUG_EXPR
7212
    xmlGenericError(xmlGenericErrorContext,
7213
      "Equal: undefined\n");
7214
#endif
7215
0
    break;
7216
72.2k
      case XPATH_NODESET:
7217
72.2k
      case XPATH_XSLT_TREE:
7218
72.2k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7219
72.2k
    break;
7220
631k
      case XPATH_BOOLEAN:
7221
631k
    if ((arg1->nodesetval == NULL) ||
7222
631k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7223
217k
    else
7224
217k
        ret = 1;
7225
631k
    ret = (ret == arg2->boolval);
7226
631k
    break;
7227
160k
      case XPATH_NUMBER:
7228
160k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7229
160k
    break;
7230
166k
      case XPATH_STRING:
7231
166k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7232
166k
    break;
7233
0
      case XPATH_USERS:
7234
#ifdef LIBXML_XPTR_LOCS_ENABLED
7235
      case XPATH_POINT:
7236
      case XPATH_RANGE:
7237
      case XPATH_LOCATIONSET:
7238
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7239
0
    TODO
7240
0
    break;
7241
1.03M
  }
7242
1.03M
  xmlXPathReleaseObject(ctxt->context, arg1);
7243
1.03M
  xmlXPathReleaseObject(ctxt->context, arg2);
7244
1.03M
  return(ret);
7245
1.03M
    }
7246
7247
1.80M
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7248
2.83M
}
7249
7250
/**
7251
 * xmlXPathNotEqualValues:
7252
 * @ctxt:  the XPath Parser context
7253
 *
7254
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7255
 *
7256
 * Returns 0 or 1 depending on the results of the test.
7257
 */
7258
int
7259
481k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7260
481k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7261
481k
    int ret = 0;
7262
7263
481k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7264
481k
    arg2 = valuePop(ctxt);
7265
481k
    arg1 = valuePop(ctxt);
7266
481k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7267
0
  if (arg1 != NULL)
7268
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7269
0
  else
7270
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7271
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7272
0
    }
7273
7274
481k
    if (arg1 == arg2) {
7275
#ifdef DEBUG_EXPR
7276
        xmlGenericError(xmlGenericErrorContext,
7277
    "NotEqual: by pointer\n");
7278
#endif
7279
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7280
0
        return(0);
7281
0
    }
7282
7283
    /*
7284
     *If either argument is a nodeset, it's a 'special case'
7285
     */
7286
481k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7287
481k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7288
  /*
7289
   *Hack it to assure arg1 is the nodeset
7290
   */
7291
334k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7292
283k
    argtmp = arg2;
7293
283k
    arg2 = arg1;
7294
283k
    arg1 = argtmp;
7295
283k
  }
7296
334k
  switch (arg2->type) {
7297
0
      case XPATH_UNDEFINED:
7298
#ifdef DEBUG_EXPR
7299
    xmlGenericError(xmlGenericErrorContext,
7300
      "NotEqual: undefined\n");
7301
#endif
7302
0
    break;
7303
33.5k
      case XPATH_NODESET:
7304
33.5k
      case XPATH_XSLT_TREE:
7305
33.5k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7306
33.5k
    break;
7307
223k
      case XPATH_BOOLEAN:
7308
223k
    if ((arg1->nodesetval == NULL) ||
7309
223k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7310
141k
    else
7311
141k
        ret = 1;
7312
223k
    ret = (ret != arg2->boolval);
7313
223k
    break;
7314
61.7k
      case XPATH_NUMBER:
7315
61.7k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7316
61.7k
    break;
7317
15.1k
      case XPATH_STRING:
7318
15.1k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7319
15.1k
    break;
7320
0
      case XPATH_USERS:
7321
#ifdef LIBXML_XPTR_LOCS_ENABLED
7322
      case XPATH_POINT:
7323
      case XPATH_RANGE:
7324
      case XPATH_LOCATIONSET:
7325
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7326
0
    TODO
7327
0
    break;
7328
334k
  }
7329
334k
  xmlXPathReleaseObject(ctxt->context, arg1);
7330
334k
  xmlXPathReleaseObject(ctxt->context, arg2);
7331
334k
  return(ret);
7332
334k
    }
7333
7334
147k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7335
481k
}
7336
7337
/**
7338
 * xmlXPathCompareValues:
7339
 * @ctxt:  the XPath Parser context
7340
 * @inf:  less than (1) or greater than (0)
7341
 * @strict:  is the comparison strict
7342
 *
7343
 * Implement the compare operation on XPath objects:
7344
 *     @arg1 < @arg2    (1, 1, ...
7345
 *     @arg1 <= @arg2   (1, 0, ...
7346
 *     @arg1 > @arg2    (0, 1, ...
7347
 *     @arg1 >= @arg2   (0, 0, ...
7348
 *
7349
 * When neither object to be compared is a node-set and the operator is
7350
 * <=, <, >=, >, then the objects are compared by converted both objects
7351
 * to numbers and comparing the numbers according to IEEE 754. The <
7352
 * comparison will be true if and only if the first number is less than the
7353
 * second number. The <= comparison will be true if and only if the first
7354
 * number is less than or equal to the second number. The > comparison
7355
 * will be true if and only if the first number is greater than the second
7356
 * number. The >= comparison will be true if and only if the first number
7357
 * is greater than or equal to the second number.
7358
 *
7359
 * Returns 1 if the comparison succeeded, 0 if it failed
7360
 */
7361
int
7362
5.13M
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7363
5.13M
    int ret = 0, arg1i = 0, arg2i = 0;
7364
5.13M
    xmlXPathObjectPtr arg1, arg2;
7365
7366
5.13M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7367
5.13M
    arg2 = valuePop(ctxt);
7368
5.13M
    arg1 = valuePop(ctxt);
7369
5.13M
    if ((arg1 == NULL) || (arg2 == NULL)) {
7370
0
  if (arg1 != NULL)
7371
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7372
0
  else
7373
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7374
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7375
0
    }
7376
7377
5.13M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7378
5.13M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7379
  /*
7380
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7381
   * are not freed from within this routine; they will be freed from the
7382
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7383
   */
7384
2.46M
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7385
2.46M
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7386
953k
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7387
1.51M
  } else {
7388
1.51M
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7389
233k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7390
233k
                                arg1, arg2);
7391
1.28M
      } else {
7392
1.28M
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7393
1.28M
                                arg2, arg1);
7394
1.28M
      }
7395
1.51M
  }
7396
2.46M
  return(ret);
7397
2.46M
    }
7398
7399
2.66M
    if (arg1->type != XPATH_NUMBER) {
7400
1.53M
  valuePush(ctxt, arg1);
7401
1.53M
  xmlXPathNumberFunction(ctxt, 1);
7402
1.53M
  arg1 = valuePop(ctxt);
7403
1.53M
    }
7404
2.66M
    if (arg1->type != XPATH_NUMBER) {
7405
0
  xmlXPathFreeObject(arg1);
7406
0
  xmlXPathFreeObject(arg2);
7407
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7408
0
    }
7409
2.66M
    if (arg2->type != XPATH_NUMBER) {
7410
1.15M
  valuePush(ctxt, arg2);
7411
1.15M
  xmlXPathNumberFunction(ctxt, 1);
7412
1.15M
  arg2 = valuePop(ctxt);
7413
1.15M
    }
7414
2.66M
    if (arg2->type != XPATH_NUMBER) {
7415
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7416
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7417
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7418
0
    }
7419
    /*
7420
     * Add tests for infinity and nan
7421
     * => feedback on 3.4 for Inf and NaN
7422
     */
7423
    /* Hand check NaN and Infinity comparisons */
7424
2.66M
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7425
1.47M
  ret=0;
7426
1.47M
    } else {
7427
1.18M
  arg1i=xmlXPathIsInf(arg1->floatval);
7428
1.18M
  arg2i=xmlXPathIsInf(arg2->floatval);
7429
1.18M
  if (inf && strict) {
7430
816k
      if ((arg1i == -1 && arg2i != -1) ||
7431
816k
    (arg2i == 1 && arg1i != 1)) {
7432
5.42k
    ret = 1;
7433
810k
      } else if (arg1i == 0 && arg2i == 0) {
7434
801k
    ret = (arg1->floatval < arg2->floatval);
7435
801k
      } else {
7436
9.35k
    ret = 0;
7437
9.35k
      }
7438
816k
  }
7439
369k
  else if (inf && !strict) {
7440
130k
      if (arg1i == -1 || arg2i == 1) {
7441
1.24k
    ret = 1;
7442
129k
      } else if (arg1i == 0 && arg2i == 0) {
7443
126k
    ret = (arg1->floatval <= arg2->floatval);
7444
126k
      } else {
7445
2.54k
    ret = 0;
7446
2.54k
      }
7447
130k
  }
7448
238k
  else if (!inf && strict) {
7449
112k
      if ((arg1i == 1 && arg2i != 1) ||
7450
112k
    (arg2i == -1 && arg1i != -1)) {
7451
941
    ret = 1;
7452
111k
      } else if (arg1i == 0 && arg2i == 0) {
7453
107k
    ret = (arg1->floatval > arg2->floatval);
7454
107k
      } else {
7455
3.41k
    ret = 0;
7456
3.41k
      }
7457
112k
  }
7458
126k
  else if (!inf && !strict) {
7459
126k
      if (arg1i == 1 || arg2i == -1) {
7460
28.9k
    ret = 1;
7461
97.4k
      } else if (arg1i == 0 && arg2i == 0) {
7462
81.6k
    ret = (arg1->floatval >= arg2->floatval);
7463
81.6k
      } else {
7464
15.8k
    ret = 0;
7465
15.8k
      }
7466
126k
  }
7467
1.18M
    }
7468
2.66M
    xmlXPathReleaseObject(ctxt->context, arg1);
7469
2.66M
    xmlXPathReleaseObject(ctxt->context, arg2);
7470
2.66M
    return(ret);
7471
2.66M
}
7472
7473
/**
7474
 * xmlXPathValueFlipSign:
7475
 * @ctxt:  the XPath Parser context
7476
 *
7477
 * Implement the unary - operation on an XPath object
7478
 * The numeric operators convert their operands to numbers as if
7479
 * by calling the number function.
7480
 */
7481
void
7482
1.47M
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7483
1.47M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7484
1.47M
    CAST_TO_NUMBER;
7485
1.47M
    CHECK_TYPE(XPATH_NUMBER);
7486
1.47M
    ctxt->value->floatval = -ctxt->value->floatval;
7487
1.47M
}
7488
7489
/**
7490
 * xmlXPathAddValues:
7491
 * @ctxt:  the XPath Parser context
7492
 *
7493
 * Implement the add operation on XPath objects:
7494
 * The numeric operators convert their operands to numbers as if
7495
 * by calling the number function.
7496
 */
7497
void
7498
154k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7499
154k
    xmlXPathObjectPtr arg;
7500
154k
    double val;
7501
7502
154k
    arg = valuePop(ctxt);
7503
154k
    if (arg == NULL)
7504
154k
  XP_ERROR(XPATH_INVALID_OPERAND);
7505
154k
    val = xmlXPathCastToNumber(arg);
7506
154k
    xmlXPathReleaseObject(ctxt->context, arg);
7507
154k
    CAST_TO_NUMBER;
7508
154k
    CHECK_TYPE(XPATH_NUMBER);
7509
154k
    ctxt->value->floatval += val;
7510
154k
}
7511
7512
/**
7513
 * xmlXPathSubValues:
7514
 * @ctxt:  the XPath Parser context
7515
 *
7516
 * Implement the subtraction operation on XPath objects:
7517
 * The numeric operators convert their operands to numbers as if
7518
 * by calling the number function.
7519
 */
7520
void
7521
1.83M
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7522
1.83M
    xmlXPathObjectPtr arg;
7523
1.83M
    double val;
7524
7525
1.83M
    arg = valuePop(ctxt);
7526
1.83M
    if (arg == NULL)
7527
1.83M
  XP_ERROR(XPATH_INVALID_OPERAND);
7528
1.83M
    val = xmlXPathCastToNumber(arg);
7529
1.83M
    xmlXPathReleaseObject(ctxt->context, arg);
7530
1.83M
    CAST_TO_NUMBER;
7531
1.83M
    CHECK_TYPE(XPATH_NUMBER);
7532
1.83M
    ctxt->value->floatval -= val;
7533
1.83M
}
7534
7535
/**
7536
 * xmlXPathMultValues:
7537
 * @ctxt:  the XPath Parser context
7538
 *
7539
 * Implement the multiply operation on XPath objects:
7540
 * The numeric operators convert their operands to numbers as if
7541
 * by calling the number function.
7542
 */
7543
void
7544
2.81M
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7545
2.81M
    xmlXPathObjectPtr arg;
7546
2.81M
    double val;
7547
7548
2.81M
    arg = valuePop(ctxt);
7549
2.81M
    if (arg == NULL)
7550
2.81M
  XP_ERROR(XPATH_INVALID_OPERAND);
7551
2.81M
    val = xmlXPathCastToNumber(arg);
7552
2.81M
    xmlXPathReleaseObject(ctxt->context, arg);
7553
2.81M
    CAST_TO_NUMBER;
7554
2.81M
    CHECK_TYPE(XPATH_NUMBER);
7555
2.81M
    ctxt->value->floatval *= val;
7556
2.81M
}
7557
7558
/**
7559
 * xmlXPathDivValues:
7560
 * @ctxt:  the XPath Parser context
7561
 *
7562
 * Implement the div operation on XPath objects @arg1 / @arg2:
7563
 * The numeric operators convert their operands to numbers as if
7564
 * by calling the number function.
7565
 */
7566
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7567
void
7568
17.4k
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7569
17.4k
    xmlXPathObjectPtr arg;
7570
17.4k
    double val;
7571
7572
17.4k
    arg = valuePop(ctxt);
7573
17.4k
    if (arg == NULL)
7574
17.4k
  XP_ERROR(XPATH_INVALID_OPERAND);
7575
17.4k
    val = xmlXPathCastToNumber(arg);
7576
17.4k
    xmlXPathReleaseObject(ctxt->context, arg);
7577
17.4k
    CAST_TO_NUMBER;
7578
17.4k
    CHECK_TYPE(XPATH_NUMBER);
7579
17.4k
    ctxt->value->floatval /= val;
7580
17.4k
}
7581
7582
/**
7583
 * xmlXPathModValues:
7584
 * @ctxt:  the XPath Parser context
7585
 *
7586
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7587
 * The numeric operators convert their operands to numbers as if
7588
 * by calling the number function.
7589
 */
7590
void
7591
20.2k
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7592
20.2k
    xmlXPathObjectPtr arg;
7593
20.2k
    double arg1, arg2;
7594
7595
20.2k
    arg = valuePop(ctxt);
7596
20.2k
    if (arg == NULL)
7597
20.2k
  XP_ERROR(XPATH_INVALID_OPERAND);
7598
20.2k
    arg2 = xmlXPathCastToNumber(arg);
7599
20.2k
    xmlXPathReleaseObject(ctxt->context, arg);
7600
20.2k
    CAST_TO_NUMBER;
7601
20.2k
    CHECK_TYPE(XPATH_NUMBER);
7602
20.2k
    arg1 = ctxt->value->floatval;
7603
20.2k
    if (arg2 == 0)
7604
228
  ctxt->value->floatval = xmlXPathNAN;
7605
19.9k
    else {
7606
19.9k
  ctxt->value->floatval = fmod(arg1, arg2);
7607
19.9k
    }
7608
20.2k
}
7609
7610
/************************************************************************
7611
 *                  *
7612
 *    The traversal functions         *
7613
 *                  *
7614
 ************************************************************************/
7615
7616
/*
7617
 * A traversal function enumerates nodes along an axis.
7618
 * Initially it must be called with NULL, and it indicates
7619
 * termination on the axis by returning NULL.
7620
 */
7621
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7622
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7623
7624
/*
7625
 * xmlXPathTraversalFunctionExt:
7626
 * A traversal function enumerates nodes along an axis.
7627
 * Initially it must be called with NULL, and it indicates
7628
 * termination on the axis by returning NULL.
7629
 * The context node of the traversal is specified via @contextNode.
7630
 */
7631
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7632
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7633
7634
/*
7635
 * xmlXPathNodeSetMergeFunction:
7636
 * Used for merging node sets in xmlXPathCollectAndTest().
7637
 */
7638
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7639
        (xmlNodeSetPtr, xmlNodeSetPtr);
7640
7641
7642
/**
7643
 * xmlXPathNextSelf:
7644
 * @ctxt:  the XPath Parser context
7645
 * @cur:  the current node in the traversal
7646
 *
7647
 * Traversal function for the "self" direction
7648
 * The self axis contains just the context node itself
7649
 *
7650
 * Returns the next element following that axis
7651
 */
7652
xmlNodePtr
7653
2.14k
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7654
2.14k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7655
2.14k
    if (cur == NULL)
7656
1.07k
        return(ctxt->context->node);
7657
1.07k
    return(NULL);
7658
2.14k
}
7659
7660
/**
7661
 * xmlXPathNextChild:
7662
 * @ctxt:  the XPath Parser context
7663
 * @cur:  the current node in the traversal
7664
 *
7665
 * Traversal function for the "child" direction
7666
 * The child axis contains the children of the context node in document order.
7667
 *
7668
 * Returns the next element following that axis
7669
 */
7670
xmlNodePtr
7671
493k
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7672
493k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7673
493k
    if (cur == NULL) {
7674
228k
  if (ctxt->context->node == NULL) return(NULL);
7675
228k
  switch (ctxt->context->node->type) {
7676
98.6k
            case XML_ELEMENT_NODE:
7677
200k
            case XML_TEXT_NODE:
7678
205k
            case XML_CDATA_SECTION_NODE:
7679
205k
            case XML_ENTITY_REF_NODE:
7680
205k
            case XML_ENTITY_NODE:
7681
213k
            case XML_PI_NODE:
7682
222k
            case XML_COMMENT_NODE:
7683
222k
            case XML_NOTATION_NODE:
7684
222k
            case XML_DTD_NODE:
7685
222k
    return(ctxt->context->node->children);
7686
4.53k
            case XML_DOCUMENT_NODE:
7687
4.53k
            case XML_DOCUMENT_TYPE_NODE:
7688
4.53k
            case XML_DOCUMENT_FRAG_NODE:
7689
4.53k
            case XML_HTML_DOCUMENT_NODE:
7690
4.53k
    return(((xmlDocPtr) ctxt->context->node)->children);
7691
0
      case XML_ELEMENT_DECL:
7692
0
      case XML_ATTRIBUTE_DECL:
7693
0
      case XML_ENTITY_DECL:
7694
1.36k
            case XML_ATTRIBUTE_NODE:
7695
1.36k
      case XML_NAMESPACE_DECL:
7696
1.36k
      case XML_XINCLUDE_START:
7697
1.36k
      case XML_XINCLUDE_END:
7698
1.36k
    return(NULL);
7699
228k
  }
7700
0
  return(NULL);
7701
228k
    }
7702
265k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7703
265k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7704
0
  return(NULL);
7705
265k
    return(cur->next);
7706
265k
}
7707
7708
/**
7709
 * xmlXPathNextChildElement:
7710
 * @ctxt:  the XPath Parser context
7711
 * @cur:  the current node in the traversal
7712
 *
7713
 * Traversal function for the "child" direction and nodes of type element.
7714
 * The child axis contains the children of the context node in document order.
7715
 *
7716
 * Returns the next element following that axis
7717
 */
7718
static xmlNodePtr
7719
45.4M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7720
45.4M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7721
45.4M
    if (cur == NULL) {
7722
25.9M
  cur = ctxt->context->node;
7723
25.9M
  if (cur == NULL) return(NULL);
7724
  /*
7725
  * Get the first element child.
7726
  */
7727
25.9M
  switch (cur->type) {
7728
17.7M
            case XML_ELEMENT_NODE:
7729
17.7M
      case XML_DOCUMENT_FRAG_NODE:
7730
17.7M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7731
17.7M
            case XML_ENTITY_NODE:
7732
17.7M
    cur = cur->children;
7733
17.7M
    if (cur != NULL) {
7734
13.4M
        if (cur->type == XML_ELEMENT_NODE)
7735
0
      return(cur);
7736
13.4M
        do {
7737
13.4M
      cur = cur->next;
7738
13.4M
        } while ((cur != NULL) &&
7739
13.4M
      (cur->type != XML_ELEMENT_NODE));
7740
13.4M
        return(cur);
7741
13.4M
    }
7742
4.30M
    return(NULL);
7743
2.34M
            case XML_DOCUMENT_NODE:
7744
2.34M
            case XML_HTML_DOCUMENT_NODE:
7745
2.34M
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7746
5.83M
      default:
7747
5.83M
    return(NULL);
7748
25.9M
  }
7749
0
  return(NULL);
7750
25.9M
    }
7751
    /*
7752
    * Get the next sibling element node.
7753
    */
7754
19.4M
    switch (cur->type) {
7755
19.4M
  case XML_ELEMENT_NODE:
7756
19.4M
  case XML_TEXT_NODE:
7757
19.4M
  case XML_ENTITY_REF_NODE:
7758
19.4M
  case XML_ENTITY_NODE:
7759
19.4M
  case XML_CDATA_SECTION_NODE:
7760
19.4M
  case XML_PI_NODE:
7761
19.4M
  case XML_COMMENT_NODE:
7762
19.4M
  case XML_XINCLUDE_END:
7763
19.4M
      break;
7764
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7765
0
  default:
7766
0
      return(NULL);
7767
19.4M
    }
7768
19.4M
    if (cur->next != NULL) {
7769
17.1M
  if (cur->next->type == XML_ELEMENT_NODE)
7770
0
      return(cur->next);
7771
17.1M
  cur = cur->next;
7772
26.8M
  do {
7773
26.8M
      cur = cur->next;
7774
26.8M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7775
17.1M
  return(cur);
7776
17.1M
    }
7777
2.31M
    return(NULL);
7778
19.4M
}
7779
7780
#if 0
7781
/**
7782
 * xmlXPathNextDescendantOrSelfElemParent:
7783
 * @ctxt:  the XPath Parser context
7784
 * @cur:  the current node in the traversal
7785
 *
7786
 * Traversal function for the "descendant-or-self" axis.
7787
 * Additionally it returns only nodes which can be parents of
7788
 * element nodes.
7789
 *
7790
 *
7791
 * Returns the next element following that axis
7792
 */
7793
static xmlNodePtr
7794
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7795
               xmlNodePtr contextNode)
7796
{
7797
    if (cur == NULL) {
7798
  if (contextNode == NULL)
7799
      return(NULL);
7800
  switch (contextNode->type) {
7801
      case XML_ELEMENT_NODE:
7802
      case XML_XINCLUDE_START:
7803
      case XML_DOCUMENT_FRAG_NODE:
7804
      case XML_DOCUMENT_NODE:
7805
      case XML_HTML_DOCUMENT_NODE:
7806
    return(contextNode);
7807
      default:
7808
    return(NULL);
7809
  }
7810
  return(NULL);
7811
    } else {
7812
  xmlNodePtr start = cur;
7813
7814
  while (cur != NULL) {
7815
      switch (cur->type) {
7816
    case XML_ELEMENT_NODE:
7817
    /* TODO: OK to have XInclude here? */
7818
    case XML_XINCLUDE_START:
7819
    case XML_DOCUMENT_FRAG_NODE:
7820
        if (cur != start)
7821
      return(cur);
7822
        if (cur->children != NULL) {
7823
      cur = cur->children;
7824
      continue;
7825
        }
7826
        break;
7827
    /* Not sure if we need those here. */
7828
    case XML_DOCUMENT_NODE:
7829
    case XML_HTML_DOCUMENT_NODE:
7830
        if (cur != start)
7831
      return(cur);
7832
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7833
    default:
7834
        break;
7835
      }
7836
7837
next_sibling:
7838
      if ((cur == NULL) || (cur == contextNode))
7839
    return(NULL);
7840
      if (cur->next != NULL) {
7841
    cur = cur->next;
7842
      } else {
7843
    cur = cur->parent;
7844
    goto next_sibling;
7845
      }
7846
  }
7847
    }
7848
    return(NULL);
7849
}
7850
#endif
7851
7852
/**
7853
 * xmlXPathNextDescendant:
7854
 * @ctxt:  the XPath Parser context
7855
 * @cur:  the current node in the traversal
7856
 *
7857
 * Traversal function for the "descendant" direction
7858
 * the descendant axis contains the descendants of the context node in document
7859
 * order; a descendant is a child or a child of a child and so on.
7860
 *
7861
 * Returns the next element following that axis
7862
 */
7863
xmlNodePtr
7864
117M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7865
117M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7866
117M
    if (cur == NULL) {
7867
4.97M
  if (ctxt->context->node == NULL)
7868
0
      return(NULL);
7869
4.97M
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7870
4.97M
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7871
16.9k
      return(NULL);
7872
7873
4.95M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7874
1.37M
      return(ctxt->context->doc->children);
7875
3.58M
        return(ctxt->context->node->children);
7876
4.95M
    }
7877
7878
112M
    if (cur->type == XML_NAMESPACE_DECL)
7879
0
        return(NULL);
7880
112M
    if (cur->children != NULL) {
7881
  /*
7882
   * Do not descend on entities declarations
7883
   */
7884
27.2M
  if (cur->children->type != XML_ENTITY_DECL) {
7885
27.2M
      cur = cur->children;
7886
      /*
7887
       * Skip DTDs
7888
       */
7889
27.2M
      if (cur->type != XML_DTD_NODE)
7890
27.2M
    return(cur);
7891
27.2M
  }
7892
27.2M
    }
7893
7894
84.9M
    if (cur == ctxt->context->node) return(NULL);
7895
7896
84.4M
    while (cur->next != NULL) {
7897
56.8M
  cur = cur->next;
7898
56.8M
  if ((cur->type != XML_ENTITY_DECL) &&
7899
56.8M
      (cur->type != XML_DTD_NODE))
7900
56.8M
      return(cur);
7901
56.8M
    }
7902
7903
29.7M
    do {
7904
29.7M
        cur = cur->parent;
7905
29.7M
  if (cur == NULL) break;
7906
29.7M
  if (cur == ctxt->context->node) return(NULL);
7907
24.7M
  if (cur->next != NULL) {
7908
22.4M
      cur = cur->next;
7909
22.4M
      return(cur);
7910
22.4M
  }
7911
24.7M
    } while (cur != NULL);
7912
0
    return(cur);
7913
27.5M
}
7914
7915
/**
7916
 * xmlXPathNextDescendantOrSelf:
7917
 * @ctxt:  the XPath Parser context
7918
 * @cur:  the current node in the traversal
7919
 *
7920
 * Traversal function for the "descendant-or-self" direction
7921
 * the descendant-or-self axis contains the context node and the descendants
7922
 * of the context node in document order; thus the context node is the first
7923
 * node on the axis, and the first child of the context node is the second node
7924
 * on the axis
7925
 *
7926
 * Returns the next element following that axis
7927
 */
7928
xmlNodePtr
7929
52.9M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930
52.9M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931
52.9M
    if (cur == NULL)
7932
3.06M
        return(ctxt->context->node);
7933
7934
49.9M
    if (ctxt->context->node == NULL)
7935
0
        return(NULL);
7936
49.9M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7937
49.9M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7938
39.8k
        return(NULL);
7939
7940
49.8M
    return(xmlXPathNextDescendant(ctxt, cur));
7941
49.9M
}
7942
7943
/**
7944
 * xmlXPathNextParent:
7945
 * @ctxt:  the XPath Parser context
7946
 * @cur:  the current node in the traversal
7947
 *
7948
 * Traversal function for the "parent" direction
7949
 * The parent axis contains the parent of the context node, if there is one.
7950
 *
7951
 * Returns the next element following that axis
7952
 */
7953
xmlNodePtr
7954
8.86M
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7955
8.86M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7956
    /*
7957
     * the parent of an attribute or namespace node is the element
7958
     * to which the attribute or namespace node is attached
7959
     * Namespace handling !!!
7960
     */
7961
8.86M
    if (cur == NULL) {
7962
4.49M
  if (ctxt->context->node == NULL) return(NULL);
7963
4.49M
  switch (ctxt->context->node->type) {
7964
1.59M
            case XML_ELEMENT_NODE:
7965
3.88M
            case XML_TEXT_NODE:
7966
3.99M
            case XML_CDATA_SECTION_NODE:
7967
3.99M
            case XML_ENTITY_REF_NODE:
7968
3.99M
            case XML_ENTITY_NODE:
7969
4.17M
            case XML_PI_NODE:
7970
4.37M
            case XML_COMMENT_NODE:
7971
4.37M
            case XML_NOTATION_NODE:
7972
4.37M
            case XML_DTD_NODE:
7973
4.37M
      case XML_ELEMENT_DECL:
7974
4.37M
      case XML_ATTRIBUTE_DECL:
7975
4.37M
      case XML_XINCLUDE_START:
7976
4.37M
      case XML_XINCLUDE_END:
7977
4.37M
      case XML_ENTITY_DECL:
7978
4.37M
    if (ctxt->context->node->parent == NULL)
7979
0
        return((xmlNodePtr) ctxt->context->doc);
7980
4.37M
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7981
4.37M
        ((ctxt->context->node->parent->name[0] == ' ') ||
7982
4.17M
         (xmlStrEqual(ctxt->context->node->parent->name,
7983
4.17M
         BAD_CAST "fake node libxslt"))))
7984
0
        return(NULL);
7985
4.37M
    return(ctxt->context->node->parent);
7986
465
            case XML_ATTRIBUTE_NODE: {
7987
465
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7988
7989
465
    return(att->parent);
7990
4.37M
      }
7991
116k
            case XML_DOCUMENT_NODE:
7992
116k
            case XML_DOCUMENT_TYPE_NODE:
7993
116k
            case XML_DOCUMENT_FRAG_NODE:
7994
116k
            case XML_HTML_DOCUMENT_NODE:
7995
116k
                return(NULL);
7996
1.70k
      case XML_NAMESPACE_DECL: {
7997
1.70k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7998
7999
1.70k
    if ((ns->next != NULL) &&
8000
1.70k
        (ns->next->type != XML_NAMESPACE_DECL))
8001
1.70k
        return((xmlNodePtr) ns->next);
8002
0
                return(NULL);
8003
1.70k
      }
8004
4.49M
  }
8005
4.49M
    }
8006
4.37M
    return(NULL);
8007
8.86M
}
8008
8009
/**
8010
 * xmlXPathNextAncestor:
8011
 * @ctxt:  the XPath Parser context
8012
 * @cur:  the current node in the traversal
8013
 *
8014
 * Traversal function for the "ancestor" direction
8015
 * the ancestor axis contains the ancestors of the context node; the ancestors
8016
 * of the context node consist of the parent of context node and the parent's
8017
 * parent and so on; the nodes are ordered in reverse document order; thus the
8018
 * parent is the first node on the axis, and the parent's parent is the second
8019
 * node on the axis
8020
 *
8021
 * Returns the next element following that axis
8022
 */
8023
xmlNodePtr
8024
2.52M
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8025
2.52M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8026
    /*
8027
     * the parent of an attribute or namespace node is the element
8028
     * to which the attribute or namespace node is attached
8029
     * !!!!!!!!!!!!!
8030
     */
8031
2.52M
    if (cur == NULL) {
8032
660k
  if (ctxt->context->node == NULL) return(NULL);
8033
660k
  switch (ctxt->context->node->type) {
8034
200k
            case XML_ELEMENT_NODE:
8035
562k
            case XML_TEXT_NODE:
8036
579k
            case XML_CDATA_SECTION_NODE:
8037
579k
            case XML_ENTITY_REF_NODE:
8038
579k
            case XML_ENTITY_NODE:
8039
610k
            case XML_PI_NODE:
8040
643k
            case XML_COMMENT_NODE:
8041
643k
      case XML_DTD_NODE:
8042
643k
      case XML_ELEMENT_DECL:
8043
643k
      case XML_ATTRIBUTE_DECL:
8044
643k
      case XML_ENTITY_DECL:
8045
643k
            case XML_NOTATION_NODE:
8046
643k
      case XML_XINCLUDE_START:
8047
643k
      case XML_XINCLUDE_END:
8048
643k
    if (ctxt->context->node->parent == NULL)
8049
0
        return((xmlNodePtr) ctxt->context->doc);
8050
643k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8051
643k
        ((ctxt->context->node->parent->name[0] == ' ') ||
8052
612k
         (xmlStrEqual(ctxt->context->node->parent->name,
8053
612k
         BAD_CAST "fake node libxslt"))))
8054
0
        return(NULL);
8055
643k
    return(ctxt->context->node->parent);
8056
1.00k
            case XML_ATTRIBUTE_NODE: {
8057
1.00k
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8058
8059
1.00k
    return(tmp->parent);
8060
643k
      }
8061
15.2k
            case XML_DOCUMENT_NODE:
8062
15.2k
            case XML_DOCUMENT_TYPE_NODE:
8063
15.2k
            case XML_DOCUMENT_FRAG_NODE:
8064
15.2k
            case XML_HTML_DOCUMENT_NODE:
8065
15.2k
                return(NULL);
8066
304
      case XML_NAMESPACE_DECL: {
8067
304
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8068
8069
304
    if ((ns->next != NULL) &&
8070
304
        (ns->next->type != XML_NAMESPACE_DECL))
8071
304
        return((xmlNodePtr) ns->next);
8072
    /* Bad, how did that namespace end up here ? */
8073
0
                return(NULL);
8074
304
      }
8075
660k
  }
8076
0
  return(NULL);
8077
660k
    }
8078
1.86M
    if (cur == ctxt->context->doc->children)
8079
313
  return((xmlNodePtr) ctxt->context->doc);
8080
1.86M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8081
670k
  return(NULL);
8082
1.18M
    switch (cur->type) {
8083
1.17M
  case XML_ELEMENT_NODE:
8084
1.18M
  case XML_TEXT_NODE:
8085
1.18M
  case XML_CDATA_SECTION_NODE:
8086
1.18M
  case XML_ENTITY_REF_NODE:
8087
1.18M
  case XML_ENTITY_NODE:
8088
1.18M
  case XML_PI_NODE:
8089
1.18M
  case XML_COMMENT_NODE:
8090
1.18M
  case XML_NOTATION_NODE:
8091
1.18M
  case XML_DTD_NODE:
8092
1.18M
        case XML_ELEMENT_DECL:
8093
1.18M
        case XML_ATTRIBUTE_DECL:
8094
1.18M
        case XML_ENTITY_DECL:
8095
1.18M
  case XML_XINCLUDE_START:
8096
1.18M
  case XML_XINCLUDE_END:
8097
1.18M
      if (cur->parent == NULL)
8098
0
    return(NULL);
8099
1.18M
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8100
1.18M
    ((cur->parent->name[0] == ' ') ||
8101
548k
     (xmlStrEqual(cur->parent->name,
8102
548k
            BAD_CAST "fake node libxslt"))))
8103
0
    return(NULL);
8104
1.18M
      return(cur->parent);
8105
525
  case XML_ATTRIBUTE_NODE: {
8106
525
      xmlAttrPtr att = (xmlAttrPtr) cur;
8107
8108
525
      return(att->parent);
8109
1.18M
  }
8110
1.23k
  case XML_NAMESPACE_DECL: {
8111
1.23k
      xmlNsPtr ns = (xmlNsPtr) cur;
8112
8113
1.23k
      if ((ns->next != NULL) &&
8114
1.23k
          (ns->next->type != XML_NAMESPACE_DECL))
8115
1.23k
          return((xmlNodePtr) ns->next);
8116
      /* Bad, how did that namespace end up here ? */
8117
0
            return(NULL);
8118
1.23k
  }
8119
0
  case XML_DOCUMENT_NODE:
8120
0
  case XML_DOCUMENT_TYPE_NODE:
8121
0
  case XML_DOCUMENT_FRAG_NODE:
8122
0
  case XML_HTML_DOCUMENT_NODE:
8123
0
      return(NULL);
8124
1.18M
    }
8125
0
    return(NULL);
8126
1.18M
}
8127
8128
/**
8129
 * xmlXPathNextAncestorOrSelf:
8130
 * @ctxt:  the XPath Parser context
8131
 * @cur:  the current node in the traversal
8132
 *
8133
 * Traversal function for the "ancestor-or-self" direction
8134
 * he ancestor-or-self axis contains the context node and ancestors of
8135
 * the context node in reverse document order; thus the context node is
8136
 * the first node on the axis, and the context node's parent the second;
8137
 * parent here is defined the same as with the parent axis.
8138
 *
8139
 * Returns the next element following that axis
8140
 */
8141
xmlNodePtr
8142
127k
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8143
127k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8144
127k
    if (cur == NULL)
8145
26.2k
        return(ctxt->context->node);
8146
100k
    return(xmlXPathNextAncestor(ctxt, cur));
8147
127k
}
8148
8149
/**
8150
 * xmlXPathNextFollowingSibling:
8151
 * @ctxt:  the XPath Parser context
8152
 * @cur:  the current node in the traversal
8153
 *
8154
 * Traversal function for the "following-sibling" direction
8155
 * The following-sibling axis contains the following siblings of the context
8156
 * node in document order.
8157
 *
8158
 * Returns the next element following that axis
8159
 */
8160
xmlNodePtr
8161
37.5k
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8162
37.5k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8163
37.5k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8164
37.5k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8165
1
  return(NULL);
8166
37.5k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8167
0
        return(NULL);
8168
37.5k
    if (cur == NULL)
8169
14.3k
        return(ctxt->context->node->next);
8170
23.2k
    return(cur->next);
8171
37.5k
}
8172
8173
/**
8174
 * xmlXPathNextPrecedingSibling:
8175
 * @ctxt:  the XPath Parser context
8176
 * @cur:  the current node in the traversal
8177
 *
8178
 * Traversal function for the "preceding-sibling" direction
8179
 * The preceding-sibling axis contains the preceding siblings of the context
8180
 * node in reverse document order; the first preceding sibling is first on the
8181
 * axis; the sibling preceding that node is the second on the axis and so on.
8182
 *
8183
 * Returns the next element following that axis
8184
 */
8185
xmlNodePtr
8186
6.74k
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8187
6.74k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8188
6.74k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8189
6.74k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8190
2.57k
  return(NULL);
8191
4.16k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8192
0
        return(NULL);
8193
4.16k
    if (cur == NULL)
8194
983
        return(ctxt->context->node->prev);
8195
3.18k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8196
0
  cur = cur->prev;
8197
0
  if (cur == NULL)
8198
0
      return(ctxt->context->node->prev);
8199
0
    }
8200
3.18k
    return(cur->prev);
8201
3.18k
}
8202
8203
/**
8204
 * xmlXPathNextFollowing:
8205
 * @ctxt:  the XPath Parser context
8206
 * @cur:  the current node in the traversal
8207
 *
8208
 * Traversal function for the "following" direction
8209
 * The following axis contains all nodes in the same document as the context
8210
 * node that are after the context node in document order, excluding any
8211
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8212
 * are ordered in document order
8213
 *
8214
 * Returns the next element following that axis
8215
 */
8216
xmlNodePtr
8217
1.89M
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8218
1.89M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8219
1.89M
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8220
1.89M
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8221
244k
        return(cur->children);
8222
8223
1.64M
    if (cur == NULL) {
8224
123k
        cur = ctxt->context->node;
8225
123k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8226
3.14k
            cur = cur->parent;
8227
120k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8228
213
            xmlNsPtr ns = (xmlNsPtr) cur;
8229
8230
213
            if ((ns->next == NULL) ||
8231
213
                (ns->next->type == XML_NAMESPACE_DECL))
8232
0
                return (NULL);
8233
213
            cur = (xmlNodePtr) ns->next;
8234
213
        }
8235
123k
    }
8236
1.64M
    if (cur == NULL) return(NULL) ; /* ERROR */
8237
1.64M
    if (cur->next != NULL) return(cur->next) ;
8238
550k
    do {
8239
550k
        cur = cur->parent;
8240
550k
        if (cur == NULL) break;
8241
546k
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8242
426k
        if (cur->next != NULL) return(cur->next);
8243
426k
    } while (cur != NULL);
8244
3.45k
    return(cur);
8245
439k
}
8246
8247
/*
8248
 * xmlXPathIsAncestor:
8249
 * @ancestor:  the ancestor node
8250
 * @node:  the current node
8251
 *
8252
 * Check that @ancestor is a @node's ancestor
8253
 *
8254
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8255
 */
8256
static int
8257
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8258
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8259
0
    if (node->type == XML_NAMESPACE_DECL)
8260
0
        return(0);
8261
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8262
0
        return(0);
8263
    /* nodes need to be in the same document */
8264
0
    if (ancestor->doc != node->doc) return(0);
8265
    /* avoid searching if ancestor or node is the root node */
8266
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8267
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8268
0
    while (node->parent != NULL) {
8269
0
        if (node->parent == ancestor)
8270
0
            return(1);
8271
0
  node = node->parent;
8272
0
    }
8273
0
    return(0);
8274
0
}
8275
8276
/**
8277
 * xmlXPathNextPreceding:
8278
 * @ctxt:  the XPath Parser context
8279
 * @cur:  the current node in the traversal
8280
 *
8281
 * Traversal function for the "preceding" direction
8282
 * the preceding axis contains all nodes in the same document as the context
8283
 * node that are before the context node in document order, excluding any
8284
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8285
 * ordered in reverse document order
8286
 *
8287
 * Returns the next element following that axis
8288
 */
8289
xmlNodePtr
8290
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8291
0
{
8292
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8293
0
    if (cur == NULL) {
8294
0
        cur = ctxt->context->node;
8295
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8296
0
            cur = cur->parent;
8297
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8298
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8299
8300
0
            if ((ns->next == NULL) ||
8301
0
                (ns->next->type == XML_NAMESPACE_DECL))
8302
0
                return (NULL);
8303
0
            cur = (xmlNodePtr) ns->next;
8304
0
        }
8305
0
    }
8306
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8307
0
  return (NULL);
8308
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8309
0
  cur = cur->prev;
8310
0
    do {
8311
0
        if (cur->prev != NULL) {
8312
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8313
0
            return (cur);
8314
0
        }
8315
8316
0
        cur = cur->parent;
8317
0
        if (cur == NULL)
8318
0
            return (NULL);
8319
0
        if (cur == ctxt->context->doc->children)
8320
0
            return (NULL);
8321
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8322
0
    return (cur);
8323
0
}
8324
8325
/**
8326
 * xmlXPathNextPrecedingInternal:
8327
 * @ctxt:  the XPath Parser context
8328
 * @cur:  the current node in the traversal
8329
 *
8330
 * Traversal function for the "preceding" direction
8331
 * the preceding axis contains all nodes in the same document as the context
8332
 * node that are before the context node in document order, excluding any
8333
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8334
 * ordered in reverse document order
8335
 * This is a faster implementation but internal only since it requires a
8336
 * state kept in the parser context: ctxt->ancestor.
8337
 *
8338
 * Returns the next element following that axis
8339
 */
8340
static xmlNodePtr
8341
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8342
                              xmlNodePtr cur)
8343
699k
{
8344
699k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8345
699k
    if (cur == NULL) {
8346
43.1k
        cur = ctxt->context->node;
8347
43.1k
        if (cur == NULL)
8348
0
            return (NULL);
8349
43.1k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8350
266
            cur = cur->parent;
8351
42.8k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8352
326
            xmlNsPtr ns = (xmlNsPtr) cur;
8353
8354
326
            if ((ns->next == NULL) ||
8355
326
                (ns->next->type == XML_NAMESPACE_DECL))
8356
0
                return (NULL);
8357
326
            cur = (xmlNodePtr) ns->next;
8358
326
        }
8359
43.1k
        ctxt->ancestor = cur->parent;
8360
43.1k
    }
8361
699k
    if (cur->type == XML_NAMESPACE_DECL)
8362
0
        return(NULL);
8363
699k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8364
0
  cur = cur->prev;
8365
799k
    while (cur->prev == NULL) {
8366
291k
        cur = cur->parent;
8367
291k
        if (cur == NULL)
8368
43.1k
            return (NULL);
8369
248k
        if (cur == ctxt->context->doc->children)
8370
0
            return (NULL);
8371
248k
        if (cur != ctxt->ancestor)
8372
148k
            return (cur);
8373
99.9k
        ctxt->ancestor = cur->parent;
8374
99.9k
    }
8375
508k
    cur = cur->prev;
8376
656k
    while (cur->last != NULL)
8377
148k
        cur = cur->last;
8378
508k
    return (cur);
8379
699k
}
8380
8381
/**
8382
 * xmlXPathNextNamespace:
8383
 * @ctxt:  the XPath Parser context
8384
 * @cur:  the current attribute in the traversal
8385
 *
8386
 * Traversal function for the "namespace" direction
8387
 * the namespace axis contains the namespace nodes of the context node;
8388
 * the order of nodes on this axis is implementation-defined; the axis will
8389
 * be empty unless the context node is an element
8390
 *
8391
 * We keep the XML namespace node at the end of the list.
8392
 *
8393
 * Returns the next element following that axis
8394
 */
8395
xmlNodePtr
8396
1.57M
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8397
1.57M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8398
1.57M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8399
1.40M
    if (cur == NULL) {
8400
417k
        if (ctxt->context->tmpNsList != NULL)
8401
42.3k
      xmlFree(ctxt->context->tmpNsList);
8402
417k
  ctxt->context->tmpNsList =
8403
417k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8404
417k
  ctxt->context->tmpNsNr = 0;
8405
417k
  if (ctxt->context->tmpNsList != NULL) {
8406
1.14M
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8407
727k
    ctxt->context->tmpNsNr++;
8408
727k
      }
8409
417k
  }
8410
417k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8411
417k
    }
8412
985k
    if (ctxt->context->tmpNsNr > 0) {
8413
626k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8414
626k
    } else {
8415
358k
  if (ctxt->context->tmpNsList != NULL)
8416
358k
      xmlFree(ctxt->context->tmpNsList);
8417
358k
  ctxt->context->tmpNsList = NULL;
8418
358k
  return(NULL);
8419
358k
    }
8420
985k
}
8421
8422
/**
8423
 * xmlXPathNextAttribute:
8424
 * @ctxt:  the XPath Parser context
8425
 * @cur:  the current attribute in the traversal
8426
 *
8427
 * Traversal function for the "attribute" direction
8428
 * TODO: support DTD inherited default attributes
8429
 *
8430
 * Returns the next element following that axis
8431
 */
8432
xmlNodePtr
8433
14.6M
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8434
14.6M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8435
14.6M
    if (ctxt->context->node == NULL)
8436
0
  return(NULL);
8437
14.6M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8438
7.96M
  return(NULL);
8439
6.72M
    if (cur == NULL) {
8440
3.84M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8441
0
      return(NULL);
8442
3.84M
        return((xmlNodePtr)ctxt->context->node->properties);
8443
3.84M
    }
8444
2.88M
    return((xmlNodePtr)cur->next);
8445
6.72M
}
8446
8447
/************************************************************************
8448
 *                  *
8449
 *    NodeTest Functions          *
8450
 *                  *
8451
 ************************************************************************/
8452
8453
#define IS_FUNCTION     200
8454
8455
8456
/************************************************************************
8457
 *                  *
8458
 *    Implicit tree core function library     *
8459
 *                  *
8460
 ************************************************************************/
8461
8462
/**
8463
 * xmlXPathRoot:
8464
 * @ctxt:  the XPath Parser context
8465
 *
8466
 * Initialize the context to the root of the document
8467
 */
8468
void
8469
5.23M
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8470
5.23M
    if ((ctxt == NULL) || (ctxt->context == NULL))
8471
0
  return;
8472
5.23M
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8473
5.23M
  (xmlNodePtr) ctxt->context->doc));
8474
5.23M
}
8475
8476
/************************************************************************
8477
 *                  *
8478
 *    The explicit core function library      *
8479
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8480
 *                  *
8481
 ************************************************************************/
8482
8483
8484
/**
8485
 * xmlXPathLastFunction:
8486
 * @ctxt:  the XPath Parser context
8487
 * @nargs:  the number of arguments
8488
 *
8489
 * Implement the last() XPath function
8490
 *    number last()
8491
 * The last function returns the number of nodes in the context node list.
8492
 */
8493
void
8494
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8495
0
    CHECK_ARITY(0);
8496
0
    if (ctxt->context->contextSize >= 0) {
8497
0
  valuePush(ctxt,
8498
0
      xmlXPathCacheNewFloat(ctxt->context,
8499
0
    (double) ctxt->context->contextSize));
8500
#ifdef DEBUG_EXPR
8501
  xmlGenericError(xmlGenericErrorContext,
8502
    "last() : %d\n", ctxt->context->contextSize);
8503
#endif
8504
0
    } else {
8505
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8506
0
    }
8507
0
}
8508
8509
/**
8510
 * xmlXPathPositionFunction:
8511
 * @ctxt:  the XPath Parser context
8512
 * @nargs:  the number of arguments
8513
 *
8514
 * Implement the position() XPath function
8515
 *    number position()
8516
 * The position function returns the position of the context node in the
8517
 * context node list. The first position is 1, and so the last position
8518
 * will be equal to last().
8519
 */
8520
void
8521
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522
0
    CHECK_ARITY(0);
8523
0
    if (ctxt->context->proximityPosition >= 0) {
8524
0
  valuePush(ctxt,
8525
0
        xmlXPathCacheNewFloat(ctxt->context,
8526
0
    (double) ctxt->context->proximityPosition));
8527
#ifdef DEBUG_EXPR
8528
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8529
    ctxt->context->proximityPosition);
8530
#endif
8531
0
    } else {
8532
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8533
0
    }
8534
0
}
8535
8536
/**
8537
 * xmlXPathCountFunction:
8538
 * @ctxt:  the XPath Parser context
8539
 * @nargs:  the number of arguments
8540
 *
8541
 * Implement the count() XPath function
8542
 *    number count(node-set)
8543
 */
8544
void
8545
14
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8546
14
    xmlXPathObjectPtr cur;
8547
8548
40
    CHECK_ARITY(1);
8549
40
    if ((ctxt->value == NULL) ||
8550
13
  ((ctxt->value->type != XPATH_NODESET) &&
8551
13
   (ctxt->value->type != XPATH_XSLT_TREE)))
8552
12
  XP_ERROR(XPATH_INVALID_TYPE);
8553
12
    cur = valuePop(ctxt);
8554
8555
12
    if ((cur == NULL) || (cur->nodesetval == NULL))
8556
1
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8557
11
    else
8558
11
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8559
11
      (double) cur->nodesetval->nodeNr));
8560
12
    xmlXPathReleaseObject(ctxt->context, cur);
8561
12
}
8562
8563
/**
8564
 * xmlXPathGetElementsByIds:
8565
 * @doc:  the document
8566
 * @ids:  a whitespace separated list of IDs
8567
 *
8568
 * Selects elements by their unique ID.
8569
 *
8570
 * Returns a node-set of selected elements.
8571
 */
8572
static xmlNodeSetPtr
8573
186k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8574
186k
    xmlNodeSetPtr ret;
8575
186k
    const xmlChar *cur = ids;
8576
186k
    xmlChar *ID;
8577
186k
    xmlAttrPtr attr;
8578
186k
    xmlNodePtr elem = NULL;
8579
8580
186k
    if (ids == NULL) return(NULL);
8581
8582
186k
    ret = xmlXPathNodeSetCreate(NULL);
8583
186k
    if (ret == NULL)
8584
0
        return(ret);
8585
8586
478k
    while (IS_BLANK_CH(*cur)) cur++;
8587
402k
    while (*cur != 0) {
8588
1.37M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8589
1.15M
      cur++;
8590
8591
215k
        ID = xmlStrndup(ids, cur - ids);
8592
215k
  if (ID != NULL) {
8593
      /*
8594
       * We used to check the fact that the value passed
8595
       * was an NCName, but this generated much troubles for
8596
       * me and Aleksey Sanin, people blatantly violated that
8597
       * constraint, like Visa3D spec.
8598
       * if (xmlValidateNCName(ID, 1) == 0)
8599
       */
8600
215k
      attr = xmlGetID(doc, ID);
8601
215k
      if (attr != NULL) {
8602
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8603
0
        elem = attr->parent;
8604
0
    else if (attr->type == XML_ELEMENT_NODE)
8605
0
        elem = (xmlNodePtr) attr;
8606
0
    else
8607
0
        elem = NULL;
8608
                /* TODO: Check memory error. */
8609
0
    if (elem != NULL)
8610
0
        xmlXPathNodeSetAdd(ret, elem);
8611
0
      }
8612
215k
      xmlFree(ID);
8613
215k
  }
8614
8615
881k
  while (IS_BLANK_CH(*cur)) cur++;
8616
215k
  ids = cur;
8617
215k
    }
8618
186k
    return(ret);
8619
186k
}
8620
8621
/**
8622
 * xmlXPathIdFunction:
8623
 * @ctxt:  the XPath Parser context
8624
 * @nargs:  the number of arguments
8625
 *
8626
 * Implement the id() XPath function
8627
 *    node-set id(object)
8628
 * The id function selects elements by their unique ID
8629
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8630
 * then the result is the union of the result of applying id to the
8631
 * string value of each of the nodes in the argument node-set. When the
8632
 * argument to id is of any other type, the argument is converted to a
8633
 * string as if by a call to the string function; the string is split
8634
 * into a whitespace-separated list of tokens (whitespace is any sequence
8635
 * of characters matching the production S); the result is a node-set
8636
 * containing the elements in the same document as the context node that
8637
 * have a unique ID equal to any of the tokens in the list.
8638
 */
8639
void
8640
81.0k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8641
81.0k
    xmlChar *tokens;
8642
81.0k
    xmlNodeSetPtr ret;
8643
81.0k
    xmlXPathObjectPtr obj;
8644
8645
243k
    CHECK_ARITY(1);
8646
243k
    obj = valuePop(ctxt);
8647
243k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8648
81.0k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8649
18.2k
  xmlNodeSetPtr ns;
8650
18.2k
  int i;
8651
8652
        /* TODO: Check memory error. */
8653
18.2k
  ret = xmlXPathNodeSetCreate(NULL);
8654
8655
18.2k
  if (obj->nodesetval != NULL) {
8656
133k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8657
124k
    tokens =
8658
124k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8659
124k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8660
                /* TODO: Check memory error. */
8661
124k
    ret = xmlXPathNodeSetMerge(ret, ns);
8662
124k
    xmlXPathFreeNodeSet(ns);
8663
124k
    if (tokens != NULL)
8664
124k
        xmlFree(tokens);
8665
124k
      }
8666
9.33k
  }
8667
18.2k
  xmlXPathReleaseObject(ctxt->context, obj);
8668
18.2k
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8669
18.2k
  return;
8670
18.2k
    }
8671
62.8k
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8672
62.8k
    if (obj == NULL) return;
8673
62.8k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8674
62.8k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8675
62.8k
    xmlXPathReleaseObject(ctxt->context, obj);
8676
62.8k
    return;
8677
62.8k
}
8678
8679
/**
8680
 * xmlXPathLocalNameFunction:
8681
 * @ctxt:  the XPath Parser context
8682
 * @nargs:  the number of arguments
8683
 *
8684
 * Implement the local-name() XPath function
8685
 *    string local-name(node-set?)
8686
 * The local-name function returns a string containing the local part
8687
 * of the name of the node in the argument node-set that is first in
8688
 * document order. If the node-set is empty or the first node has no
8689
 * name, an empty string is returned. If the argument is omitted it
8690
 * defaults to the context node.
8691
 */
8692
void
8693
19.0k
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8694
19.0k
    xmlXPathObjectPtr cur;
8695
8696
19.0k
    if (ctxt == NULL) return;
8697
8698
19.0k
    if (nargs == 0) {
8699
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8700
0
      ctxt->context->node));
8701
0
  nargs = 1;
8702
0
    }
8703
8704
57.0k
    CHECK_ARITY(1);
8705
57.0k
    if ((ctxt->value == NULL) ||
8706
19.0k
  ((ctxt->value->type != XPATH_NODESET) &&
8707
19.0k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8708
19.0k
  XP_ERROR(XPATH_INVALID_TYPE);
8709
19.0k
    cur = valuePop(ctxt);
8710
8711
19.0k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8712
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713
19.0k
    } else {
8714
19.0k
  int i = 0; /* Should be first in document order !!!!! */
8715
19.0k
  switch (cur->nodesetval->nodeTab[i]->type) {
8716
0
  case XML_ELEMENT_NODE:
8717
0
  case XML_ATTRIBUTE_NODE:
8718
254
  case XML_PI_NODE:
8719
254
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8720
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8721
254
      else
8722
254
    valuePush(ctxt,
8723
254
          xmlXPathCacheNewString(ctxt->context,
8724
254
      cur->nodesetval->nodeTab[i]->name));
8725
254
      break;
8726
13.3k
  case XML_NAMESPACE_DECL:
8727
13.3k
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8728
13.3k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8729
13.3k
      break;
8730
5.43k
  default:
8731
5.43k
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8732
19.0k
  }
8733
19.0k
    }
8734
19.0k
    xmlXPathReleaseObject(ctxt->context, cur);
8735
19.0k
}
8736
8737
/**
8738
 * xmlXPathNamespaceURIFunction:
8739
 * @ctxt:  the XPath Parser context
8740
 * @nargs:  the number of arguments
8741
 *
8742
 * Implement the namespace-uri() XPath function
8743
 *    string namespace-uri(node-set?)
8744
 * The namespace-uri function returns a string containing the
8745
 * namespace URI of the expanded name of the node in the argument
8746
 * node-set that is first in document order. If the node-set is empty,
8747
 * the first node has no name, or the expanded name has no namespace
8748
 * URI, an empty string is returned. If the argument is omitted it
8749
 * defaults to the context node.
8750
 */
8751
void
8752
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8753
0
    xmlXPathObjectPtr cur;
8754
8755
0
    if (ctxt == NULL) return;
8756
8757
0
    if (nargs == 0) {
8758
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8759
0
      ctxt->context->node));
8760
0
  nargs = 1;
8761
0
    }
8762
0
    CHECK_ARITY(1);
8763
0
    if ((ctxt->value == NULL) ||
8764
0
  ((ctxt->value->type != XPATH_NODESET) &&
8765
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8766
0
  XP_ERROR(XPATH_INVALID_TYPE);
8767
0
    cur = valuePop(ctxt);
8768
8769
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8770
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8771
0
    } else {
8772
0
  int i = 0; /* Should be first in document order !!!!! */
8773
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8774
0
  case XML_ELEMENT_NODE:
8775
0
  case XML_ATTRIBUTE_NODE:
8776
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8777
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8778
0
      else
8779
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8780
0
        cur->nodesetval->nodeTab[i]->ns->href));
8781
0
      break;
8782
0
  default:
8783
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8784
0
  }
8785
0
    }
8786
0
    xmlXPathReleaseObject(ctxt->context, cur);
8787
0
}
8788
8789
/**
8790
 * xmlXPathNameFunction:
8791
 * @ctxt:  the XPath Parser context
8792
 * @nargs:  the number of arguments
8793
 *
8794
 * Implement the name() XPath function
8795
 *    string name(node-set?)
8796
 * The name function returns a string containing a QName representing
8797
 * the name of the node in the argument node-set that is first in document
8798
 * order. The QName must represent the name with respect to the namespace
8799
 * declarations in effect on the node whose name is being represented.
8800
 * Typically, this will be the form in which the name occurred in the XML
8801
 * source. This need not be the case if there are namespace declarations
8802
 * in effect on the node that associate multiple prefixes with the same
8803
 * namespace. However, an implementation may include information about
8804
 * the original prefix in its representation of nodes; in this case, an
8805
 * implementation can ensure that the returned string is always the same
8806
 * as the QName used in the XML source. If the argument it omitted it
8807
 * defaults to the context node.
8808
 * Libxml keep the original prefix so the "real qualified name" used is
8809
 * returned.
8810
 */
8811
static void
8812
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8813
73.4k
{
8814
73.4k
    xmlXPathObjectPtr cur;
8815
8816
73.4k
    if (nargs == 0) {
8817
50.5k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8818
50.5k
      ctxt->context->node));
8819
50.5k
        nargs = 1;
8820
50.5k
    }
8821
8822
220k
    CHECK_ARITY(1);
8823
220k
    if ((ctxt->value == NULL) ||
8824
73.4k
        ((ctxt->value->type != XPATH_NODESET) &&
8825
73.4k
         (ctxt->value->type != XPATH_XSLT_TREE)))
8826
73.4k
        XP_ERROR(XPATH_INVALID_TYPE);
8827
73.4k
    cur = valuePop(ctxt);
8828
8829
73.4k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8830
20.0k
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8831
53.3k
    } else {
8832
53.3k
        int i = 0;              /* Should be first in document order !!!!! */
8833
8834
53.3k
        switch (cur->nodesetval->nodeTab[i]->type) {
8835
34.3k
            case XML_ELEMENT_NODE:
8836
34.3k
            case XML_ATTRIBUTE_NODE:
8837
34.3k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8838
0
        valuePush(ctxt,
8839
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8840
34.3k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8841
34.3k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8842
13.9k
        valuePush(ctxt,
8843
13.9k
            xmlXPathCacheNewString(ctxt->context,
8844
13.9k
          cur->nodesetval->nodeTab[i]->name));
8845
20.4k
    } else {
8846
20.4k
        xmlChar *fullname;
8847
8848
20.4k
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8849
20.4k
             cur->nodesetval->nodeTab[i]->ns->prefix,
8850
20.4k
             NULL, 0);
8851
20.4k
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8852
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8853
20.4k
        if (fullname == NULL) {
8854
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8855
0
        }
8856
20.4k
        valuePush(ctxt, xmlXPathCacheWrapString(
8857
20.4k
      ctxt->context, fullname));
8858
20.4k
                }
8859
34.3k
                break;
8860
34.3k
            default:
8861
19.0k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8862
19.0k
        cur->nodesetval->nodeTab[i]));
8863
19.0k
                xmlXPathLocalNameFunction(ctxt, 1);
8864
53.3k
        }
8865
53.3k
    }
8866
73.4k
    xmlXPathReleaseObject(ctxt->context, cur);
8867
73.4k
}
8868
8869
8870
/**
8871
 * xmlXPathStringFunction:
8872
 * @ctxt:  the XPath Parser context
8873
 * @nargs:  the number of arguments
8874
 *
8875
 * Implement the string() XPath function
8876
 *    string string(object?)
8877
 * The string function converts an object to a string as follows:
8878
 *    - A node-set is converted to a string by returning the value of
8879
 *      the node in the node-set that is first in document order.
8880
 *      If the node-set is empty, an empty string is returned.
8881
 *    - A number is converted to a string as follows
8882
 *      + NaN is converted to the string NaN
8883
 *      + positive zero is converted to the string 0
8884
 *      + negative zero is converted to the string 0
8885
 *      + positive infinity is converted to the string Infinity
8886
 *      + negative infinity is converted to the string -Infinity
8887
 *      + if the number is an integer, the number is represented in
8888
 *        decimal form as a Number with no decimal point and no leading
8889
 *        zeros, preceded by a minus sign (-) if the number is negative
8890
 *      + otherwise, the number is represented in decimal form as a
8891
 *        Number including a decimal point with at least one digit
8892
 *        before the decimal point and at least one digit after the
8893
 *        decimal point, preceded by a minus sign (-) if the number
8894
 *        is negative; there must be no leading zeros before the decimal
8895
 *        point apart possibly from the one required digit immediately
8896
 *        before the decimal point; beyond the one required digit
8897
 *        after the decimal point there must be as many, but only as
8898
 *        many, more digits as are needed to uniquely distinguish the
8899
 *        number from all other IEEE 754 numeric values.
8900
 *    - The boolean false value is converted to the string false.
8901
 *      The boolean true value is converted to the string true.
8902
 *
8903
 * If the argument is omitted, it defaults to a node-set with the
8904
 * context node as its only member.
8905
 */
8906
void
8907
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8908
0
    xmlXPathObjectPtr cur;
8909
8910
0
    if (ctxt == NULL) return;
8911
0
    if (nargs == 0) {
8912
0
    valuePush(ctxt,
8913
0
  xmlXPathCacheWrapString(ctxt->context,
8914
0
      xmlXPathCastNodeToString(ctxt->context->node)));
8915
0
  return;
8916
0
    }
8917
8918
0
    CHECK_ARITY(1);
8919
0
    cur = valuePop(ctxt);
8920
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8921
0
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8922
0
}
8923
8924
/**
8925
 * xmlXPathStringLengthFunction:
8926
 * @ctxt:  the XPath Parser context
8927
 * @nargs:  the number of arguments
8928
 *
8929
 * Implement the string-length() XPath function
8930
 *    number string-length(string?)
8931
 * The string-length returns the number of characters in the string
8932
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8933
 * the context node converted to a string, in other words the value
8934
 * of the context node.
8935
 */
8936
void
8937
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8938
0
    xmlXPathObjectPtr cur;
8939
8940
0
    if (nargs == 0) {
8941
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8942
0
      return;
8943
0
  if (ctxt->context->node == NULL) {
8944
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8945
0
  } else {
8946
0
      xmlChar *content;
8947
8948
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8949
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8950
0
    xmlUTF8Strlen(content)));
8951
0
      xmlFree(content);
8952
0
  }
8953
0
  return;
8954
0
    }
8955
0
    CHECK_ARITY(1);
8956
0
    CAST_TO_STRING;
8957
0
    CHECK_TYPE(XPATH_STRING);
8958
0
    cur = valuePop(ctxt);
8959
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8960
0
  xmlUTF8Strlen(cur->stringval)));
8961
0
    xmlXPathReleaseObject(ctxt->context, cur);
8962
0
}
8963
8964
/**
8965
 * xmlXPathConcatFunction:
8966
 * @ctxt:  the XPath Parser context
8967
 * @nargs:  the number of arguments
8968
 *
8969
 * Implement the concat() XPath function
8970
 *    string concat(string, string, string*)
8971
 * The concat function returns the concatenation of its arguments.
8972
 */
8973
void
8974
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975
0
    xmlXPathObjectPtr cur, newobj;
8976
0
    xmlChar *tmp;
8977
8978
0
    if (ctxt == NULL) return;
8979
0
    if (nargs < 2) {
8980
0
  CHECK_ARITY(2);
8981
0
    }
8982
8983
0
    CAST_TO_STRING;
8984
0
    cur = valuePop(ctxt);
8985
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8986
0
  xmlXPathReleaseObject(ctxt->context, cur);
8987
0
  return;
8988
0
    }
8989
0
    nargs--;
8990
8991
0
    while (nargs > 0) {
8992
0
  CAST_TO_STRING;
8993
0
  newobj = valuePop(ctxt);
8994
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8995
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8996
0
      xmlXPathReleaseObject(ctxt->context, cur);
8997
0
      XP_ERROR(XPATH_INVALID_TYPE);
8998
0
  }
8999
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
9000
0
  newobj->stringval = cur->stringval;
9001
0
  cur->stringval = tmp;
9002
0
  xmlXPathReleaseObject(ctxt->context, newobj);
9003
0
  nargs--;
9004
0
    }
9005
0
    valuePush(ctxt, cur);
9006
0
}
9007
9008
/**
9009
 * xmlXPathContainsFunction:
9010
 * @ctxt:  the XPath Parser context
9011
 * @nargs:  the number of arguments
9012
 *
9013
 * Implement the contains() XPath function
9014
 *    boolean contains(string, string)
9015
 * The contains function returns true if the first argument string
9016
 * contains the second argument string, and otherwise returns false.
9017
 */
9018
void
9019
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020
0
    xmlXPathObjectPtr hay, needle;
9021
9022
0
    CHECK_ARITY(2);
9023
0
    CAST_TO_STRING;
9024
0
    CHECK_TYPE(XPATH_STRING);
9025
0
    needle = valuePop(ctxt);
9026
0
    CAST_TO_STRING;
9027
0
    hay = valuePop(ctxt);
9028
9029
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9030
0
  xmlXPathReleaseObject(ctxt->context, hay);
9031
0
  xmlXPathReleaseObject(ctxt->context, needle);
9032
0
  XP_ERROR(XPATH_INVALID_TYPE);
9033
0
    }
9034
0
    if (xmlStrstr(hay->stringval, needle->stringval))
9035
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9036
0
    else
9037
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038
0
    xmlXPathReleaseObject(ctxt->context, hay);
9039
0
    xmlXPathReleaseObject(ctxt->context, needle);
9040
0
}
9041
9042
/**
9043
 * xmlXPathStartsWithFunction:
9044
 * @ctxt:  the XPath Parser context
9045
 * @nargs:  the number of arguments
9046
 *
9047
 * Implement the starts-with() XPath function
9048
 *    boolean starts-with(string, string)
9049
 * The starts-with function returns true if the first argument string
9050
 * starts with the second argument string, and otherwise returns false.
9051
 */
9052
void
9053
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9054
0
    xmlXPathObjectPtr hay, needle;
9055
0
    int n;
9056
9057
0
    CHECK_ARITY(2);
9058
0
    CAST_TO_STRING;
9059
0
    CHECK_TYPE(XPATH_STRING);
9060
0
    needle = valuePop(ctxt);
9061
0
    CAST_TO_STRING;
9062
0
    hay = valuePop(ctxt);
9063
9064
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9065
0
  xmlXPathReleaseObject(ctxt->context, hay);
9066
0
  xmlXPathReleaseObject(ctxt->context, needle);
9067
0
  XP_ERROR(XPATH_INVALID_TYPE);
9068
0
    }
9069
0
    n = xmlStrlen(needle->stringval);
9070
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9071
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9072
0
    else
9073
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9074
0
    xmlXPathReleaseObject(ctxt->context, hay);
9075
0
    xmlXPathReleaseObject(ctxt->context, needle);
9076
0
}
9077
9078
/**
9079
 * xmlXPathSubstringFunction:
9080
 * @ctxt:  the XPath Parser context
9081
 * @nargs:  the number of arguments
9082
 *
9083
 * Implement the substring() XPath function
9084
 *    string substring(string, number, number?)
9085
 * The substring function returns the substring of the first argument
9086
 * starting at the position specified in the second argument with
9087
 * length specified in the third argument. For example,
9088
 * substring("12345",2,3) returns "234". If the third argument is not
9089
 * specified, it returns the substring starting at the position specified
9090
 * in the second argument and continuing to the end of the string. For
9091
 * example, substring("12345",2) returns "2345".  More precisely, each
9092
 * character in the string (see [3.6 Strings]) is considered to have a
9093
 * numeric position: the position of the first character is 1, the position
9094
 * of the second character is 2 and so on. The returned substring contains
9095
 * those characters for which the position of the character is greater than
9096
 * or equal to the second argument and, if the third argument is specified,
9097
 * less than the sum of the second and third arguments; the comparisons
9098
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9099
 *  - substring("12345", 1.5, 2.6) returns "234"
9100
 *  - substring("12345", 0, 3) returns "12"
9101
 *  - substring("12345", 0 div 0, 3) returns ""
9102
 *  - substring("12345", 1, 0 div 0) returns ""
9103
 *  - substring("12345", -42, 1 div 0) returns "12345"
9104
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9105
 */
9106
void
9107
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9108
0
    xmlXPathObjectPtr str, start, len;
9109
0
    double le=0, in;
9110
0
    int i = 1, j = INT_MAX;
9111
9112
0
    if (nargs < 2) {
9113
0
  CHECK_ARITY(2);
9114
0
    }
9115
0
    if (nargs > 3) {
9116
0
  CHECK_ARITY(3);
9117
0
    }
9118
    /*
9119
     * take care of possible last (position) argument
9120
    */
9121
0
    if (nargs == 3) {
9122
0
  CAST_TO_NUMBER;
9123
0
  CHECK_TYPE(XPATH_NUMBER);
9124
0
  len = valuePop(ctxt);
9125
0
  le = len->floatval;
9126
0
  xmlXPathReleaseObject(ctxt->context, len);
9127
0
    }
9128
9129
0
    CAST_TO_NUMBER;
9130
0
    CHECK_TYPE(XPATH_NUMBER);
9131
0
    start = valuePop(ctxt);
9132
0
    in = start->floatval;
9133
0
    xmlXPathReleaseObject(ctxt->context, start);
9134
0
    CAST_TO_STRING;
9135
0
    CHECK_TYPE(XPATH_STRING);
9136
0
    str = valuePop(ctxt);
9137
9138
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9139
0
        i = INT_MAX;
9140
0
    } else if (in >= 1.0) {
9141
0
        i = (int)in;
9142
0
        if (in - floor(in) >= 0.5)
9143
0
            i += 1;
9144
0
    }
9145
9146
0
    if (nargs == 3) {
9147
0
        double rin, rle, end;
9148
9149
0
        rin = floor(in);
9150
0
        if (in - rin >= 0.5)
9151
0
            rin += 1.0;
9152
9153
0
        rle = floor(le);
9154
0
        if (le - rle >= 0.5)
9155
0
            rle += 1.0;
9156
9157
0
        end = rin + rle;
9158
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9159
0
            j = 1;
9160
0
        } else if (end < INT_MAX) {
9161
0
            j = (int)end;
9162
0
        }
9163
0
    }
9164
9165
0
    if (i < j) {
9166
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9167
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9168
0
  xmlFree(ret);
9169
0
    } else {
9170
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9171
0
    }
9172
9173
0
    xmlXPathReleaseObject(ctxt->context, str);
9174
0
}
9175
9176
/**
9177
 * xmlXPathSubstringBeforeFunction:
9178
 * @ctxt:  the XPath Parser context
9179
 * @nargs:  the number of arguments
9180
 *
9181
 * Implement the substring-before() XPath function
9182
 *    string substring-before(string, string)
9183
 * The substring-before function returns the substring of the first
9184
 * argument string that precedes the first occurrence of the second
9185
 * argument string in the first argument string, or the empty string
9186
 * if the first argument string does not contain the second argument
9187
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9188
 */
9189
void
9190
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9191
0
  xmlXPathObjectPtr str;
9192
0
  xmlXPathObjectPtr find;
9193
0
  xmlBufPtr target;
9194
0
  const xmlChar *point;
9195
0
  int offset;
9196
9197
0
  CHECK_ARITY(2);
9198
0
  CAST_TO_STRING;
9199
0
  find = valuePop(ctxt);
9200
0
  CAST_TO_STRING;
9201
0
  str = valuePop(ctxt);
9202
9203
0
  target = xmlBufCreate();
9204
0
  if (target) {
9205
0
    point = xmlStrstr(str->stringval, find->stringval);
9206
0
    if (point) {
9207
0
      offset = point - str->stringval;
9208
0
      xmlBufAdd(target, str->stringval, offset);
9209
0
    }
9210
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211
0
  xmlBufContent(target)));
9212
0
    xmlBufFree(target);
9213
0
  }
9214
0
  xmlXPathReleaseObject(ctxt->context, str);
9215
0
  xmlXPathReleaseObject(ctxt->context, find);
9216
0
}
9217
9218
/**
9219
 * xmlXPathSubstringAfterFunction:
9220
 * @ctxt:  the XPath Parser context
9221
 * @nargs:  the number of arguments
9222
 *
9223
 * Implement the substring-after() XPath function
9224
 *    string substring-after(string, string)
9225
 * The substring-after function returns the substring of the first
9226
 * argument string that follows the first occurrence of the second
9227
 * argument string in the first argument string, or the empty stringi
9228
 * if the first argument string does not contain the second argument
9229
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9230
 * and substring-after("1999/04/01","19") returns 99/04/01.
9231
 */
9232
void
9233
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234
0
  xmlXPathObjectPtr str;
9235
0
  xmlXPathObjectPtr find;
9236
0
  xmlBufPtr target;
9237
0
  const xmlChar *point;
9238
0
  int offset;
9239
9240
0
  CHECK_ARITY(2);
9241
0
  CAST_TO_STRING;
9242
0
  find = valuePop(ctxt);
9243
0
  CAST_TO_STRING;
9244
0
  str = valuePop(ctxt);
9245
9246
0
  target = xmlBufCreate();
9247
0
  if (target) {
9248
0
    point = xmlStrstr(str->stringval, find->stringval);
9249
0
    if (point) {
9250
0
      offset = point - str->stringval + xmlStrlen(find->stringval);
9251
0
      xmlBufAdd(target, &str->stringval[offset],
9252
0
       xmlStrlen(str->stringval) - offset);
9253
0
    }
9254
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9255
0
  xmlBufContent(target)));
9256
0
    xmlBufFree(target);
9257
0
  }
9258
0
  xmlXPathReleaseObject(ctxt->context, str);
9259
0
  xmlXPathReleaseObject(ctxt->context, find);
9260
0
}
9261
9262
/**
9263
 * xmlXPathNormalizeFunction:
9264
 * @ctxt:  the XPath Parser context
9265
 * @nargs:  the number of arguments
9266
 *
9267
 * Implement the normalize-space() XPath function
9268
 *    string normalize-space(string?)
9269
 * The normalize-space function returns the argument string with white
9270
 * space normalized by stripping leading and trailing whitespace
9271
 * and replacing sequences of whitespace characters by a single
9272
 * space. Whitespace characters are the same allowed by the S production
9273
 * in XML. If the argument is omitted, it defaults to the context
9274
 * node converted to a string, in other words the value of the context node.
9275
 */
9276
void
9277
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9278
0
    xmlChar *source, *target;
9279
0
    int blank;
9280
9281
0
    if (ctxt == NULL) return;
9282
0
    if (nargs == 0) {
9283
        /* Use current context node */
9284
0
        valuePush(ctxt,
9285
0
            xmlXPathCacheWrapString(ctxt->context,
9286
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9287
0
        nargs = 1;
9288
0
    }
9289
9290
0
    CHECK_ARITY(1);
9291
0
    CAST_TO_STRING;
9292
0
    CHECK_TYPE(XPATH_STRING);
9293
0
    source = ctxt->value->stringval;
9294
0
    if (source == NULL)
9295
0
        return;
9296
0
    target = source;
9297
9298
    /* Skip leading whitespaces */
9299
0
    while (IS_BLANK_CH(*source))
9300
0
        source++;
9301
9302
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9303
0
    blank = 0;
9304
0
    while (*source) {
9305
0
        if (IS_BLANK_CH(*source)) {
9306
0
      blank = 1;
9307
0
        } else {
9308
0
            if (blank) {
9309
0
                *target++ = 0x20;
9310
0
                blank = 0;
9311
0
            }
9312
0
            *target++ = *source;
9313
0
        }
9314
0
        source++;
9315
0
    }
9316
0
    *target = 0;
9317
0
}
9318
9319
/**
9320
 * xmlXPathTranslateFunction:
9321
 * @ctxt:  the XPath Parser context
9322
 * @nargs:  the number of arguments
9323
 *
9324
 * Implement the translate() XPath function
9325
 *    string translate(string, string, string)
9326
 * The translate function returns the first argument string with
9327
 * occurrences of characters in the second argument string replaced
9328
 * by the character at the corresponding position in the third argument
9329
 * string. For example, translate("bar","abc","ABC") returns the string
9330
 * BAr. If there is a character in the second argument string with no
9331
 * character at a corresponding position in the third argument string
9332
 * (because the second argument string is longer than the third argument
9333
 * string), then occurrences of that character in the first argument
9334
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9335
 * returns "AAA". If a character occurs more than once in second
9336
 * argument string, then the first occurrence determines the replacement
9337
 * character. If the third argument string is longer than the second
9338
 * argument string, then excess characters are ignored.
9339
 */
9340
void
9341
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9342
0
    xmlXPathObjectPtr str;
9343
0
    xmlXPathObjectPtr from;
9344
0
    xmlXPathObjectPtr to;
9345
0
    xmlBufPtr target;
9346
0
    int offset, max;
9347
0
    xmlChar ch;
9348
0
    const xmlChar *point;
9349
0
    xmlChar *cptr;
9350
9351
0
    CHECK_ARITY(3);
9352
9353
0
    CAST_TO_STRING;
9354
0
    to = valuePop(ctxt);
9355
0
    CAST_TO_STRING;
9356
0
    from = valuePop(ctxt);
9357
0
    CAST_TO_STRING;
9358
0
    str = valuePop(ctxt);
9359
9360
0
    target = xmlBufCreate();
9361
0
    if (target) {
9362
0
  max = xmlUTF8Strlen(to->stringval);
9363
0
  for (cptr = str->stringval; (ch=*cptr); ) {
9364
0
      offset = xmlUTF8Strloc(from->stringval, cptr);
9365
0
      if (offset >= 0) {
9366
0
    if (offset < max) {
9367
0
        point = xmlUTF8Strpos(to->stringval, offset);
9368
0
        if (point)
9369
0
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9370
0
    }
9371
0
      } else
9372
0
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9373
9374
      /* Step to next character in input */
9375
0
      cptr++;
9376
0
      if ( ch & 0x80 ) {
9377
    /* if not simple ascii, verify proper format */
9378
0
    if ( (ch & 0xc0) != 0xc0 ) {
9379
0
        xmlGenericError(xmlGenericErrorContext,
9380
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381
                    /* not asserting an XPath error is probably better */
9382
0
        break;
9383
0
    }
9384
    /* then skip over remaining bytes for this char */
9385
0
    while ( (ch <<= 1) & 0x80 )
9386
0
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9387
0
      xmlGenericError(xmlGenericErrorContext,
9388
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9389
                        /* not asserting an XPath error is probably better */
9390
0
      break;
9391
0
        }
9392
0
    if (ch & 0x80) /* must have had error encountered */
9393
0
        break;
9394
0
      }
9395
0
  }
9396
0
    }
9397
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9398
0
  xmlBufContent(target)));
9399
0
    xmlBufFree(target);
9400
0
    xmlXPathReleaseObject(ctxt->context, str);
9401
0
    xmlXPathReleaseObject(ctxt->context, from);
9402
0
    xmlXPathReleaseObject(ctxt->context, to);
9403
0
}
9404
9405
/**
9406
 * xmlXPathBooleanFunction:
9407
 * @ctxt:  the XPath Parser context
9408
 * @nargs:  the number of arguments
9409
 *
9410
 * Implement the boolean() XPath function
9411
 *    boolean boolean(object)
9412
 * The boolean function converts its argument to a boolean as follows:
9413
 *    - a number is true if and only if it is neither positive or
9414
 *      negative zero nor NaN
9415
 *    - a node-set is true if and only if it is non-empty
9416
 *    - a string is true if and only if its length is non-zero
9417
 */
9418
void
9419
1.21M
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420
1.21M
    xmlXPathObjectPtr cur;
9421
9422
3.63M
    CHECK_ARITY(1);
9423
3.63M
    cur = valuePop(ctxt);
9424
3.63M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9425
1.21M
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9426
1.21M
    valuePush(ctxt, cur);
9427
1.21M
}
9428
9429
/**
9430
 * xmlXPathNotFunction:
9431
 * @ctxt:  the XPath Parser context
9432
 * @nargs:  the number of arguments
9433
 *
9434
 * Implement the not() XPath function
9435
 *    boolean not(boolean)
9436
 * The not function returns true if its argument is false,
9437
 * and false otherwise.
9438
 */
9439
void
9440
3
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9441
7
    CHECK_ARITY(1);
9442
7
    CAST_TO_BOOLEAN;
9443
7
    CHECK_TYPE(XPATH_BOOLEAN);
9444
2
    ctxt->value->boolval = ! ctxt->value->boolval;
9445
2
}
9446
9447
/**
9448
 * xmlXPathTrueFunction:
9449
 * @ctxt:  the XPath Parser context
9450
 * @nargs:  the number of arguments
9451
 *
9452
 * Implement the true() XPath function
9453
 *    boolean true()
9454
 */
9455
void
9456
324
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9457
970
    CHECK_ARITY(0);
9458
970
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9459
970
}
9460
9461
/**
9462
 * xmlXPathFalseFunction:
9463
 * @ctxt:  the XPath Parser context
9464
 * @nargs:  the number of arguments
9465
 *
9466
 * Implement the false() XPath function
9467
 *    boolean false()
9468
 */
9469
void
9470
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9471
0
    CHECK_ARITY(0);
9472
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9473
0
}
9474
9475
/**
9476
 * xmlXPathLangFunction:
9477
 * @ctxt:  the XPath Parser context
9478
 * @nargs:  the number of arguments
9479
 *
9480
 * Implement the lang() XPath function
9481
 *    boolean lang(string)
9482
 * The lang function returns true or false depending on whether the
9483
 * language of the context node as specified by xml:lang attributes
9484
 * is the same as or is a sublanguage of the language specified by
9485
 * the argument string. The language of the context node is determined
9486
 * by the value of the xml:lang attribute on the context node, or, if
9487
 * the context node has no xml:lang attribute, by the value of the
9488
 * xml:lang attribute on the nearest ancestor of the context node that
9489
 * has an xml:lang attribute. If there is no such attribute, then lang
9490
 * returns false. If there is such an attribute, then lang returns
9491
 * true if the attribute value is equal to the argument ignoring case,
9492
 * or if there is some suffix starting with - such that the attribute
9493
 * value is equal to the argument ignoring that suffix of the attribute
9494
 * value and ignoring case.
9495
 */
9496
void
9497
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498
0
    xmlXPathObjectPtr val = NULL;
9499
0
    const xmlChar *theLang = NULL;
9500
0
    const xmlChar *lang;
9501
0
    int ret = 0;
9502
0
    int i;
9503
9504
0
    CHECK_ARITY(1);
9505
0
    CAST_TO_STRING;
9506
0
    CHECK_TYPE(XPATH_STRING);
9507
0
    val = valuePop(ctxt);
9508
0
    lang = val->stringval;
9509
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9510
0
    if ((theLang != NULL) && (lang != NULL)) {
9511
0
        for (i = 0;lang[i] != 0;i++)
9512
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9513
0
          goto not_equal;
9514
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9515
0
      ret = 1;
9516
0
    }
9517
0
not_equal:
9518
0
    if (theLang != NULL)
9519
0
  xmlFree((void *)theLang);
9520
9521
0
    xmlXPathReleaseObject(ctxt->context, val);
9522
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9523
0
}
9524
9525
/**
9526
 * xmlXPathNumberFunction:
9527
 * @ctxt:  the XPath Parser context
9528
 * @nargs:  the number of arguments
9529
 *
9530
 * Implement the number() XPath function
9531
 *    number number(object?)
9532
 */
9533
void
9534
7.50M
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
7.50M
    xmlXPathObjectPtr cur;
9536
7.50M
    double res;
9537
9538
7.50M
    if (ctxt == NULL) return;
9539
7.50M
    if (nargs == 0) {
9540
0
  if (ctxt->context->node == NULL) {
9541
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9542
0
  } else {
9543
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9544
9545
0
      res = xmlXPathStringEvalNumber(content);
9546
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9547
0
      xmlFree(content);
9548
0
  }
9549
0
  return;
9550
0
    }
9551
9552
30.0M
    CHECK_ARITY(1);
9553
30.0M
    cur = valuePop(ctxt);
9554
30.0M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9555
30.0M
}
9556
9557
/**
9558
 * xmlXPathSumFunction:
9559
 * @ctxt:  the XPath Parser context
9560
 * @nargs:  the number of arguments
9561
 *
9562
 * Implement the sum() XPath function
9563
 *    number sum(node-set)
9564
 * The sum function returns the sum of the values of the nodes in
9565
 * the argument node-set.
9566
 */
9567
void
9568
4.42k
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9569
4.42k
    xmlXPathObjectPtr cur;
9570
4.42k
    int i;
9571
4.42k
    double res = 0.0;
9572
9573
13.2k
    CHECK_ARITY(1);
9574
13.2k
    if ((ctxt->value == NULL) ||
9575
4.42k
  ((ctxt->value->type != XPATH_NODESET) &&
9576
4.42k
   (ctxt->value->type != XPATH_XSLT_TREE)))
9577
4.42k
  XP_ERROR(XPATH_INVALID_TYPE);
9578
4.42k
    cur = valuePop(ctxt);
9579
9580
4.42k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9581
8.66k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9582
6.05k
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9583
6.05k
  }
9584
2.61k
    }
9585
4.42k
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9586
4.42k
    xmlXPathReleaseObject(ctxt->context, cur);
9587
4.42k
}
9588
9589
/**
9590
 * xmlXPathFloorFunction:
9591
 * @ctxt:  the XPath Parser context
9592
 * @nargs:  the number of arguments
9593
 *
9594
 * Implement the floor() XPath function
9595
 *    number floor(number)
9596
 * The floor function returns the largest (closest to positive infinity)
9597
 * number that is not greater than the argument and that is an integer.
9598
 */
9599
void
9600
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9601
0
    CHECK_ARITY(1);
9602
0
    CAST_TO_NUMBER;
9603
0
    CHECK_TYPE(XPATH_NUMBER);
9604
9605
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9606
0
}
9607
9608
/**
9609
 * xmlXPathCeilingFunction:
9610
 * @ctxt:  the XPath Parser context
9611
 * @nargs:  the number of arguments
9612
 *
9613
 * Implement the ceiling() XPath function
9614
 *    number ceiling(number)
9615
 * The ceiling function returns the smallest (closest to negative infinity)
9616
 * number that is not less than the argument and that is an integer.
9617
 */
9618
void
9619
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9620
0
    CHECK_ARITY(1);
9621
0
    CAST_TO_NUMBER;
9622
0
    CHECK_TYPE(XPATH_NUMBER);
9623
9624
#ifdef _AIX
9625
    /* Work around buggy ceil() function on AIX */
9626
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9627
#else
9628
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9629
0
#endif
9630
0
}
9631
9632
/**
9633
 * xmlXPathRoundFunction:
9634
 * @ctxt:  the XPath Parser context
9635
 * @nargs:  the number of arguments
9636
 *
9637
 * Implement the round() XPath function
9638
 *    number round(number)
9639
 * The round function returns the number that is closest to the
9640
 * argument and that is an integer. If there are two such numbers,
9641
 * then the one that is closest to positive infinity is returned.
9642
 */
9643
void
9644
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9645
0
    double f;
9646
9647
0
    CHECK_ARITY(1);
9648
0
    CAST_TO_NUMBER;
9649
0
    CHECK_TYPE(XPATH_NUMBER);
9650
9651
0
    f = ctxt->value->floatval;
9652
9653
0
    if ((f >= -0.5) && (f < 0.5)) {
9654
        /* Handles negative zero. */
9655
0
        ctxt->value->floatval *= 0.0;
9656
0
    }
9657
0
    else {
9658
0
        double rounded = floor(f);
9659
0
        if (f - rounded >= 0.5)
9660
0
            rounded += 1.0;
9661
0
        ctxt->value->floatval = rounded;
9662
0
    }
9663
0
}
9664
9665
/************************************************************************
9666
 *                  *
9667
 *      The Parser          *
9668
 *                  *
9669
 ************************************************************************/
9670
9671
/*
9672
 * a few forward declarations since we use a recursive call based
9673
 * implementation.
9674
 */
9675
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9676
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9677
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9678
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9679
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9680
                                    int qualified);
9681
9682
/**
9683
 * xmlXPathCurrentChar:
9684
 * @ctxt:  the XPath parser context
9685
 * @cur:  pointer to the beginning of the char
9686
 * @len:  pointer to the length of the char read
9687
 *
9688
 * The current char value, if using UTF-8 this may actually span multiple
9689
 * bytes in the input buffer.
9690
 *
9691
 * Returns the current char value and its length
9692
 */
9693
9694
static int
9695
505k
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9696
505k
    unsigned char c;
9697
505k
    unsigned int val;
9698
505k
    const xmlChar *cur;
9699
9700
505k
    if (ctxt == NULL)
9701
0
  return(0);
9702
505k
    cur = ctxt->cur;
9703
9704
    /*
9705
     * We are supposed to handle UTF8, check it's valid
9706
     * From rfc2044: encoding of the Unicode values on UTF-8:
9707
     *
9708
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9709
     * 0000 0000-0000 007F   0xxxxxxx
9710
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9711
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9712
     *
9713
     * Check for the 0x110000 limit too
9714
     */
9715
505k
    c = *cur;
9716
505k
    if (c & 0x80) {
9717
47.0k
  if ((cur[1] & 0xc0) != 0x80)
9718
501
      goto encoding_error;
9719
46.5k
  if ((c & 0xe0) == 0xe0) {
9720
9721
3.32k
      if ((cur[2] & 0xc0) != 0x80)
9722
10
    goto encoding_error;
9723
3.31k
      if ((c & 0xf0) == 0xf0) {
9724
112
    if (((c & 0xf8) != 0xf0) ||
9725
112
        ((cur[3] & 0xc0) != 0x80))
9726
7
        goto encoding_error;
9727
    /* 4-byte code */
9728
105
    *len = 4;
9729
105
    val = (cur[0] & 0x7) << 18;
9730
105
    val |= (cur[1] & 0x3f) << 12;
9731
105
    val |= (cur[2] & 0x3f) << 6;
9732
105
    val |= cur[3] & 0x3f;
9733
3.20k
      } else {
9734
        /* 3-byte code */
9735
3.20k
    *len = 3;
9736
3.20k
    val = (cur[0] & 0xf) << 12;
9737
3.20k
    val |= (cur[1] & 0x3f) << 6;
9738
3.20k
    val |= cur[2] & 0x3f;
9739
3.20k
      }
9740
43.1k
  } else {
9741
    /* 2-byte code */
9742
43.1k
      *len = 2;
9743
43.1k
      val = (cur[0] & 0x1f) << 6;
9744
43.1k
      val |= cur[1] & 0x3f;
9745
43.1k
  }
9746
46.4k
  if (!IS_CHAR(val)) {
9747
17
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9748
0
  }
9749
46.4k
  return(val);
9750
458k
    } else {
9751
  /* 1-byte code */
9752
458k
  *len = 1;
9753
458k
  return(*cur);
9754
458k
    }
9755
518
encoding_error:
9756
    /*
9757
     * If we detect an UTF8 error that probably means that the
9758
     * input encoding didn't get properly advertised in the
9759
     * declaration header. Report the error and switch the encoding
9760
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9761
     * encoding !)
9762
     */
9763
518
    *len = 0;
9764
518
    XP_ERROR0(XPATH_ENCODING_ERROR);
9765
0
}
9766
9767
/**
9768
 * xmlXPathParseNCName:
9769
 * @ctxt:  the XPath Parser context
9770
 *
9771
 * parse an XML namespace non qualified name.
9772
 *
9773
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9774
 *
9775
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9776
 *                       CombiningChar | Extender
9777
 *
9778
 * Returns the namespace name or NULL
9779
 */
9780
9781
xmlChar *
9782
128k
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9783
128k
    const xmlChar *in;
9784
128k
    xmlChar *ret;
9785
128k
    int count = 0;
9786
9787
128k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9788
    /*
9789
     * Accelerator for simple ASCII names
9790
     */
9791
128k
    in = ctxt->cur;
9792
128k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9793
128k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9794
128k
  (*in == '_')) {
9795
114k
  in++;
9796
296k
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9797
296k
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9798
296k
         ((*in >= 0x30) && (*in <= 0x39)) ||
9799
296k
         (*in == '_') || (*in == '.') ||
9800
296k
         (*in == '-'))
9801
182k
      in++;
9802
114k
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9803
114k
            (*in == '[') || (*in == ']') || (*in == ':') ||
9804
114k
            (*in == '@') || (*in == '*')) {
9805
57.8k
      count = in - ctxt->cur;
9806
57.8k
      if (count == 0)
9807
0
    return(NULL);
9808
57.8k
      ret = xmlStrndup(ctxt->cur, count);
9809
57.8k
      ctxt->cur = in;
9810
57.8k
      return(ret);
9811
57.8k
  }
9812
114k
    }
9813
70.3k
    return(xmlXPathParseNameComplex(ctxt, 0));
9814
128k
}
9815
9816
9817
/**
9818
 * xmlXPathParseQName:
9819
 * @ctxt:  the XPath Parser context
9820
 * @prefix:  a xmlChar **
9821
 *
9822
 * parse an XML qualified name
9823
 *
9824
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9825
 *
9826
 * [NS 6] Prefix ::= NCName
9827
 *
9828
 * [NS 7] LocalPart ::= NCName
9829
 *
9830
 * Returns the function returns the local part, and prefix is updated
9831
 *   to get the Prefix if any.
9832
 */
9833
9834
static xmlChar *
9835
4.61k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9836
4.61k
    xmlChar *ret = NULL;
9837
9838
4.61k
    *prefix = NULL;
9839
4.61k
    ret = xmlXPathParseNCName(ctxt);
9840
4.61k
    if (ret && CUR == ':') {
9841
434
        *prefix = ret;
9842
434
  NEXT;
9843
434
  ret = xmlXPathParseNCName(ctxt);
9844
434
    }
9845
4.61k
    return(ret);
9846
4.61k
}
9847
9848
/**
9849
 * xmlXPathParseName:
9850
 * @ctxt:  the XPath Parser context
9851
 *
9852
 * parse an XML name
9853
 *
9854
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9855
 *                  CombiningChar | Extender
9856
 *
9857
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9858
 *
9859
 * Returns the namespace name or NULL
9860
 */
9861
9862
xmlChar *
9863
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9864
0
    const xmlChar *in;
9865
0
    xmlChar *ret;
9866
0
    size_t count = 0;
9867
9868
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9869
    /*
9870
     * Accelerator for simple ASCII names
9871
     */
9872
0
    in = ctxt->cur;
9873
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9874
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9875
0
  (*in == '_') || (*in == ':')) {
9876
0
  in++;
9877
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9878
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9879
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9880
0
         (*in == '_') || (*in == '-') ||
9881
0
         (*in == ':') || (*in == '.'))
9882
0
      in++;
9883
0
  if ((*in > 0) && (*in < 0x80)) {
9884
0
      count = in - ctxt->cur;
9885
0
            if (count > XML_MAX_NAME_LENGTH) {
9886
0
                ctxt->cur = in;
9887
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9888
0
            }
9889
0
      ret = xmlStrndup(ctxt->cur, count);
9890
0
      ctxt->cur = in;
9891
0
      return(ret);
9892
0
  }
9893
0
    }
9894
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9895
0
}
9896
9897
static xmlChar *
9898
70.3k
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9899
70.3k
    xmlChar buf[XML_MAX_NAMELEN + 5];
9900
70.3k
    int len = 0, l;
9901
70.3k
    int c;
9902
9903
    /*
9904
     * Handler for more complex cases
9905
     */
9906
70.3k
    c = CUR_CHAR(l);
9907
70.3k
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9908
70.3k
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9909
70.3k
        (c == '*') || /* accelerators */
9910
70.3k
  (!IS_LETTER(c) && (c != '_') &&
9911
62.8k
         ((!qualified) || (c != ':')))) {
9912
8.63k
  return(NULL);
9913
8.63k
    }
9914
9915
237k
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9916
237k
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9917
234k
            (c == '.') || (c == '-') ||
9918
234k
      (c == '_') || ((qualified) && (c == ':')) ||
9919
234k
      (IS_COMBINING(c)) ||
9920
234k
      (IS_EXTENDER(c)))) {
9921
176k
  COPY_BUF(l,buf,len,c);
9922
176k
  NEXTL(l);
9923
176k
  c = CUR_CHAR(l);
9924
176k
  if (len >= XML_MAX_NAMELEN) {
9925
      /*
9926
       * Okay someone managed to make a huge name, so he's ready to pay
9927
       * for the processing speed.
9928
       */
9929
251
      xmlChar *buffer;
9930
251
      int max = len * 2;
9931
9932
251
            if (len > XML_MAX_NAME_LENGTH) {
9933
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9934
0
            }
9935
251
      buffer = (xmlChar *) xmlMallocAtomic(max);
9936
251
      if (buffer == NULL) {
9937
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9938
0
      }
9939
251
      memcpy(buffer, buf, len);
9940
18.0k
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9941
18.0k
       (c == '.') || (c == '-') ||
9942
18.0k
       (c == '_') || ((qualified) && (c == ':')) ||
9943
18.0k
       (IS_COMBINING(c)) ||
9944
18.0k
       (IS_EXTENDER(c))) {
9945
17.7k
    if (len + 10 > max) {
9946
118
                    xmlChar *tmp;
9947
118
                    if (max > XML_MAX_NAME_LENGTH) {
9948
0
                        xmlFree(buffer);
9949
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9950
0
                    }
9951
118
        max *= 2;
9952
118
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9953
118
        if (tmp == NULL) {
9954
0
                        xmlFree(buffer);
9955
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9956
0
        }
9957
118
                    buffer = tmp;
9958
118
    }
9959
17.7k
    COPY_BUF(l,buffer,len,c);
9960
17.7k
    NEXTL(l);
9961
17.7k
    c = CUR_CHAR(l);
9962
17.7k
      }
9963
251
      buffer[len] = 0;
9964
251
      return(buffer);
9965
251
  }
9966
176k
    }
9967
61.4k
    if (len == 0)
9968
0
  return(NULL);
9969
61.4k
    return(xmlStrndup(buf, len));
9970
61.4k
}
9971
9972
135k
#define MAX_FRAC 20
9973
9974
/**
9975
 * xmlXPathStringEvalNumber:
9976
 * @str:  A string to scan
9977
 *
9978
 *  [30a]  Float  ::= Number ('e' Digits?)?
9979
 *
9980
 *  [30]   Number ::=   Digits ('.' Digits?)?
9981
 *                    | '.' Digits
9982
 *  [31]   Digits ::=   [0-9]+
9983
 *
9984
 * Compile a Number in the string
9985
 * In complement of the Number expression, this function also handles
9986
 * negative values : '-' Number.
9987
 *
9988
 * Returns the double value.
9989
 */
9990
double
9991
8.67M
xmlXPathStringEvalNumber(const xmlChar *str) {
9992
8.67M
    const xmlChar *cur = str;
9993
8.67M
    double ret;
9994
8.67M
    int ok = 0;
9995
8.67M
    int isneg = 0;
9996
8.67M
    int exponent = 0;
9997
8.67M
    int is_exponent_negative = 0;
9998
8.67M
#ifdef __GNUC__
9999
8.67M
    unsigned long tmp = 0;
10000
8.67M
    double temp;
10001
8.67M
#endif
10002
8.67M
    if (cur == NULL) return(0);
10003
28.5M
    while (IS_BLANK_CH(*cur)) cur++;
10004
8.67M
    if (*cur == '-') {
10005
674
  isneg = 1;
10006
674
  cur++;
10007
674
    }
10008
8.67M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
10009
7.54M
        return(xmlXPathNAN);
10010
7.54M
    }
10011
10012
1.13M
#ifdef __GNUC__
10013
    /*
10014
     * tmp/temp is a workaround against a gcc compiler bug
10015
     * http://veillard.com/gcc.bug
10016
     */
10017
1.13M
    ret = 0;
10018
2.29M
    while ((*cur >= '0') && (*cur <= '9')) {
10019
1.16M
  ret = ret * 10;
10020
1.16M
  tmp = (*cur - '0');
10021
1.16M
  ok = 1;
10022
1.16M
  cur++;
10023
1.16M
  temp = (double) tmp;
10024
1.16M
  ret = ret + temp;
10025
1.16M
    }
10026
#else
10027
    ret = 0;
10028
    while ((*cur >= '0') && (*cur <= '9')) {
10029
  ret = ret * 10 + (*cur - '0');
10030
  ok = 1;
10031
  cur++;
10032
    }
10033
#endif
10034
10035
1.13M
    if (*cur == '.') {
10036
211k
  int v, frac = 0, max;
10037
211k
  double fraction = 0;
10038
10039
211k
        cur++;
10040
211k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10041
78.0k
      return(xmlXPathNAN);
10042
78.0k
  }
10043
217k
        while (*cur == '0') {
10044
83.7k
      frac = frac + 1;
10045
83.7k
      cur++;
10046
83.7k
        }
10047
133k
        max = frac + MAX_FRAC;
10048
198k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10049
64.4k
      v = (*cur - '0');
10050
64.4k
      fraction = fraction * 10 + v;
10051
64.4k
      frac = frac + 1;
10052
64.4k
      cur++;
10053
64.4k
  }
10054
133k
  fraction /= pow(10.0, frac);
10055
133k
  ret = ret + fraction;
10056
147k
  while ((*cur >= '0') && (*cur <= '9'))
10057
14.1k
      cur++;
10058
133k
    }
10059
1.05M
    if ((*cur == 'e') || (*cur == 'E')) {
10060
12.2k
      cur++;
10061
12.2k
      if (*cur == '-') {
10062
8.50k
  is_exponent_negative = 1;
10063
8.50k
  cur++;
10064
8.50k
      } else if (*cur == '+') {
10065
1.23k
        cur++;
10066
1.23k
      }
10067
30.3k
      while ((*cur >= '0') && (*cur <= '9')) {
10068
18.0k
        if (exponent < 1000000)
10069
17.5k
    exponent = exponent * 10 + (*cur - '0');
10070
18.0k
  cur++;
10071
18.0k
      }
10072
12.2k
    }
10073
1.05M
    while (IS_BLANK_CH(*cur)) cur++;
10074
1.05M
    if (*cur != 0) return(xmlXPathNAN);
10075
935k
    if (isneg) ret = -ret;
10076
935k
    if (is_exponent_negative) exponent = -exponent;
10077
935k
    ret *= pow(10.0, (double)exponent);
10078
935k
    return(ret);
10079
1.05M
}
10080
10081
/**
10082
 * xmlXPathCompNumber:
10083
 * @ctxt:  the XPath Parser context
10084
 *
10085
 *  [30]   Number ::=   Digits ('.' Digits?)?
10086
 *                    | '.' Digits
10087
 *  [31]   Digits ::=   [0-9]+
10088
 *
10089
 * Compile a Number, then push it on the stack
10090
 *
10091
 */
10092
static void
10093
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10094
14.3k
{
10095
14.3k
    double ret = 0.0;
10096
14.3k
    int ok = 0;
10097
14.3k
    int exponent = 0;
10098
14.3k
    int is_exponent_negative = 0;
10099
14.3k
    xmlXPathObjectPtr num;
10100
14.3k
#ifdef __GNUC__
10101
14.3k
    unsigned long tmp = 0;
10102
14.3k
    double temp;
10103
14.3k
#endif
10104
10105
14.3k
    CHECK_ERROR;
10106
14.3k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10107
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10108
0
    }
10109
14.3k
#ifdef __GNUC__
10110
    /*
10111
     * tmp/temp is a workaround against a gcc compiler bug
10112
     * http://veillard.com/gcc.bug
10113
     */
10114
14.3k
    ret = 0;
10115
53.9k
    while ((CUR >= '0') && (CUR <= '9')) {
10116
39.5k
  ret = ret * 10;
10117
39.5k
  tmp = (CUR - '0');
10118
39.5k
        ok = 1;
10119
39.5k
        NEXT;
10120
39.5k
  temp = (double) tmp;
10121
39.5k
  ret = ret + temp;
10122
39.5k
    }
10123
#else
10124
    ret = 0;
10125
    while ((CUR >= '0') && (CUR <= '9')) {
10126
  ret = ret * 10 + (CUR - '0');
10127
  ok = 1;
10128
  NEXT;
10129
    }
10130
#endif
10131
14.3k
    if (CUR == '.') {
10132
1.72k
  int v, frac = 0, max;
10133
1.72k
  double fraction = 0;
10134
10135
1.72k
        NEXT;
10136
1.72k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10137
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10138
0
        }
10139
3.02k
        while (CUR == '0') {
10140
1.30k
            frac = frac + 1;
10141
1.30k
            NEXT;
10142
1.30k
        }
10143
1.72k
        max = frac + MAX_FRAC;
10144
4.78k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10145
3.06k
      v = (CUR - '0');
10146
3.06k
      fraction = fraction * 10 + v;
10147
3.06k
      frac = frac + 1;
10148
3.06k
            NEXT;
10149
3.06k
        }
10150
1.72k
        fraction /= pow(10.0, frac);
10151
1.72k
        ret = ret + fraction;
10152
3.35k
        while ((CUR >= '0') && (CUR <= '9'))
10153
1.63k
            NEXT;
10154
1.72k
    }
10155
14.3k
    if ((CUR == 'e') || (CUR == 'E')) {
10156
2.32k
        NEXT;
10157
2.32k
        if (CUR == '-') {
10158
69
            is_exponent_negative = 1;
10159
69
            NEXT;
10160
2.25k
        } else if (CUR == '+') {
10161
71
      NEXT;
10162
71
  }
10163
11.8k
        while ((CUR >= '0') && (CUR <= '9')) {
10164
9.54k
            if (exponent < 1000000)
10165
8.34k
                exponent = exponent * 10 + (CUR - '0');
10166
9.54k
            NEXT;
10167
9.54k
        }
10168
2.32k
        if (is_exponent_negative)
10169
69
            exponent = -exponent;
10170
2.32k
        ret *= pow(10.0, (double) exponent);
10171
2.32k
    }
10172
14.3k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10173
14.3k
    if (num == NULL) {
10174
0
  ctxt->error = XPATH_MEMORY_ERROR;
10175
14.3k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10176
14.3k
                              NULL) == -1) {
10177
0
        xmlXPathReleaseObject(ctxt->context, num);
10178
0
    }
10179
14.3k
}
10180
10181
/**
10182
 * xmlXPathParseLiteral:
10183
 * @ctxt:  the XPath Parser context
10184
 *
10185
 * Parse a Literal
10186
 *
10187
 *  [29]   Literal ::=   '"' [^"]* '"'
10188
 *                    | "'" [^']* "'"
10189
 *
10190
 * Returns the value found or NULL in case of error
10191
 */
10192
static xmlChar *
10193
111
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10194
111
    const xmlChar *q;
10195
111
    xmlChar *ret = NULL;
10196
10197
111
    if (CUR == '"') {
10198
38
        NEXT;
10199
38
  q = CUR_PTR;
10200
3.29k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10201
3.25k
      NEXT;
10202
38
  if (!IS_CHAR_CH(CUR)) {
10203
26
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10204
12
  } else {
10205
12
      ret = xmlStrndup(q, CUR_PTR - q);
10206
12
      NEXT;
10207
12
        }
10208
73
    } else if (CUR == '\'') {
10209
71
        NEXT;
10210
71
  q = CUR_PTR;
10211
3.56k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10212
3.49k
      NEXT;
10213
71
  if (!IS_CHAR_CH(CUR)) {
10214
23
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10215
48
  } else {
10216
48
      ret = xmlStrndup(q, CUR_PTR - q);
10217
48
      NEXT;
10218
48
        }
10219
71
    } else {
10220
2
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10221
0
    }
10222
60
    return(ret);
10223
111
}
10224
10225
/**
10226
 * xmlXPathCompLiteral:
10227
 * @ctxt:  the XPath Parser context
10228
 *
10229
 * Parse a Literal and push it on the stack.
10230
 *
10231
 *  [29]   Literal ::=   '"' [^"]* '"'
10232
 *                    | "'" [^']* "'"
10233
 *
10234
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10235
 */
10236
static void
10237
1.99k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10238
1.99k
    const xmlChar *q;
10239
1.99k
    xmlChar *ret = NULL;
10240
1.99k
    xmlXPathObjectPtr lit;
10241
10242
1.99k
    if (CUR == '"') {
10243
1.50k
        NEXT;
10244
1.50k
  q = CUR_PTR;
10245
15.3k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10246
13.8k
      NEXT;
10247
1.50k
  if (!IS_CHAR_CH(CUR)) {
10248
36
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10249
1.46k
  } else {
10250
1.46k
      ret = xmlStrndup(q, CUR_PTR - q);
10251
1.46k
      NEXT;
10252
1.46k
        }
10253
1.50k
    } else if (CUR == '\'') {
10254
491
        NEXT;
10255
491
  q = CUR_PTR;
10256
6.86k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10257
6.36k
      NEXT;
10258
491
  if (!IS_CHAR_CH(CUR)) {
10259
33
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10260
458
  } else {
10261
458
      ret = xmlStrndup(q, CUR_PTR - q);
10262
458
      NEXT;
10263
458
        }
10264
491
    } else {
10265
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10266
0
    }
10267
1.92k
    if (ret == NULL) return;
10268
1.92k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10269
1.92k
    if (lit == NULL) {
10270
0
  ctxt->error = XPATH_MEMORY_ERROR;
10271
1.92k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10272
1.92k
                              NULL) == -1) {
10273
0
        xmlXPathReleaseObject(ctxt->context, lit);
10274
0
    }
10275
1.92k
    xmlFree(ret);
10276
1.92k
}
10277
10278
/**
10279
 * xmlXPathCompVariableReference:
10280
 * @ctxt:  the XPath Parser context
10281
 *
10282
 * Parse a VariableReference, evaluate it and push it on the stack.
10283
 *
10284
 * The variable bindings consist of a mapping from variable names
10285
 * to variable values. The value of a variable is an object, which can be
10286
 * of any of the types that are possible for the value of an expression,
10287
 * and may also be of additional types not specified here.
10288
 *
10289
 * Early evaluation is possible since:
10290
 * The variable bindings [...] used to evaluate a subexpression are
10291
 * always the same as those used to evaluate the containing expression.
10292
 *
10293
 *  [36]   VariableReference ::=   '$' QName
10294
 */
10295
static void
10296
1.84k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10297
1.84k
    xmlChar *name;
10298
1.84k
    xmlChar *prefix;
10299
10300
1.84k
    SKIP_BLANKS;
10301
1.84k
    if (CUR != '$') {
10302
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10303
0
    }
10304
1.84k
    NEXT;
10305
1.84k
    name = xmlXPathParseQName(ctxt, &prefix);
10306
1.84k
    if (name == NULL) {
10307
605
        xmlFree(prefix);
10308
605
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10309
0
    }
10310
1.24k
    ctxt->comp->last = -1;
10311
1.24k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10312
0
        xmlFree(prefix);
10313
0
        xmlFree(name);
10314
0
    }
10315
1.24k
    SKIP_BLANKS;
10316
1.24k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10317
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10318
0
    }
10319
1.24k
}
10320
10321
/**
10322
 * xmlXPathIsNodeType:
10323
 * @name:  a name string
10324
 *
10325
 * Is the name given a NodeType one.
10326
 *
10327
 *  [38]   NodeType ::=   'comment'
10328
 *                    | 'text'
10329
 *                    | 'processing-instruction'
10330
 *                    | 'node'
10331
 *
10332
 * Returns 1 if true 0 otherwise
10333
 */
10334
int
10335
3.28k
xmlXPathIsNodeType(const xmlChar *name) {
10336
3.28k
    if (name == NULL)
10337
0
  return(0);
10338
10339
3.28k
    if (xmlStrEqual(name, BAD_CAST "node"))
10340
169
  return(1);
10341
3.11k
    if (xmlStrEqual(name, BAD_CAST "text"))
10342
189
  return(1);
10343
2.92k
    if (xmlStrEqual(name, BAD_CAST "comment"))
10344
36
  return(1);
10345
2.89k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10346
121
  return(1);
10347
2.76k
    return(0);
10348
2.89k
}
10349
10350
/**
10351
 * xmlXPathCompFunctionCall:
10352
 * @ctxt:  the XPath Parser context
10353
 *
10354
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10355
 *  [17]   Argument ::=   Expr
10356
 *
10357
 * Compile a function call, the evaluation of all arguments are
10358
 * pushed on the stack
10359
 */
10360
static void
10361
2.76k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10362
2.76k
    xmlChar *name;
10363
2.76k
    xmlChar *prefix;
10364
2.76k
    int nbargs = 0;
10365
2.76k
    int sort = 1;
10366
10367
2.76k
    name = xmlXPathParseQName(ctxt, &prefix);
10368
2.76k
    if (name == NULL) {
10369
2
  xmlFree(prefix);
10370
2
  XP_ERROR(XPATH_EXPR_ERROR);
10371
0
    }
10372
2.76k
    SKIP_BLANKS;
10373
#ifdef DEBUG_EXPR
10374
    if (prefix == NULL)
10375
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10376
      name);
10377
    else
10378
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10379
      prefix, name);
10380
#endif
10381
10382
2.76k
    if (CUR != '(') {
10383
1
  xmlFree(name);
10384
1
  xmlFree(prefix);
10385
1
  XP_ERROR(XPATH_EXPR_ERROR);
10386
0
    }
10387
2.76k
    NEXT;
10388
2.76k
    SKIP_BLANKS;
10389
10390
    /*
10391
    * Optimization for count(): we don't need the node-set to be sorted.
10392
    */
10393
2.76k
    if ((prefix == NULL) && (name[0] == 'c') &&
10394
2.76k
  xmlStrEqual(name, BAD_CAST "count"))
10395
53
    {
10396
53
  sort = 0;
10397
53
    }
10398
2.76k
    ctxt->comp->last = -1;
10399
2.76k
    if (CUR != ')') {
10400
6.52k
  while (CUR != 0) {
10401
6.37k
      int op1 = ctxt->comp->last;
10402
6.37k
      ctxt->comp->last = -1;
10403
6.37k
      xmlXPathCompileExpr(ctxt, sort);
10404
6.37k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10405
916
    xmlFree(name);
10406
916
    xmlFree(prefix);
10407
916
    return;
10408
916
      }
10409
5.45k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10410
5.45k
      nbargs++;
10411
5.45k
      if (CUR == ')') break;
10412
4.22k
      if (CUR != ',') {
10413
93
    xmlFree(name);
10414
93
    xmlFree(prefix);
10415
93
    XP_ERROR(XPATH_EXPR_ERROR);
10416
0
      }
10417
4.13k
      NEXT;
10418
4.13k
      SKIP_BLANKS;
10419
4.13k
  }
10420
2.39k
    }
10421
1.75k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10422
0
        xmlFree(prefix);
10423
0
        xmlFree(name);
10424
0
    }
10425
1.75k
    NEXT;
10426
1.75k
    SKIP_BLANKS;
10427
1.75k
}
10428
10429
/**
10430
 * xmlXPathCompPrimaryExpr:
10431
 * @ctxt:  the XPath Parser context
10432
 *
10433
 *  [15]   PrimaryExpr ::=   VariableReference
10434
 *                | '(' Expr ')'
10435
 *                | Literal
10436
 *                | Number
10437
 *                | FunctionCall
10438
 *
10439
 * Compile a primary expression.
10440
 */
10441
static void
10442
23.3k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10443
23.3k
    SKIP_BLANKS;
10444
23.3k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10445
21.5k
    else if (CUR == '(') {
10446
2.37k
  NEXT;
10447
2.37k
  SKIP_BLANKS;
10448
2.37k
  xmlXPathCompileExpr(ctxt, 1);
10449
2.37k
  CHECK_ERROR;
10450
1.19k
  if (CUR != ')') {
10451
60
      XP_ERROR(XPATH_EXPR_ERROR);
10452
0
  }
10453
1.13k
  NEXT;
10454
1.13k
  SKIP_BLANKS;
10455
19.1k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10456
14.3k
  xmlXPathCompNumber(ctxt);
10457
14.3k
    } else if ((CUR == '\'') || (CUR == '"')) {
10458
1.99k
  xmlXPathCompLiteral(ctxt);
10459
2.76k
    } else {
10460
2.76k
  xmlXPathCompFunctionCall(ctxt);
10461
2.76k
    }
10462
22.1k
    SKIP_BLANKS;
10463
22.1k
}
10464
10465
/**
10466
 * xmlXPathCompFilterExpr:
10467
 * @ctxt:  the XPath Parser context
10468
 *
10469
 *  [20]   FilterExpr ::=   PrimaryExpr
10470
 *               | FilterExpr Predicate
10471
 *
10472
 * Compile a filter expression.
10473
 * Square brackets are used to filter expressions in the same way that
10474
 * they are used in location paths. It is an error if the expression to
10475
 * be filtered does not evaluate to a node-set. The context node list
10476
 * used for evaluating the expression in square brackets is the node-set
10477
 * to be filtered listed in document order.
10478
 */
10479
10480
static void
10481
23.3k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10482
23.3k
    xmlXPathCompPrimaryExpr(ctxt);
10483
23.3k
    CHECK_ERROR;
10484
19.8k
    SKIP_BLANKS;
10485
10486
22.8k
    while (CUR == '[') {
10487
3.03k
  xmlXPathCompPredicate(ctxt, 1);
10488
3.03k
  SKIP_BLANKS;
10489
3.03k
    }
10490
10491
10492
19.8k
}
10493
10494
/**
10495
 * xmlXPathScanName:
10496
 * @ctxt:  the XPath Parser context
10497
 *
10498
 * Trickery: parse an XML name but without consuming the input flow
10499
 * Needed to avoid insanity in the parser state.
10500
 *
10501
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10502
 *                  CombiningChar | Extender
10503
 *
10504
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10505
 *
10506
 * [6] Names ::= Name (S Name)*
10507
 *
10508
 * Returns the Name parsed or NULL
10509
 */
10510
10511
static xmlChar *
10512
56.3k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10513
56.3k
    int l;
10514
56.3k
    int c;
10515
56.3k
    const xmlChar *cur;
10516
56.3k
    xmlChar *ret;
10517
10518
56.3k
    cur = ctxt->cur;
10519
10520
56.3k
    c = CUR_CHAR(l);
10521
56.3k
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10522
56.3k
  (!IS_LETTER(c) && (c != '_') &&
10523
56.3k
         (c != ':'))) {
10524
2.76k
  return(NULL);
10525
2.76k
    }
10526
10527
238k
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10528
238k
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10529
217k
            (c == '.') || (c == '-') ||
10530
217k
      (c == '_') || (c == ':') ||
10531
217k
      (IS_COMBINING(c)) ||
10532
217k
      (IS_EXTENDER(c)))) {
10533
184k
  NEXTL(l);
10534
184k
  c = CUR_CHAR(l);
10535
184k
    }
10536
53.6k
    ret = xmlStrndup(cur, ctxt->cur - cur);
10537
53.6k
    ctxt->cur = cur;
10538
53.6k
    return(ret);
10539
56.3k
}
10540
10541
/**
10542
 * xmlXPathCompPathExpr:
10543
 * @ctxt:  the XPath Parser context
10544
 *
10545
 *  [19]   PathExpr ::=   LocationPath
10546
 *               | FilterExpr
10547
 *               | FilterExpr '/' RelativeLocationPath
10548
 *               | FilterExpr '//' RelativeLocationPath
10549
 *
10550
 * Compile a path expression.
10551
 * The / operator and // operators combine an arbitrary expression
10552
 * and a relative location path. It is an error if the expression
10553
 * does not evaluate to a node-set.
10554
 * The / operator does composition in the same way as when / is
10555
 * used in a location path. As in location paths, // is short for
10556
 * /descendant-or-self::node()/.
10557
 */
10558
10559
static void
10560
169k
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10561
169k
    int lc = 1;           /* Should we branch to LocationPath ?         */
10562
169k
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10563
10564
169k
    SKIP_BLANKS;
10565
169k
    if ((CUR == '$') || (CUR == '(') ||
10566
169k
  (IS_ASCII_DIGIT(CUR)) ||
10567
169k
        (CUR == '\'') || (CUR == '"') ||
10568
169k
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10569
20.5k
  lc = 0;
10570
148k
    } else if (CUR == '*') {
10571
  /* relative or absolute location path */
10572
18.2k
  lc = 1;
10573
130k
    } else if (CUR == '/') {
10574
  /* relative or absolute location path */
10575
61.5k
  lc = 1;
10576
68.7k
    } else if (CUR == '@') {
10577
  /* relative abbreviated attribute location path */
10578
1.86k
  lc = 1;
10579
66.8k
    } else if (CUR == '.') {
10580
  /* relative abbreviated attribute location path */
10581
10.4k
  lc = 1;
10582
56.3k
    } else {
10583
  /*
10584
   * Problem is finding if we have a name here whether it's:
10585
   *   - a nodetype
10586
   *   - a function call in which case it's followed by '('
10587
   *   - an axis in which case it's followed by ':'
10588
   *   - a element name
10589
   * We do an a priori analysis here rather than having to
10590
   * maintain parsed token content through the recursive function
10591
   * calls. This looks uglier but makes the code easier to
10592
   * read/write/debug.
10593
   */
10594
56.3k
  SKIP_BLANKS;
10595
56.3k
  name = xmlXPathScanName(ctxt);
10596
56.3k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10597
#ifdef DEBUG_STEP
10598
      xmlGenericError(xmlGenericErrorContext,
10599
        "PathExpr: Axis\n");
10600
#endif
10601
303
      lc = 1;
10602
303
      xmlFree(name);
10603
56.0k
  } else if (name != NULL) {
10604
53.3k
      int len =xmlStrlen(name);
10605
10606
10607
65.8k
      while (NXT(len) != 0) {
10608
64.8k
    if (NXT(len) == '/') {
10609
        /* element name */
10610
#ifdef DEBUG_STEP
10611
        xmlGenericError(xmlGenericErrorContext,
10612
          "PathExpr: AbbrRelLocation\n");
10613
#endif
10614
14.3k
        lc = 1;
10615
14.3k
        break;
10616
50.4k
    } else if (IS_BLANK_CH(NXT(len))) {
10617
        /* ignore blanks */
10618
12.5k
        ;
10619
37.8k
    } else if (NXT(len) == ':') {
10620
#ifdef DEBUG_STEP
10621
        xmlGenericError(xmlGenericErrorContext,
10622
          "PathExpr: AbbrRelLocation\n");
10623
#endif
10624
446
        lc = 1;
10625
446
        break;
10626
37.4k
    } else if ((NXT(len) == '(')) {
10627
        /* Node Type or Function */
10628
3.28k
        if (xmlXPathIsNodeType(name)) {
10629
#ifdef DEBUG_STEP
10630
            xmlGenericError(xmlGenericErrorContext,
10631
        "PathExpr: Type search\n");
10632
#endif
10633
515
      lc = 1;
10634
#ifdef LIBXML_XPTR_LOCS_ENABLED
10635
                    } else if (ctxt->xptr &&
10636
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10637
                        lc = 1;
10638
#endif
10639
2.76k
        } else {
10640
#ifdef DEBUG_STEP
10641
            xmlGenericError(xmlGenericErrorContext,
10642
        "PathExpr: function call\n");
10643
#endif
10644
2.76k
      lc = 0;
10645
2.76k
        }
10646
3.28k
                    break;
10647
34.1k
    } else if ((NXT(len) == '[')) {
10648
        /* element name */
10649
#ifdef DEBUG_STEP
10650
        xmlGenericError(xmlGenericErrorContext,
10651
          "PathExpr: AbbrRelLocation\n");
10652
#endif
10653
945
        lc = 1;
10654
945
        break;
10655
33.1k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10656
33.1k
         (NXT(len) == '=')) {
10657
11.8k
        lc = 1;
10658
11.8k
        break;
10659
21.3k
    } else {
10660
21.3k
        lc = 1;
10661
21.3k
        break;
10662
21.3k
    }
10663
12.5k
    len++;
10664
12.5k
      }
10665
53.3k
      if (NXT(len) == 0) {
10666
#ifdef DEBUG_STEP
10667
    xmlGenericError(xmlGenericErrorContext,
10668
      "PathExpr: AbbrRelLocation\n");
10669
#endif
10670
    /* element name */
10671
1.08k
    lc = 1;
10672
1.08k
      }
10673
53.3k
      xmlFree(name);
10674
53.3k
  } else {
10675
      /* make sure all cases are covered explicitly */
10676
2.76k
      XP_ERROR(XPATH_EXPR_ERROR);
10677
0
  }
10678
56.3k
    }
10679
10680
166k
    if (lc) {
10681
142k
  if (CUR == '/') {
10682
61.5k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10683
81.4k
  } else {
10684
81.4k
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10685
81.4k
  }
10686
142k
  xmlXPathCompLocationPath(ctxt);
10687
142k
    } else {
10688
23.3k
  xmlXPathCompFilterExpr(ctxt);
10689
23.3k
  CHECK_ERROR;
10690
19.1k
  if ((CUR == '/') && (NXT(1) == '/')) {
10691
254
      SKIP(2);
10692
254
      SKIP_BLANKS;
10693
10694
254
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10695
254
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10696
10697
254
      xmlXPathCompRelativeLocationPath(ctxt);
10698
18.9k
  } else if (CUR == '/') {
10699
1.12k
      xmlXPathCompRelativeLocationPath(ctxt);
10700
1.12k
  }
10701
19.1k
    }
10702
162k
    SKIP_BLANKS;
10703
162k
}
10704
10705
/**
10706
 * xmlXPathCompUnionExpr:
10707
 * @ctxt:  the XPath Parser context
10708
 *
10709
 *  [18]   UnionExpr ::=   PathExpr
10710
 *               | UnionExpr '|' PathExpr
10711
 *
10712
 * Compile an union expression.
10713
 */
10714
10715
static void
10716
126k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10717
126k
    xmlXPathCompPathExpr(ctxt);
10718
126k
    CHECK_ERROR;
10719
121k
    SKIP_BLANKS;
10720
163k
    while (CUR == '|') {
10721
42.1k
  int op1 = ctxt->comp->last;
10722
42.1k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10723
10724
42.1k
  NEXT;
10725
42.1k
  SKIP_BLANKS;
10726
42.1k
  xmlXPathCompPathExpr(ctxt);
10727
10728
42.1k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10729
10730
42.1k
  SKIP_BLANKS;
10731
42.1k
    }
10732
121k
}
10733
10734
/**
10735
 * xmlXPathCompUnaryExpr:
10736
 * @ctxt:  the XPath Parser context
10737
 *
10738
 *  [27]   UnaryExpr ::=   UnionExpr
10739
 *                   | '-' UnaryExpr
10740
 *
10741
 * Compile an unary expression.
10742
 */
10743
10744
static void
10745
126k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10746
126k
    int minus = 0;
10747
126k
    int found = 0;
10748
10749
126k
    SKIP_BLANKS;
10750
146k
    while (CUR == '-') {
10751
19.4k
        minus = 1 - minus;
10752
19.4k
  found = 1;
10753
19.4k
  NEXT;
10754
19.4k
  SKIP_BLANKS;
10755
19.4k
    }
10756
10757
126k
    xmlXPathCompUnionExpr(ctxt);
10758
126k
    CHECK_ERROR;
10759
120k
    if (found) {
10760
9.87k
  if (minus)
10761
8.00k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10762
1.87k
  else
10763
1.87k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10764
9.87k
    }
10765
120k
}
10766
10767
/**
10768
 * xmlXPathCompMultiplicativeExpr:
10769
 * @ctxt:  the XPath Parser context
10770
 *
10771
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10772
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10773
 *                   | MultiplicativeExpr 'div' UnaryExpr
10774
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10775
 *  [34]   MultiplyOperator ::=   '*'
10776
 *
10777
 * Compile an Additive expression.
10778
 */
10779
10780
static void
10781
97.1k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10782
97.1k
    xmlXPathCompUnaryExpr(ctxt);
10783
97.1k
    CHECK_ERROR;
10784
91.1k
    SKIP_BLANKS;
10785
120k
    while ((CUR == '*') ||
10786
120k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10787
120k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10788
29.8k
  int op = -1;
10789
29.8k
  int op1 = ctxt->comp->last;
10790
10791
29.8k
        if (CUR == '*') {
10792
29.5k
      op = 0;
10793
29.5k
      NEXT;
10794
29.5k
  } else if (CUR == 'd') {
10795
119
      op = 1;
10796
119
      SKIP(3);
10797
158
  } else if (CUR == 'm') {
10798
158
      op = 2;
10799
158
      SKIP(3);
10800
158
  }
10801
29.8k
  SKIP_BLANKS;
10802
29.8k
        xmlXPathCompUnaryExpr(ctxt);
10803
29.8k
  CHECK_ERROR;
10804
29.4k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10805
29.4k
  SKIP_BLANKS;
10806
29.4k
    }
10807
91.1k
}
10808
10809
/**
10810
 * xmlXPathCompAdditiveExpr:
10811
 * @ctxt:  the XPath Parser context
10812
 *
10813
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10814
 *                   | AdditiveExpr '+' MultiplicativeExpr
10815
 *                   | AdditiveExpr '-' MultiplicativeExpr
10816
 *
10817
 * Compile an Additive expression.
10818
 */
10819
10820
static void
10821
79.3k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10822
10823
79.3k
    xmlXPathCompMultiplicativeExpr(ctxt);
10824
79.3k
    CHECK_ERROR;
10825
73.3k
    SKIP_BLANKS;
10826
90.7k
    while ((CUR == '+') || (CUR == '-')) {
10827
17.8k
  int plus;
10828
17.8k
  int op1 = ctxt->comp->last;
10829
10830
17.8k
        if (CUR == '+') plus = 1;
10831
14.6k
  else plus = 0;
10832
17.8k
  NEXT;
10833
17.8k
  SKIP_BLANKS;
10834
17.8k
        xmlXPathCompMultiplicativeExpr(ctxt);
10835
17.8k
  CHECK_ERROR;
10836
17.3k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10837
17.3k
  SKIP_BLANKS;
10838
17.3k
    }
10839
73.3k
}
10840
10841
/**
10842
 * xmlXPathCompRelationalExpr:
10843
 * @ctxt:  the XPath Parser context
10844
 *
10845
 *  [24]   RelationalExpr ::=   AdditiveExpr
10846
 *                 | RelationalExpr '<' AdditiveExpr
10847
 *                 | RelationalExpr '>' AdditiveExpr
10848
 *                 | RelationalExpr '<=' AdditiveExpr
10849
 *                 | RelationalExpr '>=' AdditiveExpr
10850
 *
10851
 *  A <= B > C is allowed ? Answer from James, yes with
10852
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10853
 *  which is basically what got implemented.
10854
 *
10855
 * Compile a Relational expression, then push the result
10856
 * on the stack
10857
 */
10858
10859
static void
10860
54.2k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10861
54.2k
    xmlXPathCompAdditiveExpr(ctxt);
10862
54.2k
    CHECK_ERROR;
10863
48.1k
    SKIP_BLANKS;
10864
72.9k
    while ((CUR == '<') || (CUR == '>')) {
10865
25.0k
  int inf, strict;
10866
25.0k
  int op1 = ctxt->comp->last;
10867
10868
25.0k
        if (CUR == '<') inf = 1;
10869
17.1k
  else inf = 0;
10870
25.0k
  if (NXT(1) == '=') strict = 0;
10871
19.3k
  else strict = 1;
10872
25.0k
  NEXT;
10873
25.0k
  if (!strict) NEXT;
10874
25.0k
  SKIP_BLANKS;
10875
25.0k
        xmlXPathCompAdditiveExpr(ctxt);
10876
25.0k
  CHECK_ERROR;
10877
24.7k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10878
24.7k
  SKIP_BLANKS;
10879
24.7k
    }
10880
48.1k
}
10881
10882
/**
10883
 * xmlXPathCompEqualityExpr:
10884
 * @ctxt:  the XPath Parser context
10885
 *
10886
 *  [23]   EqualityExpr ::=   RelationalExpr
10887
 *                 | EqualityExpr '=' RelationalExpr
10888
 *                 | EqualityExpr '!=' RelationalExpr
10889
 *
10890
 *  A != B != C is allowed ? Answer from James, yes with
10891
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10892
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10893
 *  which is basically what got implemented.
10894
 *
10895
 * Compile an Equality expression.
10896
 *
10897
 */
10898
static void
10899
31.9k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10900
31.9k
    xmlXPathCompRelationalExpr(ctxt);
10901
31.9k
    CHECK_ERROR;
10902
25.8k
    SKIP_BLANKS;
10903
47.8k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10904
22.2k
  int eq;
10905
22.2k
  int op1 = ctxt->comp->last;
10906
10907
22.2k
        if (CUR == '=') eq = 1;
10908
1.90k
  else eq = 0;
10909
22.2k
  NEXT;
10910
22.2k
  if (!eq) NEXT;
10911
22.2k
  SKIP_BLANKS;
10912
22.2k
        xmlXPathCompRelationalExpr(ctxt);
10913
22.2k
  CHECK_ERROR;
10914
21.9k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10915
21.9k
  SKIP_BLANKS;
10916
21.9k
    }
10917
25.8k
}
10918
10919
/**
10920
 * xmlXPathCompAndExpr:
10921
 * @ctxt:  the XPath Parser context
10922
 *
10923
 *  [22]   AndExpr ::=   EqualityExpr
10924
 *                 | AndExpr 'and' EqualityExpr
10925
 *
10926
 * Compile an AND expression.
10927
 *
10928
 */
10929
static void
10930
31.3k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10931
31.3k
    xmlXPathCompEqualityExpr(ctxt);
10932
31.3k
    CHECK_ERROR;
10933
25.1k
    SKIP_BLANKS;
10934
25.5k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10935
574
  int op1 = ctxt->comp->last;
10936
574
        SKIP(3);
10937
574
  SKIP_BLANKS;
10938
574
        xmlXPathCompEqualityExpr(ctxt);
10939
574
  CHECK_ERROR;
10940
443
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10941
443
  SKIP_BLANKS;
10942
443
    }
10943
25.1k
}
10944
10945
/**
10946
 * xmlXPathCompileExpr:
10947
 * @ctxt:  the XPath Parser context
10948
 *
10949
 *  [14]   Expr ::=   OrExpr
10950
 *  [21]   OrExpr ::=   AndExpr
10951
 *                 | OrExpr 'or' AndExpr
10952
 *
10953
 * Parse and compile an expression
10954
 */
10955
static void
10956
30.4k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10957
30.4k
    xmlXPathContextPtr xpctxt = ctxt->context;
10958
10959
30.4k
    if (xpctxt != NULL) {
10960
30.4k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10961
30.0k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10962
        /*
10963
         * Parsing a single '(' pushes about 10 functions on the call stack
10964
         * before recursing!
10965
         */
10966
30.0k
        xpctxt->depth += 10;
10967
30.0k
    }
10968
10969
30.0k
    xmlXPathCompAndExpr(ctxt);
10970
30.0k
    CHECK_ERROR;
10971
23.6k
    SKIP_BLANKS;
10972
24.9k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10973
1.37k
  int op1 = ctxt->comp->last;
10974
1.37k
        SKIP(2);
10975
1.37k
  SKIP_BLANKS;
10976
1.37k
        xmlXPathCompAndExpr(ctxt);
10977
1.37k
  CHECK_ERROR;
10978
1.30k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10979
1.30k
  SKIP_BLANKS;
10980
1.30k
    }
10981
23.5k
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10982
  /* more ops could be optimized too */
10983
  /*
10984
  * This is the main place to eliminate sorting for
10985
  * operations which don't require a sorted node-set.
10986
  * E.g. count().
10987
  */
10988
12.3k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10989
12.3k
    }
10990
10991
23.5k
    if (xpctxt != NULL)
10992
23.5k
        xpctxt->depth -= 10;
10993
23.5k
}
10994
10995
/**
10996
 * xmlXPathCompPredicate:
10997
 * @ctxt:  the XPath Parser context
10998
 * @filter:  act as a filter
10999
 *
11000
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
11001
 *  [9]   PredicateExpr ::=   Expr
11002
 *
11003
 * Compile a predicate expression
11004
 */
11005
static void
11006
14.5k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11007
14.5k
    int op1 = ctxt->comp->last;
11008
11009
14.5k
    SKIP_BLANKS;
11010
14.5k
    if (CUR != '[') {
11011
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11012
0
    }
11013
14.5k
    NEXT;
11014
14.5k
    SKIP_BLANKS;
11015
11016
14.5k
    ctxt->comp->last = -1;
11017
    /*
11018
    * This call to xmlXPathCompileExpr() will deactivate sorting
11019
    * of the predicate result.
11020
    * TODO: Sorting is still activated for filters, since I'm not
11021
    *  sure if needed. Normally sorting should not be needed, since
11022
    *  a filter can only diminish the number of items in a sequence,
11023
    *  but won't change its order; so if the initial sequence is sorted,
11024
    *  subsequent sorting is not needed.
11025
    */
11026
14.5k
    if (! filter)
11027
11.5k
  xmlXPathCompileExpr(ctxt, 0);
11028
3.03k
    else
11029
3.03k
  xmlXPathCompileExpr(ctxt, 1);
11030
14.5k
    CHECK_ERROR;
11031
11032
11.4k
    if (CUR != ']') {
11033
111
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11034
0
    }
11035
11036
11.3k
    if (filter)
11037
1.97k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11038
9.33k
    else
11039
9.33k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11040
11041
11.3k
    NEXT;
11042
11.3k
    SKIP_BLANKS;
11043
11.3k
}
11044
11045
/**
11046
 * xmlXPathCompNodeTest:
11047
 * @ctxt:  the XPath Parser context
11048
 * @test:  pointer to a xmlXPathTestVal
11049
 * @type:  pointer to a xmlXPathTypeVal
11050
 * @prefix:  placeholder for a possible name prefix
11051
 *
11052
 * [7] NodeTest ::=   NameTest
11053
 *        | NodeType '(' ')'
11054
 *        | 'processing-instruction' '(' Literal ')'
11055
 *
11056
 * [37] NameTest ::=  '*'
11057
 *        | NCName ':' '*'
11058
 *        | QName
11059
 * [38] NodeType ::= 'comment'
11060
 *       | 'text'
11061
 *       | 'processing-instruction'
11062
 *       | 'node'
11063
 *
11064
 * Returns the name found and updates @test, @type and @prefix appropriately
11065
 */
11066
static xmlChar *
11067
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11068
               xmlXPathTypeVal *type, xmlChar **prefix,
11069
182k
         xmlChar *name) {
11070
182k
    int blanks;
11071
11072
182k
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11073
0
  STRANGE;
11074
0
  return(NULL);
11075
0
    }
11076
182k
    *type = (xmlXPathTypeVal) 0;
11077
182k
    *test = (xmlXPathTestVal) 0;
11078
182k
    *prefix = NULL;
11079
182k
    SKIP_BLANKS;
11080
11081
182k
    if ((name == NULL) && (CUR == '*')) {
11082
  /*
11083
   * All elements
11084
   */
11085
71.8k
  NEXT;
11086
71.8k
  *test = NODE_TEST_ALL;
11087
71.8k
  return(NULL);
11088
71.8k
    }
11089
11090
110k
    if (name == NULL)
11091
3.44k
  name = xmlXPathParseNCName(ctxt);
11092
110k
    if (name == NULL) {
11093
377
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11094
0
    }
11095
11096
109k
    blanks = IS_BLANK_CH(CUR);
11097
109k
    SKIP_BLANKS;
11098
109k
    if (CUR == '(') {
11099
1.23k
  NEXT;
11100
  /*
11101
   * NodeType or PI search
11102
   */
11103
1.23k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11104
92
      *type = NODE_TYPE_COMMENT;
11105
1.13k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11106
755
      *type = NODE_TYPE_NODE;
11107
383
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11108
121
      *type = NODE_TYPE_PI;
11109
262
  else if (xmlStrEqual(name, BAD_CAST "text"))
11110
247
      *type = NODE_TYPE_TEXT;
11111
15
  else {
11112
15
      if (name != NULL)
11113
15
    xmlFree(name);
11114
15
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11115
0
  }
11116
11117
1.21k
  *test = NODE_TEST_TYPE;
11118
11119
1.21k
  SKIP_BLANKS;
11120
1.21k
  if (*type == NODE_TYPE_PI) {
11121
      /*
11122
       * Specific case: search a PI by name.
11123
       */
11124
121
      if (name != NULL)
11125
121
    xmlFree(name);
11126
121
      name = NULL;
11127
121
      if (CUR != ')') {
11128
111
    name = xmlXPathParseLiteral(ctxt);
11129
111
                if (name == NULL) {
11130
51
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11131
0
                }
11132
60
    *test = NODE_TEST_PI;
11133
60
    SKIP_BLANKS;
11134
60
      }
11135
121
  }
11136
1.16k
  if (CUR != ')') {
11137
42
      if (name != NULL)
11138
42
    xmlFree(name);
11139
42
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11140
0
  }
11141
1.12k
  NEXT;
11142
1.12k
  return(name);
11143
1.16k
    }
11144
108k
    *test = NODE_TEST_NAME;
11145
108k
    if ((!blanks) && (CUR == ':')) {
11146
1.44k
  NEXT;
11147
11148
  /*
11149
   * Since currently the parser context don't have a
11150
   * namespace list associated:
11151
   * The namespace name for this prefix can be computed
11152
   * only at evaluation time. The compilation is done
11153
   * outside of any context.
11154
   */
11155
#if 0
11156
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11157
  if (name != NULL)
11158
      xmlFree(name);
11159
  if (*prefix == NULL) {
11160
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11161
  }
11162
#else
11163
1.44k
  *prefix = name;
11164
1.44k
#endif
11165
11166
1.44k
  if (CUR == '*') {
11167
      /*
11168
       * All elements
11169
       */
11170
327
      NEXT;
11171
327
      *test = NODE_TEST_ALL;
11172
327
      return(NULL);
11173
327
  }
11174
11175
1.11k
  name = xmlXPathParseNCName(ctxt);
11176
1.11k
  if (name == NULL) {
11177
20
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11178
0
  }
11179
1.11k
    }
11180
108k
    return(name);
11181
108k
}
11182
11183
/**
11184
 * xmlXPathIsAxisName:
11185
 * @name:  a preparsed name token
11186
 *
11187
 * [6] AxisName ::=   'ancestor'
11188
 *                  | 'ancestor-or-self'
11189
 *                  | 'attribute'
11190
 *                  | 'child'
11191
 *                  | 'descendant'
11192
 *                  | 'descendant-or-self'
11193
 *                  | 'following'
11194
 *                  | 'following-sibling'
11195
 *                  | 'namespace'
11196
 *                  | 'parent'
11197
 *                  | 'preceding'
11198
 *                  | 'preceding-sibling'
11199
 *                  | 'self'
11200
 *
11201
 * Returns the axis or 0
11202
 */
11203
static xmlXPathAxisVal
11204
110k
xmlXPathIsAxisName(const xmlChar *name) {
11205
110k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11206
110k
    switch (name[0]) {
11207
25.2k
  case 'a':
11208
25.2k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11209
273
    ret = AXIS_ANCESTOR;
11210
25.2k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11211
152
    ret = AXIS_ANCESTOR_OR_SELF;
11212
25.2k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11213
58
    ret = AXIS_ATTRIBUTE;
11214
25.2k
      break;
11215
9.50k
  case 'c':
11216
9.50k
      if (xmlStrEqual(name, BAD_CAST "child"))
11217
253
    ret = AXIS_CHILD;
11218
9.50k
      break;
11219
3.44k
  case 'd':
11220
3.44k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11221
103
    ret = AXIS_DESCENDANT;
11222
3.44k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11223
38
    ret = AXIS_DESCENDANT_OR_SELF;
11224
3.44k
      break;
11225
1.18k
  case 'f':
11226
1.18k
      if (xmlStrEqual(name, BAD_CAST "following"))
11227
352
    ret = AXIS_FOLLOWING;
11228
1.18k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11229
50
    ret = AXIS_FOLLOWING_SIBLING;
11230
1.18k
      break;
11231
4.26k
  case 'n':
11232
4.26k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11233
1.28k
    ret = AXIS_NAMESPACE;
11234
4.26k
      break;
11235
4.21k
  case 'p':
11236
4.21k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11237
101
    ret = AXIS_PARENT;
11238
4.21k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11239
336
    ret = AXIS_PRECEDING;
11240
4.21k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11241
128
    ret = AXIS_PRECEDING_SIBLING;
11242
4.21k
      break;
11243
1.76k
  case 's':
11244
1.76k
      if (xmlStrEqual(name, BAD_CAST "self"))
11245
112
    ret = AXIS_SELF;
11246
1.76k
      break;
11247
110k
    }
11248
110k
    return(ret);
11249
110k
}
11250
11251
/**
11252
 * xmlXPathCompStep:
11253
 * @ctxt:  the XPath Parser context
11254
 *
11255
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11256
 *                  | AbbreviatedStep
11257
 *
11258
 * [12] AbbreviatedStep ::=   '.' | '..'
11259
 *
11260
 * [5] AxisSpecifier ::= AxisName '::'
11261
 *                  | AbbreviatedAxisSpecifier
11262
 *
11263
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11264
 *
11265
 * Modified for XPtr range support as:
11266
 *
11267
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11268
 *                     | AbbreviatedStep
11269
 *                     | 'range-to' '(' Expr ')' Predicate*
11270
 *
11271
 * Compile one step in a Location Path
11272
 * A location step of . is short for self::node(). This is
11273
 * particularly useful in conjunction with //. For example, the
11274
 * location path .//para is short for
11275
 * self::node()/descendant-or-self::node()/child::para
11276
 * and so will select all para descendant elements of the context
11277
 * node.
11278
 * Similarly, a location step of .. is short for parent::node().
11279
 * For example, ../title is short for parent::node()/child::title
11280
 * and so will select the title children of the parent of the context
11281
 * node.
11282
 */
11283
static void
11284
217k
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11285
#ifdef LIBXML_XPTR_LOCS_ENABLED
11286
    int rangeto = 0;
11287
    int op2 = -1;
11288
#endif
11289
11290
217k
    SKIP_BLANKS;
11291
217k
    if ((CUR == '.') && (NXT(1) == '.')) {
11292
3.77k
  SKIP(2);
11293
3.77k
  SKIP_BLANKS;
11294
3.77k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11295
3.77k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11296
213k
    } else if (CUR == '.') {
11297
28.9k
  NEXT;
11298
28.9k
  SKIP_BLANKS;
11299
184k
    } else {
11300
184k
  xmlChar *name = NULL;
11301
184k
  xmlChar *prefix = NULL;
11302
184k
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11303
184k
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11304
184k
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11305
184k
  int op1;
11306
11307
  /*
11308
   * The modification needed for XPointer change to the production
11309
   */
11310
#ifdef LIBXML_XPTR_LOCS_ENABLED
11311
  if (ctxt->xptr) {
11312
      name = xmlXPathParseNCName(ctxt);
11313
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11314
                op2 = ctxt->comp->last;
11315
    xmlFree(name);
11316
    SKIP_BLANKS;
11317
    if (CUR != '(') {
11318
        XP_ERROR(XPATH_EXPR_ERROR);
11319
    }
11320
    NEXT;
11321
    SKIP_BLANKS;
11322
11323
    xmlXPathCompileExpr(ctxt, 1);
11324
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11325
    CHECK_ERROR;
11326
11327
    SKIP_BLANKS;
11328
    if (CUR != ')') {
11329
        XP_ERROR(XPATH_EXPR_ERROR);
11330
    }
11331
    NEXT;
11332
    rangeto = 1;
11333
    goto eval_predicates;
11334
      }
11335
  }
11336
#endif
11337
184k
  if (CUR == '*') {
11338
66.1k
      axis = AXIS_CHILD;
11339
118k
  } else {
11340
118k
      if (name == NULL)
11341
118k
    name = xmlXPathParseNCName(ctxt);
11342
118k
      if (name != NULL) {
11343
110k
    axis = xmlXPathIsAxisName(name);
11344
110k
    if (axis != 0) {
11345
3.24k
        SKIP_BLANKS;
11346
3.24k
        if ((CUR == ':') && (NXT(1) == ':')) {
11347
2.15k
      SKIP(2);
11348
2.15k
      xmlFree(name);
11349
2.15k
      name = NULL;
11350
2.15k
        } else {
11351
      /* an element name can conflict with an axis one :-\ */
11352
1.09k
      axis = AXIS_CHILD;
11353
1.09k
        }
11354
107k
    } else {
11355
107k
        axis = AXIS_CHILD;
11356
107k
    }
11357
110k
      } else if (CUR == '@') {
11358
6.65k
    NEXT;
11359
6.65k
    axis = AXIS_ATTRIBUTE;
11360
6.65k
      } else {
11361
977
    axis = AXIS_CHILD;
11362
977
      }
11363
118k
  }
11364
11365
184k
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11366
2.76k
            xmlFree(name);
11367
2.76k
            return;
11368
2.76k
        }
11369
11370
182k
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11371
182k
  if (test == 0)
11372
392
      return;
11373
11374
181k
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11375
181k
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11376
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11377
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11378
0
      }
11379
0
  }
11380
#ifdef DEBUG_STEP
11381
  xmlGenericError(xmlGenericErrorContext,
11382
    "Basis : computing new set\n");
11383
#endif
11384
11385
#ifdef DEBUG_STEP
11386
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11387
  if (ctxt->value == NULL)
11388
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11389
  else if (ctxt->value->nodesetval == NULL)
11390
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11391
  else
11392
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11393
#endif
11394
11395
#ifdef LIBXML_XPTR_LOCS_ENABLED
11396
eval_predicates:
11397
#endif
11398
181k
  op1 = ctxt->comp->last;
11399
181k
  ctxt->comp->last = -1;
11400
11401
181k
  SKIP_BLANKS;
11402
193k
  while (CUR == '[') {
11403
11.5k
      xmlXPathCompPredicate(ctxt, 0);
11404
11.5k
  }
11405
11406
#ifdef LIBXML_XPTR_LOCS_ENABLED
11407
  if (rangeto) {
11408
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11409
  } else
11410
#endif
11411
181k
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11412
181k
                           test, type, (void *)prefix, (void *)name) == -1) {
11413
0
            xmlFree(prefix);
11414
0
            xmlFree(name);
11415
0
        }
11416
181k
    }
11417
#ifdef DEBUG_STEP
11418
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11419
    if (ctxt->value == NULL)
11420
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11421
    else if (ctxt->value->nodesetval == NULL)
11422
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11423
    else
11424
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11425
    ctxt->value->nodesetval);
11426
#endif
11427
217k
}
11428
11429
/**
11430
 * xmlXPathCompRelativeLocationPath:
11431
 * @ctxt:  the XPath Parser context
11432
 *
11433
 *  [3]   RelativeLocationPath ::=   Step
11434
 *                     | RelativeLocationPath '/' Step
11435
 *                     | AbbreviatedRelativeLocationPath
11436
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11437
 *
11438
 * Compile a relative location path.
11439
 */
11440
static void
11441
xmlXPathCompRelativeLocationPath
11442
137k
(xmlXPathParserContextPtr ctxt) {
11443
137k
    SKIP_BLANKS;
11444
137k
    if ((CUR == '/') && (NXT(1) == '/')) {
11445
2.20k
  SKIP(2);
11446
2.20k
  SKIP_BLANKS;
11447
2.20k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11448
2.20k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11449
135k
    } else if (CUR == '/') {
11450
6.59k
      NEXT;
11451
6.59k
  SKIP_BLANKS;
11452
6.59k
    }
11453
137k
    xmlXPathCompStep(ctxt);
11454
137k
    CHECK_ERROR;
11455
134k
    SKIP_BLANKS;
11456
214k
    while (CUR == '/') {
11457
79.5k
  if ((CUR == '/') && (NXT(1) == '/')) {
11458
22.5k
      SKIP(2);
11459
22.5k
      SKIP_BLANKS;
11460
22.5k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11461
22.5k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11462
22.5k
      xmlXPathCompStep(ctxt);
11463
57.0k
  } else if (CUR == '/') {
11464
57.0k
      NEXT;
11465
57.0k
      SKIP_BLANKS;
11466
57.0k
      xmlXPathCompStep(ctxt);
11467
57.0k
  }
11468
79.5k
  SKIP_BLANKS;
11469
79.5k
    }
11470
134k
}
11471
11472
/**
11473
 * xmlXPathCompLocationPath:
11474
 * @ctxt:  the XPath Parser context
11475
 *
11476
 *  [1]   LocationPath ::=   RelativeLocationPath
11477
 *                     | AbsoluteLocationPath
11478
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11479
 *                     | AbbreviatedAbsoluteLocationPath
11480
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11481
 *                           '//' RelativeLocationPath
11482
 *
11483
 * Compile a location path
11484
 *
11485
 * // is short for /descendant-or-self::node()/. For example,
11486
 * //para is short for /descendant-or-self::node()/child::para and
11487
 * so will select any para element in the document (even a para element
11488
 * that is a document element will be selected by //para since the
11489
 * document element node is a child of the root node); div//para is
11490
 * short for div/descendant-or-self::node()/child::para and so will
11491
 * select all para descendants of div children.
11492
 */
11493
static void
11494
142k
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11495
142k
    SKIP_BLANKS;
11496
142k
    if (CUR != '/') {
11497
81.4k
        xmlXPathCompRelativeLocationPath(ctxt);
11498
81.4k
    } else {
11499
122k
  while (CUR == '/') {
11500
61.9k
      if ((CUR == '/') && (NXT(1) == '/')) {
11501
27.7k
    SKIP(2);
11502
27.7k
    SKIP_BLANKS;
11503
27.7k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11504
27.7k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11505
27.7k
    xmlXPathCompRelativeLocationPath(ctxt);
11506
34.1k
      } else if (CUR == '/') {
11507
34.1k
    NEXT;
11508
34.1k
    SKIP_BLANKS;
11509
34.1k
    if ((CUR != 0 ) &&
11510
34.1k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11511
33.8k
         (CUR == '@') || (CUR == '*')))
11512
27.2k
        xmlXPathCompRelativeLocationPath(ctxt);
11513
34.1k
      }
11514
61.9k
      CHECK_ERROR;
11515
61.9k
  }
11516
61.5k
    }
11517
142k
}
11518
11519
/************************************************************************
11520
 *                  *
11521
 *    XPath precompiled expression evaluation     *
11522
 *                  *
11523
 ************************************************************************/
11524
11525
static int
11526
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11527
11528
#ifdef DEBUG_STEP
11529
static void
11530
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11531
        int nbNodes)
11532
{
11533
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11534
    switch (op->value) {
11535
        case AXIS_ANCESTOR:
11536
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11537
            break;
11538
        case AXIS_ANCESTOR_OR_SELF:
11539
            xmlGenericError(xmlGenericErrorContext,
11540
                            "axis 'ancestors-or-self' ");
11541
            break;
11542
        case AXIS_ATTRIBUTE:
11543
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11544
            break;
11545
        case AXIS_CHILD:
11546
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11547
            break;
11548
        case AXIS_DESCENDANT:
11549
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11550
            break;
11551
        case AXIS_DESCENDANT_OR_SELF:
11552
            xmlGenericError(xmlGenericErrorContext,
11553
                            "axis 'descendant-or-self' ");
11554
            break;
11555
        case AXIS_FOLLOWING:
11556
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11557
            break;
11558
        case AXIS_FOLLOWING_SIBLING:
11559
            xmlGenericError(xmlGenericErrorContext,
11560
                            "axis 'following-siblings' ");
11561
            break;
11562
        case AXIS_NAMESPACE:
11563
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11564
            break;
11565
        case AXIS_PARENT:
11566
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11567
            break;
11568
        case AXIS_PRECEDING:
11569
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11570
            break;
11571
        case AXIS_PRECEDING_SIBLING:
11572
            xmlGenericError(xmlGenericErrorContext,
11573
                            "axis 'preceding-sibling' ");
11574
            break;
11575
        case AXIS_SELF:
11576
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11577
            break;
11578
    }
11579
    xmlGenericError(xmlGenericErrorContext,
11580
  " context contains %d nodes\n", nbNodes);
11581
    switch (op->value2) {
11582
        case NODE_TEST_NONE:
11583
            xmlGenericError(xmlGenericErrorContext,
11584
                            "           searching for none !!!\n");
11585
            break;
11586
        case NODE_TEST_TYPE:
11587
            xmlGenericError(xmlGenericErrorContext,
11588
                            "           searching for type %d\n", op->value3);
11589
            break;
11590
        case NODE_TEST_PI:
11591
            xmlGenericError(xmlGenericErrorContext,
11592
                            "           searching for PI !!!\n");
11593
            break;
11594
        case NODE_TEST_ALL:
11595
            xmlGenericError(xmlGenericErrorContext,
11596
                            "           searching for *\n");
11597
            break;
11598
        case NODE_TEST_NS:
11599
            xmlGenericError(xmlGenericErrorContext,
11600
                            "           searching for namespace %s\n",
11601
                            op->value5);
11602
            break;
11603
        case NODE_TEST_NAME:
11604
            xmlGenericError(xmlGenericErrorContext,
11605
                            "           searching for name %s\n", op->value5);
11606
            if (op->value4)
11607
                xmlGenericError(xmlGenericErrorContext,
11608
                                "           with namespace %s\n", op->value4);
11609
            break;
11610
    }
11611
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11612
}
11613
#endif /* DEBUG_STEP */
11614
11615
/**
11616
 * xmlXPathNodeSetFilter:
11617
 * @ctxt:  the XPath Parser context
11618
 * @set: the node set to filter
11619
 * @filterOpIndex: the index of the predicate/filter op
11620
 * @minPos: minimum position in the filtered set (1-based)
11621
 * @maxPos: maximum position in the filtered set (1-based)
11622
 * @hasNsNodes: true if the node set may contain namespace nodes
11623
 *
11624
 * Filter a node set, keeping only nodes for which the predicate expression
11625
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11626
 * filtered result.
11627
 */
11628
static void
11629
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11630
          xmlNodeSetPtr set,
11631
          int filterOpIndex,
11632
                      int minPos, int maxPos,
11633
          int hasNsNodes)
11634
895k
{
11635
895k
    xmlXPathContextPtr xpctxt;
11636
895k
    xmlNodePtr oldnode;
11637
895k
    xmlDocPtr olddoc;
11638
895k
    xmlXPathStepOpPtr filterOp;
11639
895k
    int oldcs, oldpp;
11640
895k
    int i, j, pos;
11641
11642
895k
    if ((set == NULL) || (set->nodeNr == 0))
11643
63.7k
        return;
11644
11645
    /*
11646
    * Check if the node set contains a sufficient number of nodes for
11647
    * the requested range.
11648
    */
11649
831k
    if (set->nodeNr < minPos) {
11650
44.3k
        xmlXPathNodeSetClear(set, hasNsNodes);
11651
44.3k
        return;
11652
44.3k
    }
11653
11654
787k
    xpctxt = ctxt->context;
11655
787k
    oldnode = xpctxt->node;
11656
787k
    olddoc = xpctxt->doc;
11657
787k
    oldcs = xpctxt->contextSize;
11658
787k
    oldpp = xpctxt->proximityPosition;
11659
787k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11660
11661
787k
    xpctxt->contextSize = set->nodeNr;
11662
11663
2.97M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11664
2.41M
        xmlNodePtr node = set->nodeTab[i];
11665
2.41M
        int res;
11666
11667
2.41M
        xpctxt->node = node;
11668
2.41M
        xpctxt->proximityPosition = i + 1;
11669
11670
        /*
11671
        * Also set the xpath document in case things like
11672
        * key() are evaluated in the predicate.
11673
        *
11674
        * TODO: Get real doc for namespace nodes.
11675
        */
11676
2.41M
        if ((node->type != XML_NAMESPACE_DECL) &&
11677
2.41M
            (node->doc != NULL))
11678
2.39M
            xpctxt->doc = node->doc;
11679
11680
2.41M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11681
11682
2.41M
        if (ctxt->error != XPATH_EXPRESSION_OK)
11683
2.18k
            break;
11684
2.41M
        if (res < 0) {
11685
            /* Shouldn't happen */
11686
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11687
0
            break;
11688
0
        }
11689
11690
2.41M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11691
604k
            if (i != j) {
11692
47.9k
                set->nodeTab[j] = node;
11693
47.9k
                set->nodeTab[i] = NULL;
11694
47.9k
            }
11695
11696
604k
            j += 1;
11697
1.80M
        } else {
11698
            /* Remove the entry from the initial node set. */
11699
1.80M
            set->nodeTab[i] = NULL;
11700
1.80M
            if (node->type == XML_NAMESPACE_DECL)
11701
3.97k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11702
1.80M
        }
11703
11704
2.41M
        if (res != 0) {
11705
623k
            if (pos == maxPos) {
11706
219k
                i += 1;
11707
219k
                break;
11708
219k
            }
11709
11710
403k
            pos += 1;
11711
403k
        }
11712
2.41M
    }
11713
11714
    /* Free remaining nodes. */
11715
787k
    if (hasNsNodes) {
11716
59.3k
        for (; i < set->nodeNr; i++) {
11717
24.6k
            xmlNodePtr node = set->nodeTab[i];
11718
24.6k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11719
22.8k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11720
24.6k
        }
11721
34.6k
    }
11722
11723
787k
    set->nodeNr = j;
11724
11725
    /* If too many elements were removed, shrink table to preserve memory. */
11726
787k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11727
787k
        (set->nodeNr < set->nodeMax / 2)) {
11728
19.0k
        xmlNodePtr *tmp;
11729
19.0k
        int nodeMax = set->nodeNr;
11730
11731
19.0k
        if (nodeMax < XML_NODESET_DEFAULT)
11732
18.7k
            nodeMax = XML_NODESET_DEFAULT;
11733
19.0k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11734
19.0k
                nodeMax * sizeof(xmlNodePtr));
11735
19.0k
        if (tmp == NULL) {
11736
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11737
19.0k
        } else {
11738
19.0k
            set->nodeTab = tmp;
11739
19.0k
            set->nodeMax = nodeMax;
11740
19.0k
        }
11741
19.0k
    }
11742
11743
787k
    xpctxt->node = oldnode;
11744
787k
    xpctxt->doc = olddoc;
11745
787k
    xpctxt->contextSize = oldcs;
11746
787k
    xpctxt->proximityPosition = oldpp;
11747
787k
}
11748
11749
#ifdef LIBXML_XPTR_LOCS_ENABLED
11750
/**
11751
 * xmlXPathLocationSetFilter:
11752
 * @ctxt:  the XPath Parser context
11753
 * @locset: the location set to filter
11754
 * @filterOpIndex: the index of the predicate/filter op
11755
 * @minPos: minimum position in the filtered set (1-based)
11756
 * @maxPos: maximum position in the filtered set (1-based)
11757
 *
11758
 * Filter a location set, keeping only nodes for which the predicate
11759
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11760
 * in the filtered result.
11761
 */
11762
static void
11763
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11764
              xmlLocationSetPtr locset,
11765
              int filterOpIndex,
11766
                          int minPos, int maxPos)
11767
{
11768
    xmlXPathContextPtr xpctxt;
11769
    xmlNodePtr oldnode;
11770
    xmlDocPtr olddoc;
11771
    xmlXPathStepOpPtr filterOp;
11772
    int oldcs, oldpp;
11773
    int i, j, pos;
11774
11775
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11776
        return;
11777
11778
    xpctxt = ctxt->context;
11779
    oldnode = xpctxt->node;
11780
    olddoc = xpctxt->doc;
11781
    oldcs = xpctxt->contextSize;
11782
    oldpp = xpctxt->proximityPosition;
11783
    filterOp = &ctxt->comp->steps[filterOpIndex];
11784
11785
    xpctxt->contextSize = locset->locNr;
11786
11787
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11788
        xmlNodePtr contextNode = locset->locTab[i]->user;
11789
        int res;
11790
11791
        xpctxt->node = contextNode;
11792
        xpctxt->proximityPosition = i + 1;
11793
11794
        /*
11795
        * Also set the xpath document in case things like
11796
        * key() are evaluated in the predicate.
11797
        *
11798
        * TODO: Get real doc for namespace nodes.
11799
        */
11800
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11801
            (contextNode->doc != NULL))
11802
            xpctxt->doc = contextNode->doc;
11803
11804
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11805
11806
        if (ctxt->error != XPATH_EXPRESSION_OK)
11807
            break;
11808
        if (res < 0) {
11809
            /* Shouldn't happen */
11810
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11811
            break;
11812
        }
11813
11814
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11815
            if (i != j) {
11816
                locset->locTab[j] = locset->locTab[i];
11817
                locset->locTab[i] = NULL;
11818
            }
11819
11820
            j += 1;
11821
        } else {
11822
            /* Remove the entry from the initial location set. */
11823
            xmlXPathFreeObject(locset->locTab[i]);
11824
            locset->locTab[i] = NULL;
11825
        }
11826
11827
        if (res != 0) {
11828
            if (pos == maxPos) {
11829
                i += 1;
11830
                break;
11831
            }
11832
11833
            pos += 1;
11834
        }
11835
    }
11836
11837
    /* Free remaining nodes. */
11838
    for (; i < locset->locNr; i++)
11839
        xmlXPathFreeObject(locset->locTab[i]);
11840
11841
    locset->locNr = j;
11842
11843
    /* If too many elements were removed, shrink table to preserve memory. */
11844
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11845
        (locset->locNr < locset->locMax / 2)) {
11846
        xmlXPathObjectPtr *tmp;
11847
        int locMax = locset->locNr;
11848
11849
        if (locMax < XML_NODESET_DEFAULT)
11850
            locMax = XML_NODESET_DEFAULT;
11851
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11852
                locMax * sizeof(xmlXPathObjectPtr));
11853
        if (tmp == NULL) {
11854
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11855
        } else {
11856
            locset->locTab = tmp;
11857
            locset->locMax = locMax;
11858
        }
11859
    }
11860
11861
    xpctxt->node = oldnode;
11862
    xpctxt->doc = olddoc;
11863
    xpctxt->contextSize = oldcs;
11864
    xpctxt->proximityPosition = oldpp;
11865
}
11866
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11867
11868
/**
11869
 * xmlXPathCompOpEvalPredicate:
11870
 * @ctxt:  the XPath Parser context
11871
 * @op: the predicate op
11872
 * @set: the node set to filter
11873
 * @minPos: minimum position in the filtered set (1-based)
11874
 * @maxPos: maximum position in the filtered set (1-based)
11875
 * @hasNsNodes: true if the node set may contain namespace nodes
11876
 *
11877
 * Filter a node set, keeping only nodes for which the sequence of predicate
11878
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11879
 * in the filtered result.
11880
 */
11881
static void
11882
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11883
          xmlXPathStepOpPtr op,
11884
          xmlNodeSetPtr set,
11885
                            int minPos, int maxPos,
11886
          int hasNsNodes)
11887
824k
{
11888
824k
    if (op->ch1 != -1) {
11889
40.6k
  xmlXPathCompExprPtr comp = ctxt->comp;
11890
  /*
11891
  * Process inner predicates first.
11892
  */
11893
40.6k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11894
0
            xmlGenericError(xmlGenericErrorContext,
11895
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11896
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11897
0
  }
11898
40.6k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11899
40.6k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11900
40.6k
        ctxt->context->depth += 1;
11901
40.6k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11902
40.6k
                                    1, set->nodeNr, hasNsNodes);
11903
40.6k
        ctxt->context->depth -= 1;
11904
40.6k
  CHECK_ERROR;
11905
40.6k
    }
11906
11907
824k
    if (op->ch2 != -1)
11908
824k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11909
824k
}
11910
11911
static int
11912
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11913
          xmlXPathStepOpPtr op,
11914
          int *maxPos)
11915
370k
{
11916
11917
370k
    xmlXPathStepOpPtr exprOp;
11918
11919
    /*
11920
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11921
    */
11922
11923
    /*
11924
    * If not -1, then ch1 will point to:
11925
    * 1) For predicates (XPATH_OP_PREDICATE):
11926
    *    - an inner predicate operator
11927
    * 2) For filters (XPATH_OP_FILTER):
11928
    *    - an inner filter operator OR
11929
    *    - an expression selecting the node set.
11930
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11931
    */
11932
370k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11933
0
  return(0);
11934
11935
370k
    if (op->ch2 != -1) {
11936
370k
  exprOp = &ctxt->comp->steps[op->ch2];
11937
370k
    } else
11938
0
  return(0);
11939
11940
370k
    if ((exprOp != NULL) &&
11941
370k
  (exprOp->op == XPATH_OP_VALUE) &&
11942
370k
  (exprOp->value4 != NULL) &&
11943
370k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11944
135k
    {
11945
135k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11946
11947
  /*
11948
  * We have a "[n]" predicate here.
11949
  * TODO: Unfortunately this simplistic test here is not
11950
  * able to detect a position() predicate in compound
11951
  * expressions like "[@attr = 'a" and position() = 1],
11952
  * and even not the usage of position() in
11953
  * "[position() = 1]"; thus - obviously - a position-range,
11954
  * like it "[position() < 5]", is also not detected.
11955
  * Maybe we could rewrite the AST to ease the optimization.
11956
  */
11957
11958
135k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11959
133k
      *maxPos = (int) floatval;
11960
133k
            if (floatval == (double) *maxPos)
11961
133k
                return(1);
11962
133k
        }
11963
135k
    }
11964
237k
    return(0);
11965
370k
}
11966
11967
static int
11968
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11969
                           xmlXPathStepOpPtr op,
11970
         xmlNodePtr * first, xmlNodePtr * last,
11971
         int toBool)
11972
19.6M
{
11973
11974
19.6M
#define XP_TEST_HIT \
11975
77.9M
    if (hasAxisRange != 0) { \
11976
99.2k
  if (++pos == maxPos) { \
11977
48.9k
      if (addNode(seq, cur) < 0) \
11978
48.9k
          ctxt->error = XPATH_MEMORY_ERROR; \
11979
48.9k
      goto axis_range_end; } \
11980
77.8M
    } else { \
11981
77.8M
  if (addNode(seq, cur) < 0) \
11982
77.8M
      ctxt->error = XPATH_MEMORY_ERROR; \
11983
77.8M
  if (breakOnFirstHit) goto first_hit; }
11984
11985
19.6M
#define XP_TEST_HIT_NS \
11986
19.6M
    if (hasAxisRange != 0) { \
11987
52.4k
  if (++pos == maxPos) { \
11988
46.1k
      hasNsNodes = 1; \
11989
46.1k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11990
46.1k
          ctxt->error = XPATH_MEMORY_ERROR; \
11991
46.1k
  goto axis_range_end; } \
11992
892k
    } else { \
11993
892k
  hasNsNodes = 1; \
11994
892k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11995
892k
      ctxt->error = XPATH_MEMORY_ERROR; \
11996
892k
  if (breakOnFirstHit) goto first_hit; }
11997
11998
19.6M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999
19.6M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000
19.6M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001
19.6M
    const xmlChar *prefix = op->value4;
12002
19.6M
    const xmlChar *name = op->value5;
12003
19.6M
    const xmlChar *URI = NULL;
12004
12005
#ifdef DEBUG_STEP
12006
    int nbMatches = 0, prevMatches = 0;
12007
#endif
12008
19.6M
    int total = 0, hasNsNodes = 0;
12009
    /* The popped object holding the context nodes */
12010
19.6M
    xmlXPathObjectPtr obj;
12011
    /* The set of context nodes for the node tests */
12012
19.6M
    xmlNodeSetPtr contextSeq;
12013
19.6M
    int contextIdx;
12014
19.6M
    xmlNodePtr contextNode;
12015
    /* The final resulting node set wrt to all context nodes */
12016
19.6M
    xmlNodeSetPtr outSeq;
12017
    /*
12018
    * The temporary resulting node set wrt 1 context node.
12019
    * Used to feed predicate evaluation.
12020
    */
12021
19.6M
    xmlNodeSetPtr seq;
12022
19.6M
    xmlNodePtr cur;
12023
    /* First predicate operator */
12024
19.6M
    xmlXPathStepOpPtr predOp;
12025
19.6M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12026
19.6M
    int hasPredicateRange, hasAxisRange, pos;
12027
19.6M
    int breakOnFirstHit;
12028
12029
19.6M
    xmlXPathTraversalFunction next = NULL;
12030
19.6M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12031
19.6M
    xmlXPathNodeSetMergeFunction mergeAndClear;
12032
19.6M
    xmlNodePtr oldContextNode;
12033
19.6M
    xmlXPathContextPtr xpctxt = ctxt->context;
12034
12035
12036
19.6M
    CHECK_TYPE0(XPATH_NODESET);
12037
19.6M
    obj = valuePop(ctxt);
12038
    /*
12039
    * Setup namespaces.
12040
    */
12041
19.6M
    if (prefix != NULL) {
12042
54.1k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12043
54.1k
        if (URI == NULL) {
12044
88
      xmlXPathReleaseObject(xpctxt, obj);
12045
88
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12046
0
  }
12047
54.1k
    }
12048
    /*
12049
    * Setup axis.
12050
    *
12051
    * MAYBE FUTURE TODO: merging optimizations:
12052
    * - If the nodes to be traversed wrt to the initial nodes and
12053
    *   the current axis cannot overlap, then we could avoid searching
12054
    *   for duplicates during the merge.
12055
    *   But the question is how/when to evaluate if they cannot overlap.
12056
    *   Example: if we know that for two initial nodes, the one is
12057
    *   not in the ancestor-or-self axis of the other, then we could safely
12058
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12059
    *   the descendant-or-self axis.
12060
    */
12061
19.6M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12062
19.6M
    switch (axis) {
12063
24.9k
        case AXIS_ANCESTOR:
12064
24.9k
            first = NULL;
12065
24.9k
            next = xmlXPathNextAncestor;
12066
24.9k
            break;
12067
8.35k
        case AXIS_ANCESTOR_OR_SELF:
12068
8.35k
            first = NULL;
12069
8.35k
            next = xmlXPathNextAncestorOrSelf;
12070
8.35k
            break;
12071
863k
        case AXIS_ATTRIBUTE:
12072
863k
            first = NULL;
12073
863k
      last = NULL;
12074
863k
            next = xmlXPathNextAttribute;
12075
863k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12076
863k
            break;
12077
14.4M
        case AXIS_CHILD:
12078
14.4M
      last = NULL;
12079
14.4M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12080
14.4M
    (type == NODE_TYPE_NODE))
12081
14.3M
      {
12082
    /*
12083
    * Optimization if an element node type is 'element'.
12084
    */
12085
14.3M
    next = xmlXPathNextChildElement;
12086
14.3M
      } else
12087
32.3k
    next = xmlXPathNextChild;
12088
14.4M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12089
14.4M
            break;
12090
1.93M
        case AXIS_DESCENDANT:
12091
1.93M
      last = NULL;
12092
1.93M
            next = xmlXPathNextDescendant;
12093
1.93M
            break;
12094
1.77M
        case AXIS_DESCENDANT_OR_SELF:
12095
1.77M
      last = NULL;
12096
1.77M
            next = xmlXPathNextDescendantOrSelf;
12097
1.77M
            break;
12098
123k
        case AXIS_FOLLOWING:
12099
123k
      last = NULL;
12100
123k
            next = xmlXPathNextFollowing;
12101
123k
            break;
12102
10.2k
        case AXIS_FOLLOWING_SIBLING:
12103
10.2k
      last = NULL;
12104
10.2k
            next = xmlXPathNextFollowingSibling;
12105
10.2k
            break;
12106
70.3k
        case AXIS_NAMESPACE:
12107
70.3k
            first = NULL;
12108
70.3k
      last = NULL;
12109
70.3k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12110
70.3k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12111
70.3k
            break;
12112
440k
        case AXIS_PARENT:
12113
440k
            first = NULL;
12114
440k
            next = xmlXPathNextParent;
12115
440k
            break;
12116
7.51k
        case AXIS_PRECEDING:
12117
7.51k
            first = NULL;
12118
7.51k
            next = xmlXPathNextPrecedingInternal;
12119
7.51k
            break;
12120
3.40k
        case AXIS_PRECEDING_SIBLING:
12121
3.40k
            first = NULL;
12122
3.40k
            next = xmlXPathNextPrecedingSibling;
12123
3.40k
            break;
12124
1.07k
        case AXIS_SELF:
12125
1.07k
            first = NULL;
12126
1.07k
      last = NULL;
12127
1.07k
            next = xmlXPathNextSelf;
12128
1.07k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12129
1.07k
            break;
12130
19.6M
    }
12131
12132
#ifdef DEBUG_STEP
12133
    xmlXPathDebugDumpStepAxis(op,
12134
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12135
#endif
12136
12137
19.6M
    if (next == NULL) {
12138
0
  xmlXPathReleaseObject(xpctxt, obj);
12139
0
        return(0);
12140
0
    }
12141
19.6M
    contextSeq = obj->nodesetval;
12142
19.6M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12143
4.39M
  xmlXPathReleaseObject(xpctxt, obj);
12144
4.39M
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12145
4.39M
        return(0);
12146
4.39M
    }
12147
    /*
12148
    * Predicate optimization ---------------------------------------------
12149
    * If this step has a last predicate, which contains a position(),
12150
    * then we'll optimize (although not exactly "position()", but only
12151
    * the  short-hand form, i.e., "[n]".
12152
    *
12153
    * Example - expression "/foo[parent::bar][1]":
12154
    *
12155
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12156
    *   ROOT                               -- op->ch1
12157
    *   PREDICATE                          -- op->ch2 (predOp)
12158
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12159
    *       SORT
12160
    *         COLLECT  'parent' 'name' 'node' bar
12161
    *           NODE
12162
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12163
    *
12164
    */
12165
15.2M
    maxPos = 0;
12166
15.2M
    predOp = NULL;
12167
15.2M
    hasPredicateRange = 0;
12168
15.2M
    hasAxisRange = 0;
12169
15.2M
    if (op->ch2 != -1) {
12170
  /*
12171
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12172
  */
12173
370k
  predOp = &ctxt->comp->steps[op->ch2];
12174
370k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12175
133k
      if (predOp->ch1 != -1) {
12176
    /*
12177
    * Use the next inner predicate operator.
12178
    */
12179
26.9k
    predOp = &ctxt->comp->steps[predOp->ch1];
12180
26.9k
    hasPredicateRange = 1;
12181
106k
      } else {
12182
    /*
12183
    * There's no other predicate than the [n] predicate.
12184
    */
12185
106k
    predOp = NULL;
12186
106k
    hasAxisRange = 1;
12187
106k
      }
12188
133k
  }
12189
370k
    }
12190
15.2M
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12191
    /*
12192
    * Axis traversal -----------------------------------------------------
12193
    */
12194
    /*
12195
     * 2.3 Node Tests
12196
     *  - For the attribute axis, the principal node type is attribute.
12197
     *  - For the namespace axis, the principal node type is namespace.
12198
     *  - For other axes, the principal node type is element.
12199
     *
12200
     * A node test * is true for any node of the
12201
     * principal node type. For example, child::* will
12202
     * select all element children of the context node
12203
     */
12204
15.2M
    oldContextNode = xpctxt->node;
12205
15.2M
    addNode = xmlXPathNodeSetAddUnique;
12206
15.2M
    outSeq = NULL;
12207
15.2M
    seq = NULL;
12208
15.2M
    contextNode = NULL;
12209
15.2M
    contextIdx = 0;
12210
12211
12212
67.1M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12213
67.1M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12214
52.0M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12215
12216
52.0M
  if (seq == NULL) {
12217
16.4M
      seq = xmlXPathNodeSetCreate(NULL);
12218
16.4M
      if (seq == NULL) {
12219
                /* TODO: Propagate memory error. */
12220
0
    total = 0;
12221
0
    goto error;
12222
0
      }
12223
16.4M
  }
12224
  /*
12225
  * Traverse the axis and test the nodes.
12226
  */
12227
52.0M
  pos = 0;
12228
52.0M
  cur = NULL;
12229
52.0M
  hasNsNodes = 0;
12230
196M
        do {
12231
196M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12232
326
                goto error;
12233
12234
196M
            cur = next(ctxt, cur);
12235
196M
            if (cur == NULL)
12236
51.7M
                break;
12237
12238
      /*
12239
      * QUESTION TODO: What does the "first" and "last" stuff do?
12240
      */
12241
144M
            if ((first != NULL) && (*first != NULL)) {
12242
52.8k
    if (*first == cur)
12243
4.67k
        break;
12244
48.1k
    if (((total % 256) == 0) &&
12245
48.1k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12246
48.1k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12247
#else
12248
        (xmlXPathCmpNodes(*first, cur) >= 0))
12249
#endif
12250
37.0k
    {
12251
37.0k
        break;
12252
37.0k
    }
12253
48.1k
      }
12254
144M
      if ((last != NULL) && (*last != NULL)) {
12255
0
    if (*last == cur)
12256
0
        break;
12257
0
    if (((total % 256) == 0) &&
12258
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12259
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12260
#else
12261
        (xmlXPathCmpNodes(cur, *last) >= 0))
12262
#endif
12263
0
    {
12264
0
        break;
12265
0
    }
12266
0
      }
12267
12268
144M
            total++;
12269
12270
#ifdef DEBUG_STEP
12271
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12272
#endif
12273
12274
144M
      switch (test) {
12275
0
                case NODE_TEST_NONE:
12276
0
        total = 0;
12277
0
                    STRANGE
12278
0
        goto error;
12279
54.5M
                case NODE_TEST_TYPE:
12280
54.5M
        if (type == NODE_TYPE_NODE) {
12281
54.5M
      switch (cur->type) {
12282
1.12M
          case XML_DOCUMENT_NODE:
12283
1.12M
          case XML_HTML_DOCUMENT_NODE:
12284
21.4M
          case XML_ELEMENT_NODE:
12285
21.4M
          case XML_ATTRIBUTE_NODE:
12286
23.4M
          case XML_PI_NODE:
12287
25.7M
          case XML_COMMENT_NODE:
12288
27.2M
          case XML_CDATA_SECTION_NODE:
12289
54.5M
          case XML_TEXT_NODE:
12290
54.5M
        XP_TEST_HIT
12291
54.5M
        break;
12292
54.5M
          case XML_NAMESPACE_DECL: {
12293
27.4k
        if (axis == AXIS_NAMESPACE) {
12294
1.29k
            XP_TEST_HIT_NS
12295
26.1k
        } else {
12296
26.1k
                              hasNsNodes = 1;
12297
26.1k
            XP_TEST_HIT
12298
26.1k
        }
12299
27.4k
        break;
12300
27.4k
                            }
12301
27.4k
          default:
12302
0
        break;
12303
54.5M
      }
12304
54.5M
        } else if (cur->type == (xmlElementType) type) {
12305
18.0k
      if (cur->type == XML_NAMESPACE_DECL)
12306
0
          XP_TEST_HIT_NS
12307
18.0k
      else
12308
18.0k
          XP_TEST_HIT
12309
18.0k
        } else if ((type == NODE_TYPE_TEXT) &&
12310
6.35k
       (cur->type == XML_CDATA_SECTION_NODE))
12311
2.59k
        {
12312
2.59k
      XP_TEST_HIT
12313
2.59k
        }
12314
54.5M
        break;
12315
54.5M
                case NODE_TEST_PI:
12316
10.6k
                    if ((cur->type == XML_PI_NODE) &&
12317
10.6k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12318
0
        {
12319
0
      XP_TEST_HIT
12320
0
                    }
12321
10.6k
                    break;
12322
49.7M
                case NODE_TEST_ALL:
12323
49.7M
                    if (axis == AXIS_ATTRIBUTE) {
12324
2.38M
                        if (cur->type == XML_ATTRIBUTE_NODE)
12325
2.38M
      {
12326
2.38M
                            if (prefix == NULL)
12327
2.38M
          {
12328
2.38M
        XP_TEST_HIT
12329
2.38M
                            } else if ((cur->ns != NULL) &&
12330
300
        (xmlStrEqual(URI, cur->ns->href)))
12331
0
          {
12332
0
        XP_TEST_HIT
12333
0
                            }
12334
2.38M
                        }
12335
47.3M
                    } else if (axis == AXIS_NAMESPACE) {
12336
927k
                        if (cur->type == XML_NAMESPACE_DECL)
12337
927k
      {
12338
927k
          XP_TEST_HIT_NS
12339
927k
                        }
12340
46.4M
                    } else {
12341
46.4M
                        if (cur->type == XML_ELEMENT_NODE) {
12342
20.3M
                            if (prefix == NULL)
12343
20.0M
          {
12344
20.0M
        XP_TEST_HIT
12345
12346
20.0M
                            } else if ((cur->ns != NULL) &&
12347
245k
        (xmlStrEqual(URI, cur->ns->href)))
12348
63.5k
          {
12349
63.5k
        XP_TEST_HIT
12350
63.5k
                            }
12351
20.3M
                        }
12352
46.4M
                    }
12353
49.6M
                    break;
12354
49.6M
                case NODE_TEST_NS:{
12355
0
                        TODO;
12356
0
                        break;
12357
49.7M
                    }
12358
40.3M
                case NODE_TEST_NAME:
12359
40.3M
                    if (axis == AXIS_ATTRIBUTE) {
12360
513k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12361
0
          break;
12362
39.8M
        } else if (axis == AXIS_NAMESPACE) {
12363
115k
                        if (cur->type != XML_NAMESPACE_DECL)
12364
0
          break;
12365
39.7M
        } else {
12366
39.7M
            if (cur->type != XML_ELEMENT_NODE)
12367
19.8M
          break;
12368
39.7M
        }
12369
20.5M
                    switch (cur->type) {
12370
19.9M
                        case XML_ELEMENT_NODE:
12371
19.9M
                            if (xmlStrEqual(name, cur->name)) {
12372
1.25M
                                if (prefix == NULL) {
12373
1.22M
                                    if (cur->ns == NULL)
12374
740k
            {
12375
740k
          XP_TEST_HIT
12376
740k
                                    }
12377
1.22M
                                } else {
12378
38.9k
                                    if ((cur->ns != NULL) &&
12379
38.9k
                                        (xmlStrEqual(URI, cur->ns->href)))
12380
14.9k
            {
12381
14.9k
          XP_TEST_HIT
12382
14.9k
                                    }
12383
38.9k
                                }
12384
1.25M
                            }
12385
19.8M
                            break;
12386
19.8M
                        case XML_ATTRIBUTE_NODE:{
12387
513k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12388
12389
513k
                                if (xmlStrEqual(name, attr->name)) {
12390
74.6k
                                    if (prefix == NULL) {
12391
74.3k
                                        if ((attr->ns == NULL) ||
12392
74.3k
                                            (attr->ns->prefix == NULL))
12393
74.3k
          {
12394
74.3k
              XP_TEST_HIT
12395
74.3k
                                        }
12396
74.3k
                                    } else {
12397
258
                                        if ((attr->ns != NULL) &&
12398
258
                                            (xmlStrEqual(URI,
12399
0
                attr->ns->href)))
12400
0
          {
12401
0
              XP_TEST_HIT
12402
0
                                        }
12403
258
                                    }
12404
74.6k
                                }
12405
512k
                                break;
12406
513k
                            }
12407
512k
                        case XML_NAMESPACE_DECL:
12408
115k
                            if (cur->type == XML_NAMESPACE_DECL) {
12409
115k
                                xmlNsPtr ns = (xmlNsPtr) cur;
12410
12411
115k
                                if ((ns->prefix != NULL) && (name != NULL)
12412
115k
                                    && (xmlStrEqual(ns->prefix, name)))
12413
16.1k
        {
12414
16.1k
            XP_TEST_HIT_NS
12415
16.1k
                                }
12416
115k
                            }
12417
114k
                            break;
12418
114k
                        default:
12419
0
                            break;
12420
20.5M
                    }
12421
20.5M
                    break;
12422
144M
      } /* switch(test) */
12423
144M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12424
12425
51.8M
  goto apply_predicates;
12426
12427
51.8M
axis_range_end: /* ----------------------------------------------------- */
12428
  /*
12429
  * We have a "/foo[n]", and position() = n was reached.
12430
  * Note that we can have as well "/foo/::parent::foo[1]", so
12431
  * a duplicate-aware merge is still needed.
12432
  * Merge with the result.
12433
  */
12434
95.0k
  if (outSeq == NULL) {
12435
46.9k
      outSeq = seq;
12436
46.9k
      seq = NULL;
12437
46.9k
  } else
12438
            /* TODO: Check memory error. */
12439
48.0k
      outSeq = mergeAndClear(outSeq, seq);
12440
  /*
12441
  * Break if only a true/false result was requested.
12442
  */
12443
95.0k
  if (toBool)
12444
21.2k
      break;
12445
73.7k
  continue;
12446
12447
78.5k
first_hit: /* ---------------------------------------------------------- */
12448
  /*
12449
  * Break if only a true/false result was requested and
12450
  * no predicates existed and a node test succeeded.
12451
  */
12452
78.5k
  if (outSeq == NULL) {
12453
78.5k
      outSeq = seq;
12454
78.5k
      seq = NULL;
12455
78.5k
  } else
12456
            /* TODO: Check memory error. */
12457
0
      outSeq = mergeAndClear(outSeq, seq);
12458
78.5k
  break;
12459
12460
#ifdef DEBUG_STEP
12461
  if (seq != NULL)
12462
      nbMatches += seq->nodeNr;
12463
#endif
12464
12465
51.8M
apply_predicates: /* --------------------------------------------------- */
12466
51.8M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12467
0
      goto error;
12468
12469
        /*
12470
  * Apply predicates.
12471
  */
12472
51.8M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12473
      /*
12474
      * E.g. when we have a "/foo[some expression][n]".
12475
      */
12476
      /*
12477
      * QUESTION TODO: The old predicate evaluation took into
12478
      *  account location-sets.
12479
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12480
      *  Do we expect such a set here?
12481
      *  All what I learned now from the evaluation semantics
12482
      *  does not indicate that a location-set will be processed
12483
      *  here, so this looks OK.
12484
      */
12485
      /*
12486
      * Iterate over all predicates, starting with the outermost
12487
      * predicate.
12488
      * TODO: Problem: we cannot execute the inner predicates first
12489
      *  since we cannot go back *up* the operator tree!
12490
      *  Options we have:
12491
      *  1) Use of recursive functions (like is it currently done
12492
      *     via xmlXPathCompOpEval())
12493
      *  2) Add a predicate evaluation information stack to the
12494
      *     context struct
12495
      *  3) Change the way the operators are linked; we need a
12496
      *     "parent" field on xmlXPathStepOp
12497
      *
12498
      * For the moment, I'll try to solve this with a recursive
12499
      * function: xmlXPathCompOpEvalPredicate().
12500
      */
12501
783k
      if (hasPredicateRange != 0)
12502
105k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12503
105k
              hasNsNodes);
12504
678k
      else
12505
678k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12506
678k
              hasNsNodes);
12507
12508
783k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12509
2.17k
    total = 0;
12510
2.17k
    goto error;
12511
2.17k
      }
12512
783k
        }
12513
12514
51.8M
        if (seq->nodeNr > 0) {
12515
      /*
12516
      * Add to result set.
12517
      */
12518
14.0M
      if (outSeq == NULL) {
12519
5.01M
    outSeq = seq;
12520
5.01M
    seq = NULL;
12521
9.00M
      } else {
12522
                /* TODO: Check memory error. */
12523
9.00M
    outSeq = mergeAndClear(outSeq, seq);
12524
9.00M
      }
12525
12526
14.0M
            if (toBool)
12527
1.73k
                break;
12528
14.0M
  }
12529
51.8M
    }
12530
12531
15.2M
error:
12532
15.2M
    if ((obj->boolval) && (obj->user != NULL)) {
12533
  /*
12534
  * QUESTION TODO: What does this do and why?
12535
  * TODO: Do we have to do this also for the "error"
12536
  * cleanup further down?
12537
  */
12538
0
  ctxt->value->boolval = 1;
12539
0
  ctxt->value->user = obj->user;
12540
0
  obj->user = NULL;
12541
0
  obj->boolval = 0;
12542
0
    }
12543
15.2M
    xmlXPathReleaseObject(xpctxt, obj);
12544
12545
    /*
12546
    * Ensure we return at least an empty set.
12547
    */
12548
15.2M
    if (outSeq == NULL) {
12549
10.1M
  if ((seq != NULL) && (seq->nodeNr == 0))
12550
10.1M
      outSeq = seq;
12551
275
  else
12552
            /* TODO: Check memory error. */
12553
275
      outSeq = xmlXPathNodeSetCreate(NULL);
12554
10.1M
    }
12555
15.2M
    if ((seq != NULL) && (seq != outSeq)) {
12556
1.21M
   xmlXPathFreeNodeSet(seq);
12557
1.21M
    }
12558
    /*
12559
    * Hand over the result. Better to push the set also in
12560
    * case of errors.
12561
    */
12562
15.2M
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12563
    /*
12564
    * Reset the context node.
12565
    */
12566
15.2M
    xpctxt->node = oldContextNode;
12567
    /*
12568
    * When traversing the namespace axis in "toBool" mode, it's
12569
    * possible that tmpNsList wasn't freed.
12570
    */
12571
15.2M
    if (xpctxt->tmpNsList != NULL) {
12572
16.3k
        xmlFree(xpctxt->tmpNsList);
12573
16.3k
        xpctxt->tmpNsList = NULL;
12574
16.3k
    }
12575
12576
#ifdef DEBUG_STEP
12577
    xmlGenericError(xmlGenericErrorContext,
12578
  "\nExamined %d nodes, found %d nodes at that step\n",
12579
  total, nbMatches);
12580
#endif
12581
12582
15.2M
    return(total);
12583
15.2M
}
12584
12585
static int
12586
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12587
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12588
12589
/**
12590
 * xmlXPathCompOpEvalFirst:
12591
 * @ctxt:  the XPath parser context with the compiled expression
12592
 * @op:  an XPath compiled operation
12593
 * @first:  the first elem found so far
12594
 *
12595
 * Evaluate the Precompiled XPath operation searching only the first
12596
 * element in document order
12597
 *
12598
 * Returns the number of examined objects.
12599
 */
12600
static int
12601
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12602
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12603
583k
{
12604
583k
    int total = 0, cur;
12605
583k
    xmlXPathCompExprPtr comp;
12606
583k
    xmlXPathObjectPtr arg1, arg2;
12607
12608
583k
    CHECK_ERROR0;
12609
583k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12610
2
        return(0);
12611
583k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12612
583k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12613
583k
    ctxt->context->depth += 1;
12614
583k
    comp = ctxt->comp;
12615
583k
    switch (op->op) {
12616
0
        case XPATH_OP_END:
12617
0
            break;
12618
254k
        case XPATH_OP_UNION:
12619
254k
            total =
12620
254k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12621
254k
                                        first);
12622
254k
      CHECK_ERROR0;
12623
253k
            if ((ctxt->value != NULL)
12624
253k
                && (ctxt->value->type == XPATH_NODESET)
12625
253k
                && (ctxt->value->nodesetval != NULL)
12626
253k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12627
                /*
12628
                 * limit tree traversing to first node in the result
12629
                 */
12630
    /*
12631
    * OPTIMIZE TODO: This implicitly sorts
12632
    *  the result, even if not needed. E.g. if the argument
12633
    *  of the count() function, no sorting is needed.
12634
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12635
    *  already sorted?
12636
    */
12637
67.0k
    if (ctxt->value->nodesetval->nodeNr > 1)
12638
19.8k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12639
67.0k
                *first = ctxt->value->nodesetval->nodeTab[0];
12640
67.0k
            }
12641
253k
            cur =
12642
253k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12643
253k
                                        first);
12644
253k
      CHECK_ERROR0;
12645
12646
253k
            arg2 = valuePop(ctxt);
12647
253k
            arg1 = valuePop(ctxt);
12648
253k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12649
253k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12650
18
          xmlXPathReleaseObject(ctxt->context, arg1);
12651
18
          xmlXPathReleaseObject(ctxt->context, arg2);
12652
18
                XP_ERROR0(XPATH_INVALID_TYPE);
12653
0
            }
12654
253k
            if ((ctxt->context->opLimit != 0) &&
12655
253k
                (((arg1->nodesetval != NULL) &&
12656
253k
                  (xmlXPathCheckOpLimit(ctxt,
12657
200k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12658
253k
                 ((arg2->nodesetval != NULL) &&
12659
253k
                  (xmlXPathCheckOpLimit(ctxt,
12660
251k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12661
2
          xmlXPathReleaseObject(ctxt->context, arg1);
12662
2
          xmlXPathReleaseObject(ctxt->context, arg2);
12663
2
                break;
12664
2
            }
12665
12666
            /* TODO: Check memory error. */
12667
253k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12668
253k
                                                    arg2->nodesetval);
12669
253k
            valuePush(ctxt, arg1);
12670
253k
      xmlXPathReleaseObject(ctxt->context, arg2);
12671
            /* optimizer */
12672
253k
      if (total > cur)
12673
2.64k
    xmlXPathCompSwap(op);
12674
253k
            total += cur;
12675
253k
            break;
12676
6.92k
        case XPATH_OP_ROOT:
12677
6.92k
            xmlXPathRoot(ctxt);
12678
6.92k
            break;
12679
36.1k
        case XPATH_OP_NODE:
12680
36.1k
            if (op->ch1 != -1)
12681
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12682
36.1k
      CHECK_ERROR0;
12683
36.1k
            if (op->ch2 != -1)
12684
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12685
36.1k
      CHECK_ERROR0;
12686
36.1k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12687
36.1k
    ctxt->context->node));
12688
36.1k
            break;
12689
239k
        case XPATH_OP_COLLECT:{
12690
239k
                if (op->ch1 == -1)
12691
0
                    break;
12692
12693
239k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12694
239k
    CHECK_ERROR0;
12695
12696
239k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12697
239k
                break;
12698
239k
            }
12699
19
        case XPATH_OP_VALUE:
12700
19
            valuePush(ctxt,
12701
19
                      xmlXPathCacheObjectCopy(ctxt->context,
12702
19
      (xmlXPathObjectPtr) op->value4));
12703
19
            break;
12704
31.9k
        case XPATH_OP_SORT:
12705
31.9k
            if (op->ch1 != -1)
12706
31.9k
                total +=
12707
31.9k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12708
31.9k
                                            first);
12709
31.9k
      CHECK_ERROR0;
12710
31.8k
            if ((ctxt->value != NULL)
12711
31.8k
                && (ctxt->value->type == XPATH_NODESET)
12712
31.8k
                && (ctxt->value->nodesetval != NULL)
12713
31.8k
    && (ctxt->value->nodesetval->nodeNr > 1))
12714
7.22k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12715
31.8k
            break;
12716
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12717
12.0k
  case XPATH_OP_FILTER:
12718
12.0k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12719
12.0k
            break;
12720
0
#endif
12721
2.05k
        default:
12722
2.05k
            total += xmlXPathCompOpEval(ctxt, op);
12723
2.05k
            break;
12724
583k
    }
12725
12726
582k
    ctxt->context->depth -= 1;
12727
582k
    return(total);
12728
583k
}
12729
12730
/**
12731
 * xmlXPathCompOpEvalLast:
12732
 * @ctxt:  the XPath parser context with the compiled expression
12733
 * @op:  an XPath compiled operation
12734
 * @last:  the last elem found so far
12735
 *
12736
 * Evaluate the Precompiled XPath operation searching only the last
12737
 * element in document order
12738
 *
12739
 * Returns the number of nodes traversed
12740
 */
12741
static int
12742
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12743
                       xmlNodePtr * last)
12744
0
{
12745
0
    int total = 0, cur;
12746
0
    xmlXPathCompExprPtr comp;
12747
0
    xmlXPathObjectPtr arg1, arg2;
12748
12749
0
    CHECK_ERROR0;
12750
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12751
0
        return(0);
12752
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12753
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12754
0
    ctxt->context->depth += 1;
12755
0
    comp = ctxt->comp;
12756
0
    switch (op->op) {
12757
0
        case XPATH_OP_END:
12758
0
            break;
12759
0
        case XPATH_OP_UNION:
12760
0
            total =
12761
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12762
0
      CHECK_ERROR0;
12763
0
            if ((ctxt->value != NULL)
12764
0
                && (ctxt->value->type == XPATH_NODESET)
12765
0
                && (ctxt->value->nodesetval != NULL)
12766
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12767
                /*
12768
                 * limit tree traversing to first node in the result
12769
                 */
12770
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12771
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12772
0
                *last =
12773
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12774
0
                                                     nodesetval->nodeNr -
12775
0
                                                     1];
12776
0
            }
12777
0
            cur =
12778
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12779
0
      CHECK_ERROR0;
12780
0
            if ((ctxt->value != NULL)
12781
0
                && (ctxt->value->type == XPATH_NODESET)
12782
0
                && (ctxt->value->nodesetval != NULL)
12783
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12784
0
            }
12785
12786
0
            arg2 = valuePop(ctxt);
12787
0
            arg1 = valuePop(ctxt);
12788
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12789
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12790
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12791
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12792
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12793
0
            }
12794
0
            if ((ctxt->context->opLimit != 0) &&
12795
0
                (((arg1->nodesetval != NULL) &&
12796
0
                  (xmlXPathCheckOpLimit(ctxt,
12797
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12798
0
                 ((arg2->nodesetval != NULL) &&
12799
0
                  (xmlXPathCheckOpLimit(ctxt,
12800
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12801
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12802
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12803
0
                break;
12804
0
            }
12805
12806
            /* TODO: Check memory error. */
12807
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12808
0
                                                    arg2->nodesetval);
12809
0
            valuePush(ctxt, arg1);
12810
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12811
            /* optimizer */
12812
0
      if (total > cur)
12813
0
    xmlXPathCompSwap(op);
12814
0
            total += cur;
12815
0
            break;
12816
0
        case XPATH_OP_ROOT:
12817
0
            xmlXPathRoot(ctxt);
12818
0
            break;
12819
0
        case XPATH_OP_NODE:
12820
0
            if (op->ch1 != -1)
12821
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12822
0
      CHECK_ERROR0;
12823
0
            if (op->ch2 != -1)
12824
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12825
0
      CHECK_ERROR0;
12826
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12827
0
    ctxt->context->node));
12828
0
            break;
12829
0
        case XPATH_OP_COLLECT:{
12830
0
                if (op->ch1 == -1)
12831
0
                    break;
12832
12833
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12834
0
    CHECK_ERROR0;
12835
12836
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12837
0
                break;
12838
0
            }
12839
0
        case XPATH_OP_VALUE:
12840
0
            valuePush(ctxt,
12841
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12842
0
      (xmlXPathObjectPtr) op->value4));
12843
0
            break;
12844
0
        case XPATH_OP_SORT:
12845
0
            if (op->ch1 != -1)
12846
0
                total +=
12847
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12848
0
                                           last);
12849
0
      CHECK_ERROR0;
12850
0
            if ((ctxt->value != NULL)
12851
0
                && (ctxt->value->type == XPATH_NODESET)
12852
0
                && (ctxt->value->nodesetval != NULL)
12853
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12854
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12855
0
            break;
12856
0
        default:
12857
0
            total += xmlXPathCompOpEval(ctxt, op);
12858
0
            break;
12859
0
    }
12860
12861
0
    ctxt->context->depth -= 1;
12862
0
    return (total);
12863
0
}
12864
12865
#ifdef XP_OPTIMIZED_FILTER_FIRST
12866
static int
12867
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12868
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12869
12.0k
{
12870
12.0k
    int total = 0;
12871
12.0k
    xmlXPathCompExprPtr comp;
12872
12.0k
    xmlNodeSetPtr set;
12873
12874
12.0k
    CHECK_ERROR0;
12875
12.0k
    comp = ctxt->comp;
12876
    /*
12877
    * Optimization for ()[last()] selection i.e. the last elem
12878
    */
12879
12.0k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12880
12.0k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12881
12.0k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12882
8.07k
  int f = comp->steps[op->ch2].ch1;
12883
12884
8.07k
  if ((f != -1) &&
12885
8.07k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12886
8.07k
      (comp->steps[f].value5 == NULL) &&
12887
8.07k
      (comp->steps[f].value == 0) &&
12888
8.07k
      (comp->steps[f].value4 != NULL) &&
12889
8.07k
      (xmlStrEqual
12890
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
12891
0
      xmlNodePtr last = NULL;
12892
12893
0
      total +=
12894
0
    xmlXPathCompOpEvalLast(ctxt,
12895
0
        &comp->steps[op->ch1],
12896
0
        &last);
12897
0
      CHECK_ERROR0;
12898
      /*
12899
      * The nodeset should be in document order,
12900
      * Keep only the last value
12901
      */
12902
0
      if ((ctxt->value != NULL) &&
12903
0
    (ctxt->value->type == XPATH_NODESET) &&
12904
0
    (ctxt->value->nodesetval != NULL) &&
12905
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12906
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
12907
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12908
0
    *first = *(ctxt->value->nodesetval->nodeTab);
12909
0
      }
12910
0
      return (total);
12911
0
  }
12912
8.07k
    }
12913
12914
12.0k
    if (op->ch1 != -1)
12915
12.0k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12916
12.0k
    CHECK_ERROR0;
12917
11.9k
    if (op->ch2 == -1)
12918
0
  return (total);
12919
11.9k
    if (ctxt->value == NULL)
12920
0
  return (total);
12921
12922
#ifdef LIBXML_XPTR_LOCS_ENABLED
12923
    /*
12924
    * Hum are we filtering the result of an XPointer expression
12925
    */
12926
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12927
        xmlLocationSetPtr locset = ctxt->value->user;
12928
12929
        if (locset != NULL) {
12930
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12931
            if (locset->locNr > 0)
12932
                *first = (xmlNodePtr) locset->locTab[0]->user;
12933
        }
12934
12935
  return (total);
12936
    }
12937
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12938
12939
11.9k
    CHECK_TYPE0(XPATH_NODESET);
12940
11.9k
    set = ctxt->value->nodesetval;
12941
11.9k
    if (set != NULL) {
12942
5.86k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12943
5.86k
        if (set->nodeNr > 0)
12944
1.25k
            *first = set->nodeTab[0];
12945
5.86k
    }
12946
12947
11.9k
    return (total);
12948
11.9k
}
12949
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12950
12951
/**
12952
 * xmlXPathCompOpEval:
12953
 * @ctxt:  the XPath parser context with the compiled expression
12954
 * @op:  an XPath compiled operation
12955
 *
12956
 * Evaluate the Precompiled XPath operation
12957
 * Returns the number of nodes traversed
12958
 */
12959
static int
12960
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12961
50.5M
{
12962
50.5M
    int total = 0;
12963
50.5M
    int equal, ret;
12964
50.5M
    xmlXPathCompExprPtr comp;
12965
50.5M
    xmlXPathObjectPtr arg1, arg2;
12966
12967
50.5M
    CHECK_ERROR0;
12968
50.5M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12969
81
        return(0);
12970
50.5M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12971
50.5M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12972
50.5M
    ctxt->context->depth += 1;
12973
50.5M
    comp = ctxt->comp;
12974
50.5M
    switch (op->op) {
12975
0
        case XPATH_OP_END:
12976
0
            break;
12977
16.2k
        case XPATH_OP_AND:
12978
16.2k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12979
16.2k
      CHECK_ERROR0;
12980
16.1k
            xmlXPathBooleanFunction(ctxt, 1);
12981
16.1k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12982
1.38k
                break;
12983
14.7k
            arg2 = valuePop(ctxt);
12984
14.7k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12985
14.7k
      if (ctxt->error) {
12986
22
    xmlXPathFreeObject(arg2);
12987
22
    break;
12988
22
      }
12989
14.7k
            xmlXPathBooleanFunction(ctxt, 1);
12990
14.7k
            if (ctxt->value != NULL)
12991
14.7k
                ctxt->value->boolval &= arg2->boolval;
12992
14.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
12993
14.7k
            break;
12994
102k
        case XPATH_OP_OR:
12995
102k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12996
102k
      CHECK_ERROR0;
12997
102k
            xmlXPathBooleanFunction(ctxt, 1);
12998
102k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12999
19.0k
                break;
13000
83.5k
            arg2 = valuePop(ctxt);
13001
83.5k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13002
83.5k
      if (ctxt->error) {
13003
84
    xmlXPathFreeObject(arg2);
13004
84
    break;
13005
84
      }
13006
83.4k
            xmlXPathBooleanFunction(ctxt, 1);
13007
83.4k
            if (ctxt->value != NULL)
13008
83.4k
                ctxt->value->boolval |= arg2->boolval;
13009
83.4k
      xmlXPathReleaseObject(ctxt->context, arg2);
13010
83.4k
            break;
13011
3.32M
        case XPATH_OP_EQUAL:
13012
3.32M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13013
3.32M
      CHECK_ERROR0;
13014
3.32M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13015
3.32M
      CHECK_ERROR0;
13016
3.31M
      if (op->value)
13017
2.83M
    equal = xmlXPathEqualValues(ctxt);
13018
481k
      else
13019
481k
    equal = xmlXPathNotEqualValues(ctxt);
13020
3.31M
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13021
3.31M
            break;
13022
3.06M
        case XPATH_OP_CMP:
13023
3.06M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024
3.06M
      CHECK_ERROR0;
13025
3.06M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13026
3.06M
      CHECK_ERROR0;
13027
3.06M
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13028
3.06M
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13029
3.06M
            break;
13030
3.76M
        case XPATH_OP_PLUS:
13031
3.76M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13032
3.76M
      CHECK_ERROR0;
13033
3.75M
            if (op->ch2 != -1) {
13034
1.99M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13035
1.99M
      }
13036
3.75M
      CHECK_ERROR0;
13037
3.75M
            if (op->value == 0)
13038
1.83M
                xmlXPathSubValues(ctxt);
13039
1.91M
            else if (op->value == 1)
13040
154k
                xmlXPathAddValues(ctxt);
13041
1.76M
            else if (op->value == 2)
13042
1.47M
                xmlXPathValueFlipSign(ctxt);
13043
287k
            else if (op->value == 3) {
13044
287k
                CAST_TO_NUMBER;
13045
287k
                CHECK_TYPE0(XPATH_NUMBER);
13046
287k
            }
13047
3.75M
            break;
13048
3.75M
        case XPATH_OP_MULT:
13049
2.85M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13050
2.85M
      CHECK_ERROR0;
13051
2.85M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13052
2.85M
      CHECK_ERROR0;
13053
2.85M
            if (op->value == 0)
13054
2.81M
                xmlXPathMultValues(ctxt);
13055
37.7k
            else if (op->value == 1)
13056
17.4k
                xmlXPathDivValues(ctxt);
13057
20.2k
            else if (op->value == 2)
13058
20.2k
                xmlXPathModValues(ctxt);
13059
2.85M
            break;
13060
2.12M
        case XPATH_OP_UNION:
13061
2.12M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13062
2.12M
      CHECK_ERROR0;
13063
2.12M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13064
2.12M
      CHECK_ERROR0;
13065
13066
2.12M
            arg2 = valuePop(ctxt);
13067
2.12M
            arg1 = valuePop(ctxt);
13068
2.12M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13069
2.12M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13070
51
          xmlXPathReleaseObject(ctxt->context, arg1);
13071
51
          xmlXPathReleaseObject(ctxt->context, arg2);
13072
51
                XP_ERROR0(XPATH_INVALID_TYPE);
13073
0
            }
13074
2.12M
            if ((ctxt->context->opLimit != 0) &&
13075
2.12M
                (((arg1->nodesetval != NULL) &&
13076
2.12M
                  (xmlXPathCheckOpLimit(ctxt,
13077
1.71M
                                        arg1->nodesetval->nodeNr) < 0)) ||
13078
2.12M
                 ((arg2->nodesetval != NULL) &&
13079
2.12M
                  (xmlXPathCheckOpLimit(ctxt,
13080
1.77M
                                        arg2->nodesetval->nodeNr) < 0)))) {
13081
19
          xmlXPathReleaseObject(ctxt->context, arg1);
13082
19
          xmlXPathReleaseObject(ctxt->context, arg2);
13083
19
                break;
13084
19
            }
13085
13086
2.12M
      if ((arg1->nodesetval == NULL) ||
13087
2.12M
    ((arg2->nodesetval != NULL) &&
13088
1.71M
     (arg2->nodesetval->nodeNr != 0)))
13089
996k
      {
13090
                /* TODO: Check memory error. */
13091
996k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13092
996k
              arg2->nodesetval);
13093
996k
      }
13094
13095
2.12M
            valuePush(ctxt, arg1);
13096
2.12M
      xmlXPathReleaseObject(ctxt->context, arg2);
13097
2.12M
            break;
13098
5.22M
        case XPATH_OP_ROOT:
13099
5.22M
            xmlXPathRoot(ctxt);
13100
5.22M
            break;
13101
9.17M
        case XPATH_OP_NODE:
13102
9.17M
            if (op->ch1 != -1)
13103
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13104
9.17M
      CHECK_ERROR0;
13105
9.17M
            if (op->ch2 != -1)
13106
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13107
9.17M
      CHECK_ERROR0;
13108
9.17M
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13109
9.17M
    ctxt->context->node));
13110
9.17M
            break;
13111
18.9M
        case XPATH_OP_COLLECT:{
13112
18.9M
                if (op->ch1 == -1)
13113
0
                    break;
13114
13115
18.9M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13116
18.9M
    CHECK_ERROR0;
13117
13118
18.9M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13119
18.9M
                break;
13120
18.9M
            }
13121
1.47M
        case XPATH_OP_VALUE:
13122
1.47M
            valuePush(ctxt,
13123
1.47M
                      xmlXPathCacheObjectCopy(ctxt->context,
13124
1.47M
      (xmlXPathObjectPtr) op->value4));
13125
1.47M
            break;
13126
61
        case XPATH_OP_VARIABLE:{
13127
61
    xmlXPathObjectPtr val;
13128
13129
61
                if (op->ch1 != -1)
13130
0
                    total +=
13131
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13132
61
                if (op->value5 == NULL) {
13133
53
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13134
53
        if (val == NULL)
13135
53
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13136
0
                    valuePush(ctxt, val);
13137
8
    } else {
13138
8
                    const xmlChar *URI;
13139
13140
8
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13141
8
                    if (URI == NULL) {
13142
6
                        xmlGenericError(xmlGenericErrorContext,
13143
6
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13144
6
                                    (char *) op->value4, (char *)op->value5);
13145
6
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13146
6
                        break;
13147
6
                    }
13148
2
        val = xmlXPathVariableLookupNS(ctxt->context,
13149
2
                                                       op->value4, URI);
13150
2
        if (val == NULL)
13151
2
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13152
0
                    valuePush(ctxt, val);
13153
0
                }
13154
0
                break;
13155
61
            }
13156
159k
        case XPATH_OP_FUNCTION:{
13157
159k
                xmlXPathFunction func;
13158
159k
                const xmlChar *oldFunc, *oldFuncURI;
13159
159k
    int i;
13160
159k
                int frame;
13161
13162
159k
                frame = xmlXPathSetFrame(ctxt);
13163
159k
                if (op->ch1 != -1) {
13164
108k
                    total +=
13165
108k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13166
108k
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13167
71
                        xmlXPathPopFrame(ctxt, frame);
13168
71
                        break;
13169
71
                    }
13170
108k
                }
13171
159k
    if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13172
0
        xmlGenericError(xmlGenericErrorContext,
13173
0
          "xmlXPathCompOpEval: parameter error\n");
13174
0
        ctxt->error = XPATH_INVALID_OPERAND;
13175
0
                    xmlXPathPopFrame(ctxt, frame);
13176
0
        break;
13177
0
    }
13178
271k
    for (i = 0; i < op->value; i++) {
13179
111k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13180
0
      xmlGenericError(xmlGenericErrorContext,
13181
0
        "xmlXPathCompOpEval: parameter error\n");
13182
0
      ctxt->error = XPATH_INVALID_OPERAND;
13183
0
                        xmlXPathPopFrame(ctxt, frame);
13184
0
      break;
13185
0
        }
13186
111k
                }
13187
159k
                if (op->cache != NULL)
13188
158k
                    func = op->cache;
13189
1.18k
                else {
13190
1.18k
                    const xmlChar *URI = NULL;
13191
13192
1.18k
                    if (op->value5 == NULL)
13193
1.17k
                        func =
13194
1.17k
                            xmlXPathFunctionLookup(ctxt->context,
13195
1.17k
                                                   op->value4);
13196
11
                    else {
13197
11
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13198
11
                        if (URI == NULL) {
13199
4
                            xmlGenericError(xmlGenericErrorContext,
13200
4
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13201
4
                                    (char *)op->value4, (char *)op->value5);
13202
4
                            xmlXPathPopFrame(ctxt, frame);
13203
4
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13204
4
                            break;
13205
4
                        }
13206
7
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13207
7
                                                        op->value4, URI);
13208
7
                    }
13209
1.18k
                    if (func == NULL) {
13210
159
                        xmlGenericError(xmlGenericErrorContext,
13211
159
                                "xmlXPathCompOpEval: function %s not found\n",
13212
159
                                        (char *)op->value4);
13213
159
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13214
0
                    }
13215
1.02k
                    op->cache = func;
13216
1.02k
                    op->cacheURI = (void *) URI;
13217
1.02k
                }
13218
159k
                oldFunc = ctxt->context->function;
13219
159k
                oldFuncURI = ctxt->context->functionURI;
13220
159k
                ctxt->context->function = op->value4;
13221
159k
                ctxt->context->functionURI = op->cacheURI;
13222
159k
                func(ctxt, op->value);
13223
159k
                ctxt->context->function = oldFunc;
13224
159k
                ctxt->context->functionURI = oldFuncURI;
13225
159k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13226
159k
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13227
159k
                    XP_ERROR0(XPATH_STACK_ERROR);
13228
159k
                xmlXPathPopFrame(ctxt, frame);
13229
159k
                break;
13230
159k
            }
13231
112k
        case XPATH_OP_ARG:
13232
112k
            if (op->ch1 != -1) {
13233
3.71k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13234
3.71k
          CHECK_ERROR0;
13235
3.71k
            }
13236
112k
            if (op->ch2 != -1) {
13237
112k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238
112k
          CHECK_ERROR0;
13239
112k
      }
13240
111k
            break;
13241
111k
        case XPATH_OP_PREDICATE:
13242
127k
        case XPATH_OP_FILTER:{
13243
127k
                xmlNodeSetPtr set;
13244
13245
                /*
13246
                 * Optimization for ()[1] selection i.e. the first elem
13247
                 */
13248
127k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13249
127k
#ifdef XP_OPTIMIZED_FILTER_FIRST
13250
        /*
13251
        * FILTER TODO: Can we assume that the inner processing
13252
        *  will result in an ordered list if we have an
13253
        *  XPATH_OP_FILTER?
13254
        *  What about an additional field or flag on
13255
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13256
        *  to assume anything, so it would be more robust and
13257
        *  easier to optimize.
13258
        */
13259
127k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13260
127k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13261
#else
13262
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13263
#endif
13264
127k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13265
72.5k
                    xmlXPathObjectPtr val;
13266
13267
72.5k
                    val = comp->steps[op->ch2].value4;
13268
72.5k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13269
72.5k
                        (val->floatval == 1.0)) {
13270
43.7k
                        xmlNodePtr first = NULL;
13271
13272
43.7k
                        total +=
13273
43.7k
                            xmlXPathCompOpEvalFirst(ctxt,
13274
43.7k
                                                    &comp->steps[op->ch1],
13275
43.7k
                                                    &first);
13276
43.7k
      CHECK_ERROR0;
13277
                        /*
13278
                         * The nodeset should be in document order,
13279
                         * Keep only the first value
13280
                         */
13281
43.5k
                        if ((ctxt->value != NULL) &&
13282
43.5k
                            (ctxt->value->type == XPATH_NODESET) &&
13283
43.5k
                            (ctxt->value->nodesetval != NULL) &&
13284
43.5k
                            (ctxt->value->nodesetval->nodeNr > 1))
13285
7.22k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13286
7.22k
                                                        1, 1);
13287
43.5k
                        break;
13288
43.7k
                    }
13289
72.5k
                }
13290
                /*
13291
                 * Optimization for ()[last()] selection i.e. the last elem
13292
                 */
13293
83.4k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13294
83.4k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13295
83.4k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13296
12.6k
                    int f = comp->steps[op->ch2].ch1;
13297
13298
12.6k
                    if ((f != -1) &&
13299
12.6k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13300
12.6k
                        (comp->steps[f].value5 == NULL) &&
13301
12.6k
                        (comp->steps[f].value == 0) &&
13302
12.6k
                        (comp->steps[f].value4 != NULL) &&
13303
12.6k
                        (xmlStrEqual
13304
5
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13305
0
                        xmlNodePtr last = NULL;
13306
13307
0
                        total +=
13308
0
                            xmlXPathCompOpEvalLast(ctxt,
13309
0
                                                   &comp->steps[op->ch1],
13310
0
                                                   &last);
13311
0
      CHECK_ERROR0;
13312
                        /*
13313
                         * The nodeset should be in document order,
13314
                         * Keep only the last value
13315
                         */
13316
0
                        if ((ctxt->value != NULL) &&
13317
0
                            (ctxt->value->type == XPATH_NODESET) &&
13318
0
                            (ctxt->value->nodesetval != NULL) &&
13319
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13320
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13321
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13322
0
                        break;
13323
0
                    }
13324
12.6k
                }
13325
    /*
13326
    * Process inner predicates first.
13327
    * Example "index[parent::book][1]":
13328
    * ...
13329
    *   PREDICATE   <-- we are here "[1]"
13330
    *     PREDICATE <-- process "[parent::book]" first
13331
    *       SORT
13332
    *         COLLECT  'parent' 'name' 'node' book
13333
    *           NODE
13334
    *     ELEM Object is a number : 1
13335
    */
13336
83.4k
                if (op->ch1 != -1)
13337
83.4k
                    total +=
13338
83.4k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339
83.4k
    CHECK_ERROR0;
13340
83.2k
                if (op->ch2 == -1)
13341
0
                    break;
13342
83.2k
                if (ctxt->value == NULL)
13343
0
                    break;
13344
13345
#ifdef LIBXML_XPTR_LOCS_ENABLED
13346
                /*
13347
                 * Hum are we filtering the result of an XPointer expression
13348
                 */
13349
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13350
                    xmlLocationSetPtr locset = ctxt->value->user;
13351
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13352
                                              1, locset->locNr);
13353
                    break;
13354
                }
13355
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13356
13357
83.2k
                CHECK_TYPE0(XPATH_NODESET);
13358
83.1k
                set = ctxt->value->nodesetval;
13359
83.1k
                if (set != NULL)
13360
65.5k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13361
65.5k
                                          1, set->nodeNr, 1);
13362
83.1k
                break;
13363
83.2k
            }
13364
125k
        case XPATH_OP_SORT:
13365
125k
            if (op->ch1 != -1)
13366
125k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367
125k
      CHECK_ERROR0;
13368
124k
            if ((ctxt->value != NULL) &&
13369
124k
                (ctxt->value->type == XPATH_NODESET) &&
13370
124k
                (ctxt->value->nodesetval != NULL) &&
13371
124k
    (ctxt->value->nodesetval->nodeNr > 1))
13372
21.7k
      {
13373
21.7k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13374
21.7k
      }
13375
124k
            break;
13376
#ifdef LIBXML_XPTR_LOCS_ENABLED
13377
        case XPATH_OP_RANGETO:{
13378
                xmlXPathObjectPtr range;
13379
                xmlXPathObjectPtr res, obj;
13380
                xmlXPathObjectPtr tmp;
13381
                xmlLocationSetPtr newlocset = NULL;
13382
        xmlLocationSetPtr oldlocset;
13383
                xmlNodeSetPtr oldset;
13384
                xmlNodePtr oldnode = ctxt->context->node;
13385
                int oldcs = ctxt->context->contextSize;
13386
                int oldpp = ctxt->context->proximityPosition;
13387
                int i, j;
13388
13389
                if (op->ch1 != -1) {
13390
                    total +=
13391
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13392
                    CHECK_ERROR0;
13393
                }
13394
                if (ctxt->value == NULL) {
13395
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13396
                }
13397
                if (op->ch2 == -1)
13398
                    break;
13399
13400
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13401
                    /*
13402
                     * Extract the old locset, and then evaluate the result of the
13403
                     * expression for all the element in the locset. use it to grow
13404
                     * up a new locset.
13405
                     */
13406
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13407
13408
                    if ((ctxt->value->user == NULL) ||
13409
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13410
                        break;
13411
13412
                    obj = valuePop(ctxt);
13413
                    oldlocset = obj->user;
13414
13415
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13416
13417
                    for (i = 0; i < oldlocset->locNr; i++) {
13418
                        /*
13419
                         * Run the evaluation with a node list made of a
13420
                         * single item in the nodelocset.
13421
                         */
13422
                        ctxt->context->node = oldlocset->locTab[i]->user;
13423
                        ctxt->context->contextSize = oldlocset->locNr;
13424
                        ctxt->context->proximityPosition = i + 1;
13425
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13426
          ctxt->context->node);
13427
                        valuePush(ctxt, tmp);
13428
13429
                        if (op->ch2 != -1)
13430
                            total +=
13431
                                xmlXPathCompOpEval(ctxt,
13432
                                                   &comp->steps[op->ch2]);
13433
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13434
                            xmlXPtrFreeLocationSet(newlocset);
13435
                            goto rangeto_error;
13436
      }
13437
13438
                        res = valuePop(ctxt);
13439
      if (res->type == XPATH_LOCATIONSET) {
13440
          xmlLocationSetPtr rloc =
13441
              (xmlLocationSetPtr)res->user;
13442
          for (j=0; j<rloc->locNr; j++) {
13443
              range = xmlXPtrNewRange(
13444
          oldlocset->locTab[i]->user,
13445
          oldlocset->locTab[i]->index,
13446
          rloc->locTab[j]->user2,
13447
          rloc->locTab[j]->index2);
13448
        if (range != NULL) {
13449
            xmlXPtrLocationSetAdd(newlocset, range);
13450
        }
13451
          }
13452
      } else {
13453
          range = xmlXPtrNewRangeNodeObject(
13454
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13455
                            if (range != NULL) {
13456
                                xmlXPtrLocationSetAdd(newlocset,range);
13457
          }
13458
                        }
13459
13460
                        /*
13461
                         * Cleanup
13462
                         */
13463
                        if (res != NULL) {
13464
          xmlXPathReleaseObject(ctxt->context, res);
13465
      }
13466
                        if (ctxt->value == tmp) {
13467
                            res = valuePop(ctxt);
13468
          xmlXPathReleaseObject(ctxt->context, res);
13469
                        }
13470
                    }
13471
    } else {  /* Not a location set */
13472
                    CHECK_TYPE0(XPATH_NODESET);
13473
                    obj = valuePop(ctxt);
13474
                    oldset = obj->nodesetval;
13475
13476
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13477
13478
                    if (oldset != NULL) {
13479
                        for (i = 0; i < oldset->nodeNr; i++) {
13480
                            /*
13481
                             * Run the evaluation with a node list made of a single item
13482
                             * in the nodeset.
13483
                             */
13484
                            ctxt->context->node = oldset->nodeTab[i];
13485
          /*
13486
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13487
          */
13488
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13489
        ctxt->context->node);
13490
                            valuePush(ctxt, tmp);
13491
13492
                            if (op->ch2 != -1)
13493
                                total +=
13494
                                    xmlXPathCompOpEval(ctxt,
13495
                                                   &comp->steps[op->ch2]);
13496
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13497
                                xmlXPtrFreeLocationSet(newlocset);
13498
                                goto rangeto_error;
13499
          }
13500
13501
                            res = valuePop(ctxt);
13502
                            range =
13503
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13504
                                                      res);
13505
                            if (range != NULL) {
13506
                                xmlXPtrLocationSetAdd(newlocset, range);
13507
                            }
13508
13509
                            /*
13510
                             * Cleanup
13511
                             */
13512
                            if (res != NULL) {
13513
        xmlXPathReleaseObject(ctxt->context, res);
13514
          }
13515
                            if (ctxt->value == tmp) {
13516
                                res = valuePop(ctxt);
13517
        xmlXPathReleaseObject(ctxt->context, res);
13518
                            }
13519
                        }
13520
                    }
13521
                }
13522
13523
                /*
13524
                 * The result is used as the new evaluation set.
13525
                 */
13526
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13527
rangeto_error:
13528
    xmlXPathReleaseObject(ctxt->context, obj);
13529
                ctxt->context->node = oldnode;
13530
                ctxt->context->contextSize = oldcs;
13531
                ctxt->context->proximityPosition = oldpp;
13532
                break;
13533
            }
13534
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13535
0
        default:
13536
0
            xmlGenericError(xmlGenericErrorContext,
13537
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13538
0
            ctxt->error = XPATH_INVALID_OPERAND;
13539
0
            break;
13540
50.5M
    }
13541
13542
50.5M
    ctxt->context->depth -= 1;
13543
50.5M
    return (total);
13544
50.5M
}
13545
13546
/**
13547
 * xmlXPathCompOpEvalToBoolean:
13548
 * @ctxt:  the XPath parser context
13549
 *
13550
 * Evaluates if the expression evaluates to true.
13551
 *
13552
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13553
 */
13554
static int
13555
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13556
          xmlXPathStepOpPtr op,
13557
          int isPredicate)
13558
2.41M
{
13559
2.41M
    xmlXPathObjectPtr resObj = NULL;
13560
13561
2.42M
start:
13562
2.42M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13563
5
        return(0);
13564
    /* comp = ctxt->comp; */
13565
2.42M
    switch (op->op) {
13566
0
        case XPATH_OP_END:
13567
0
            return (0);
13568
169k
  case XPATH_OP_VALUE:
13569
169k
      resObj = (xmlXPathObjectPtr) op->value4;
13570
169k
      if (isPredicate)
13571
169k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13572
0
      return(xmlXPathCastToBoolean(resObj));
13573
11.4k
  case XPATH_OP_SORT:
13574
      /*
13575
      * We don't need sorting for boolean results. Skip this one.
13576
      */
13577
11.4k
            if (op->ch1 != -1) {
13578
11.4k
    op = &ctxt->comp->steps[op->ch1];
13579
11.4k
    goto start;
13580
11.4k
      }
13581
0
      return(0);
13582
522k
  case XPATH_OP_COLLECT:
13583
522k
      if (op->ch1 == -1)
13584
0
    return(0);
13585
13586
522k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13587
522k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13588
36
    return(-1);
13589
13590
522k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13591
522k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13592
19
    return(-1);
13593
13594
522k
      resObj = valuePop(ctxt);
13595
522k
      if (resObj == NULL)
13596
0
    return(-1);
13597
522k
      break;
13598
1.72M
  default:
13599
      /*
13600
      * Fallback to call xmlXPathCompOpEval().
13601
      */
13602
1.72M
      xmlXPathCompOpEval(ctxt, op);
13603
1.72M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13604
2.12k
    return(-1);
13605
13606
1.71M
      resObj = valuePop(ctxt);
13607
1.71M
      if (resObj == NULL)
13608
0
    return(-1);
13609
1.71M
      break;
13610
2.42M
    }
13611
13612
2.24M
    if (resObj) {
13613
2.24M
  int res;
13614
13615
2.24M
  if (resObj->type == XPATH_BOOLEAN) {
13616
1.33M
      res = resObj->boolval;
13617
1.33M
  } else if (isPredicate) {
13618
      /*
13619
      * For predicates a result of type "number" is handled
13620
      * differently:
13621
      * SPEC XPath 1.0:
13622
      * "If the result is a number, the result will be converted
13623
      *  to true if the number is equal to the context position
13624
      *  and will be converted to false otherwise;"
13625
      */
13626
908k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13627
908k
  } else {
13628
0
      res = xmlXPathCastToBoolean(resObj);
13629
0
  }
13630
2.24M
  xmlXPathReleaseObject(ctxt->context, resObj);
13631
2.24M
  return(res);
13632
2.24M
    }
13633
13634
0
    return(0);
13635
2.24M
}
13636
13637
#ifdef XPATH_STREAMING
13638
/**
13639
 * xmlXPathRunStreamEval:
13640
 * @ctxt:  the XPath parser context with the compiled expression
13641
 *
13642
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13643
 */
13644
static int
13645
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13646
          xmlXPathObjectPtr *resultSeq, int toBool)
13647
494
{
13648
494
    int max_depth, min_depth;
13649
494
    int from_root;
13650
494
    int ret, depth;
13651
494
    int eval_all_nodes;
13652
494
    xmlNodePtr cur = NULL, limit = NULL;
13653
494
    xmlStreamCtxtPtr patstream = NULL;
13654
13655
494
    if ((ctxt == NULL) || (comp == NULL))
13656
0
        return(-1);
13657
494
    max_depth = xmlPatternMaxDepth(comp);
13658
494
    if (max_depth == -1)
13659
0
        return(-1);
13660
494
    if (max_depth == -2)
13661
302
        max_depth = 10000;
13662
494
    min_depth = xmlPatternMinDepth(comp);
13663
494
    if (min_depth == -1)
13664
0
        return(-1);
13665
494
    from_root = xmlPatternFromRoot(comp);
13666
494
    if (from_root < 0)
13667
0
        return(-1);
13668
#if 0
13669
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13670
#endif
13671
13672
494
    if (! toBool) {
13673
494
  if (resultSeq == NULL)
13674
0
      return(-1);
13675
494
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13676
494
  if (*resultSeq == NULL)
13677
0
      return(-1);
13678
494
    }
13679
13680
    /*
13681
     * handle the special cases of "/" amd "." being matched
13682
     */
13683
494
    if (min_depth == 0) {
13684
57
  if (from_root) {
13685
      /* Select "/" */
13686
0
      if (toBool)
13687
0
    return(1);
13688
            /* TODO: Check memory error. */
13689
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13690
0
                         (xmlNodePtr) ctxt->doc);
13691
57
  } else {
13692
      /* Select "self::node()" */
13693
57
      if (toBool)
13694
0
    return(1);
13695
            /* TODO: Check memory error. */
13696
57
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13697
57
  }
13698
57
    }
13699
494
    if (max_depth == 0) {
13700
6
  return(0);
13701
6
    }
13702
13703
488
    if (from_root) {
13704
212
        cur = (xmlNodePtr)ctxt->doc;
13705
276
    } else if (ctxt->node != NULL) {
13706
276
        switch (ctxt->node->type) {
13707
0
            case XML_ELEMENT_NODE:
13708
276
            case XML_DOCUMENT_NODE:
13709
276
            case XML_DOCUMENT_FRAG_NODE:
13710
276
            case XML_HTML_DOCUMENT_NODE:
13711
276
          cur = ctxt->node;
13712
276
    break;
13713
0
            case XML_ATTRIBUTE_NODE:
13714
0
            case XML_TEXT_NODE:
13715
0
            case XML_CDATA_SECTION_NODE:
13716
0
            case XML_ENTITY_REF_NODE:
13717
0
            case XML_ENTITY_NODE:
13718
0
            case XML_PI_NODE:
13719
0
            case XML_COMMENT_NODE:
13720
0
            case XML_NOTATION_NODE:
13721
0
            case XML_DTD_NODE:
13722
0
            case XML_DOCUMENT_TYPE_NODE:
13723
0
            case XML_ELEMENT_DECL:
13724
0
            case XML_ATTRIBUTE_DECL:
13725
0
            case XML_ENTITY_DECL:
13726
0
            case XML_NAMESPACE_DECL:
13727
0
            case XML_XINCLUDE_START:
13728
0
            case XML_XINCLUDE_END:
13729
0
    break;
13730
276
  }
13731
276
  limit = cur;
13732
276
    }
13733
488
    if (cur == NULL) {
13734
0
        return(0);
13735
0
    }
13736
13737
488
    patstream = xmlPatternGetStreamCtxt(comp);
13738
488
    if (patstream == NULL) {
13739
  /*
13740
  * QUESTION TODO: Is this an error?
13741
  */
13742
0
  return(0);
13743
0
    }
13744
13745
488
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13746
13747
488
    if (from_root) {
13748
212
  ret = xmlStreamPush(patstream, NULL, NULL);
13749
212
  if (ret < 0) {
13750
212
  } else if (ret == 1) {
13751
14
      if (toBool)
13752
0
    goto return_1;
13753
            /* TODO: Check memory error. */
13754
14
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13755
14
  }
13756
212
    }
13757
488
    depth = 0;
13758
488
    goto scan_children;
13759
8.06k
next_node:
13760
14.3k
    do {
13761
14.3k
        if (ctxt->opLimit != 0) {
13762
14.3k
            if (ctxt->opCount >= ctxt->opLimit) {
13763
0
                xmlGenericError(xmlGenericErrorContext,
13764
0
                        "XPath operation limit exceeded\n");
13765
0
                xmlFreeStreamCtxt(patstream);
13766
0
                return(-1);
13767
0
            }
13768
14.3k
            ctxt->opCount++;
13769
14.3k
        }
13770
13771
14.3k
  switch (cur->type) {
13772
4.49k
      case XML_ELEMENT_NODE:
13773
12.3k
      case XML_TEXT_NODE:
13774
12.6k
      case XML_CDATA_SECTION_NODE:
13775
13.4k
      case XML_COMMENT_NODE:
13776
14.3k
      case XML_PI_NODE:
13777
14.3k
    if (cur->type == XML_ELEMENT_NODE) {
13778
4.49k
        ret = xmlStreamPush(patstream, cur->name,
13779
4.49k
        (cur->ns ? cur->ns->href : NULL));
13780
9.80k
    } else if (eval_all_nodes)
13781
3.57k
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13782
6.23k
    else
13783
6.23k
        break;
13784
13785
8.07k
    if (ret < 0) {
13786
        /* NOP. */
13787
8.07k
    } else if (ret == 1) {
13788
3.24k
        if (toBool)
13789
0
      goto return_1;
13790
3.24k
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13791
3.24k
            < 0) {
13792
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13793
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13794
0
        }
13795
3.24k
    }
13796
8.07k
    if ((cur->children == NULL) || (depth >= max_depth)) {
13797
5.00k
        ret = xmlStreamPop(patstream);
13798
5.00k
        while (cur->next != NULL) {
13799
3.72k
      cur = cur->next;
13800
3.72k
      if ((cur->type != XML_ENTITY_DECL) &&
13801
3.72k
          (cur->type != XML_DTD_NODE))
13802
3.72k
          goto next_node;
13803
3.72k
        }
13804
5.00k
    }
13805
4.34k
      default:
13806
4.34k
    break;
13807
14.3k
  }
13808
13809
11.0k
scan_children:
13810
11.0k
  if (cur->type == XML_NAMESPACE_DECL) break;
13811
11.0k
  if ((cur->children != NULL) && (depth < max_depth)) {
13812
      /*
13813
       * Do not descend on entities declarations
13814
       */
13815
3.55k
      if (cur->children->type != XML_ENTITY_DECL) {
13816
3.55k
    cur = cur->children;
13817
3.55k
    depth++;
13818
    /*
13819
     * Skip DTDs
13820
     */
13821
3.55k
    if (cur->type != XML_DTD_NODE)
13822
3.55k
        continue;
13823
3.55k
      }
13824
3.55k
  }
13825
13826
7.50k
  if (cur == limit)
13827
0
      break;
13828
13829
7.50k
  while (cur->next != NULL) {
13830
4.33k
      cur = cur->next;
13831
4.33k
      if ((cur->type != XML_ENTITY_DECL) &&
13832
4.33k
    (cur->type != XML_DTD_NODE))
13833
4.33k
    goto next_node;
13834
4.33k
  }
13835
13836
3.55k
  do {
13837
3.55k
      cur = cur->parent;
13838
3.55k
      depth--;
13839
3.55k
      if ((cur == NULL) || (cur == limit) ||
13840
3.55k
                (cur->type == XML_DOCUMENT_NODE))
13841
488
          goto done;
13842
3.07k
      if (cur->type == XML_ELEMENT_NODE) {
13843
3.07k
    ret = xmlStreamPop(patstream);
13844
3.07k
      } else if ((eval_all_nodes) &&
13845
0
    ((cur->type == XML_TEXT_NODE) ||
13846
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13847
0
     (cur->type == XML_COMMENT_NODE) ||
13848
0
     (cur->type == XML_PI_NODE)))
13849
0
      {
13850
0
    ret = xmlStreamPop(patstream);
13851
0
      }
13852
3.07k
      if (cur->next != NULL) {
13853
2.68k
    cur = cur->next;
13854
2.68k
    break;
13855
2.68k
      }
13856
3.07k
  } while (cur != NULL);
13857
13858
6.24k
    } while ((cur != NULL) && (depth >= 0));
13859
13860
488
done:
13861
13862
488
    if (patstream)
13863
488
  xmlFreeStreamCtxt(patstream);
13864
488
    return(0);
13865
13866
0
return_1:
13867
0
    if (patstream)
13868
0
  xmlFreeStreamCtxt(patstream);
13869
0
    return(1);
13870
8.06k
}
13871
#endif /* XPATH_STREAMING */
13872
13873
/**
13874
 * xmlXPathRunEval:
13875
 * @ctxt:  the XPath parser context with the compiled expression
13876
 * @toBool:  evaluate to a boolean result
13877
 *
13878
 * Evaluate the Precompiled XPath expression in the given context.
13879
 */
13880
static int
13881
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13882
5.54k
{
13883
5.54k
    xmlXPathCompExprPtr comp;
13884
5.54k
    int oldDepth;
13885
13886
5.54k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13887
0
  return(-1);
13888
13889
5.54k
    if (ctxt->valueTab == NULL) {
13890
  /* Allocate the value stack */
13891
363
  ctxt->valueTab = (xmlXPathObjectPtr *)
13892
363
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13893
363
  if (ctxt->valueTab == NULL) {
13894
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13895
0
      return(-1);
13896
0
  }
13897
363
  ctxt->valueNr = 0;
13898
363
  ctxt->valueMax = 10;
13899
363
  ctxt->value = NULL;
13900
363
        ctxt->valueFrame = 0;
13901
363
    }
13902
5.54k
#ifdef XPATH_STREAMING
13903
5.54k
    if (ctxt->comp->stream) {
13904
494
  int res;
13905
13906
494
  if (toBool) {
13907
      /*
13908
      * Evaluation to boolean result.
13909
      */
13910
0
      res = xmlXPathRunStreamEval(ctxt->context,
13911
0
    ctxt->comp->stream, NULL, 1);
13912
0
      if (res != -1)
13913
0
    return(res);
13914
494
  } else {
13915
494
      xmlXPathObjectPtr resObj = NULL;
13916
13917
      /*
13918
      * Evaluation to a sequence.
13919
      */
13920
494
      res = xmlXPathRunStreamEval(ctxt->context,
13921
494
    ctxt->comp->stream, &resObj, 0);
13922
13923
494
      if ((res != -1) && (resObj != NULL)) {
13924
494
    valuePush(ctxt, resObj);
13925
494
    return(0);
13926
494
      }
13927
0
      if (resObj != NULL)
13928
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13929
0
  }
13930
  /*
13931
  * QUESTION TODO: This falls back to normal XPath evaluation
13932
  * if res == -1. Is this intended?
13933
  */
13934
494
    }
13935
5.05k
#endif
13936
5.05k
    comp = ctxt->comp;
13937
5.05k
    if (comp->last < 0) {
13938
0
  xmlGenericError(xmlGenericErrorContext,
13939
0
      "xmlXPathRunEval: last is less than zero\n");
13940
0
  return(-1);
13941
0
    }
13942
5.05k
    oldDepth = ctxt->context->depth;
13943
5.05k
    if (toBool)
13944
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13945
0
      &comp->steps[comp->last], 0));
13946
5.05k
    else
13947
5.05k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13948
5.05k
    ctxt->context->depth = oldDepth;
13949
13950
5.05k
    return(0);
13951
5.05k
}
13952
13953
/************************************************************************
13954
 *                  *
13955
 *      Public interfaces       *
13956
 *                  *
13957
 ************************************************************************/
13958
13959
/**
13960
 * xmlXPathEvalPredicate:
13961
 * @ctxt:  the XPath context
13962
 * @res:  the Predicate Expression evaluation result
13963
 *
13964
 * Evaluate a predicate result for the current node.
13965
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13966
 * the result to a boolean. If the result is a number, the result will
13967
 * be converted to true if the number is equal to the position of the
13968
 * context node in the context node list (as returned by the position
13969
 * function) and will be converted to false otherwise; if the result
13970
 * is not a number, then the result will be converted as if by a call
13971
 * to the boolean function.
13972
 *
13973
 * Returns 1 if predicate is true, 0 otherwise
13974
 */
13975
int
13976
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13977
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13978
0
    switch (res->type) {
13979
0
        case XPATH_BOOLEAN:
13980
0
      return(res->boolval);
13981
0
        case XPATH_NUMBER:
13982
0
      return(res->floatval == ctxt->proximityPosition);
13983
0
        case XPATH_NODESET:
13984
0
        case XPATH_XSLT_TREE:
13985
0
      if (res->nodesetval == NULL)
13986
0
    return(0);
13987
0
      return(res->nodesetval->nodeNr != 0);
13988
0
        case XPATH_STRING:
13989
0
      return((res->stringval != NULL) &&
13990
0
             (xmlStrlen(res->stringval) != 0));
13991
0
        default:
13992
0
      STRANGE
13993
0
    }
13994
0
    return(0);
13995
0
}
13996
13997
/**
13998
 * xmlXPathEvaluatePredicateResult:
13999
 * @ctxt:  the XPath Parser context
14000
 * @res:  the Predicate Expression evaluation result
14001
 *
14002
 * Evaluate a predicate result for the current node.
14003
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14004
 * the result to a boolean. If the result is a number, the result will
14005
 * be converted to true if the number is equal to the position of the
14006
 * context node in the context node list (as returned by the position
14007
 * function) and will be converted to false otherwise; if the result
14008
 * is not a number, then the result will be converted as if by a call
14009
 * to the boolean function.
14010
 *
14011
 * Returns 1 if predicate is true, 0 otherwise
14012
 */
14013
int
14014
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14015
1.07M
                                xmlXPathObjectPtr res) {
14016
1.07M
    if ((ctxt == NULL) || (res == NULL)) return(0);
14017
1.07M
    switch (res->type) {
14018
0
        case XPATH_BOOLEAN:
14019
0
      return(res->boolval);
14020
532k
        case XPATH_NUMBER:
14021
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14022
      return((res->floatval == ctxt->context->proximityPosition) &&
14023
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14024
#else
14025
532k
      return(res->floatval == ctxt->context->proximityPosition);
14026
0
#endif
14027
542k
        case XPATH_NODESET:
14028
542k
        case XPATH_XSLT_TREE:
14029
542k
      if (res->nodesetval == NULL)
14030
36.0k
    return(0);
14031
506k
      return(res->nodesetval->nodeNr != 0);
14032
2.67k
        case XPATH_STRING:
14033
2.67k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14034
#ifdef LIBXML_XPTR_LOCS_ENABLED
14035
  case XPATH_LOCATIONSET:{
14036
      xmlLocationSetPtr ptr = res->user;
14037
      if (ptr == NULL)
14038
          return(0);
14039
      return (ptr->locNr != 0);
14040
      }
14041
#endif
14042
0
        default:
14043
0
      STRANGE
14044
1.07M
    }
14045
0
    return(0);
14046
1.07M
}
14047
14048
#ifdef XPATH_STREAMING
14049
/**
14050
 * xmlXPathTryStreamCompile:
14051
 * @ctxt: an XPath context
14052
 * @str:  the XPath expression
14053
 *
14054
 * Try to compile the XPath expression as a streamable subset.
14055
 *
14056
 * Returns the compiled expression or NULL if failed to compile.
14057
 */
14058
static xmlXPathCompExprPtr
14059
7.68k
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14060
    /*
14061
     * Optimization: use streaming patterns when the XPath expression can
14062
     * be compiled to a stream lookup
14063
     */
14064
7.68k
    xmlPatternPtr stream;
14065
7.68k
    xmlXPathCompExprPtr comp;
14066
7.68k
    xmlDictPtr dict = NULL;
14067
7.68k
    const xmlChar **namespaces = NULL;
14068
7.68k
    xmlNsPtr ns;
14069
7.68k
    int i, j;
14070
14071
7.68k
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14072
7.68k
        (!xmlStrchr(str, '@'))) {
14073
3.55k
  const xmlChar *tmp;
14074
14075
  /*
14076
   * We don't try to handle expressions using the verbose axis
14077
   * specifiers ("::"), just the simplified form at this point.
14078
   * Additionally, if there is no list of namespaces available and
14079
   *  there's a ":" in the expression, indicating a prefixed QName,
14080
   *  then we won't try to compile either. xmlPatterncompile() needs
14081
   *  to have a list of namespaces at compilation time in order to
14082
   *  compile prefixed name tests.
14083
   */
14084
3.55k
  tmp = xmlStrchr(str, ':');
14085
3.55k
  if ((tmp != NULL) &&
14086
3.55k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14087
300
      return(NULL);
14088
14089
3.25k
  if (ctxt != NULL) {
14090
3.25k
      dict = ctxt->dict;
14091
3.25k
      if (ctxt->nsNr > 0) {
14092
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14093
0
    if (namespaces == NULL) {
14094
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14095
0
        return(NULL);
14096
0
    }
14097
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14098
0
        ns = ctxt->namespaces[j];
14099
0
        namespaces[i++] = ns->href;
14100
0
        namespaces[i++] = ns->prefix;
14101
0
    }
14102
0
    namespaces[i++] = NULL;
14103
0
    namespaces[i] = NULL;
14104
0
      }
14105
3.25k
  }
14106
14107
3.25k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14108
3.25k
  if (namespaces != NULL) {
14109
0
      xmlFree((xmlChar **)namespaces);
14110
0
  }
14111
3.25k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14112
494
      comp = xmlXPathNewCompExpr();
14113
494
      if (comp == NULL) {
14114
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14115
0
    return(NULL);
14116
0
      }
14117
494
      comp->stream = stream;
14118
494
      comp->dict = dict;
14119
494
      if (comp->dict)
14120
0
    xmlDictReference(comp->dict);
14121
494
      return(comp);
14122
494
  }
14123
2.76k
  xmlFreePattern(stream);
14124
2.76k
    }
14125
6.88k
    return(NULL);
14126
7.68k
}
14127
#endif /* XPATH_STREAMING */
14128
14129
static void
14130
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14131
                           xmlXPathStepOpPtr op)
14132
476k
{
14133
476k
    xmlXPathCompExprPtr comp = pctxt->comp;
14134
476k
    xmlXPathContextPtr ctxt;
14135
14136
    /*
14137
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14138
    * internal representation.
14139
    */
14140
14141
476k
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14142
476k
        (op->ch1 != -1) &&
14143
476k
        (op->ch2 == -1 /* no predicate */))
14144
175k
    {
14145
175k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14146
14147
175k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14148
175k
            ((xmlXPathAxisVal) prevop->value ==
14149
79.6k
                AXIS_DESCENDANT_OR_SELF) &&
14150
175k
            (prevop->ch2 == -1) &&
14151
175k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14152
175k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14153
30.1k
        {
14154
            /*
14155
            * This is a "descendant-or-self::node()" without predicates.
14156
            * Try to eliminate it.
14157
            */
14158
14159
30.1k
            switch ((xmlXPathAxisVal) op->value) {
14160
23.7k
                case AXIS_CHILD:
14161
23.7k
                case AXIS_DESCENDANT:
14162
                    /*
14163
                    * Convert "descendant-or-self::node()/child::" or
14164
                    * "descendant-or-self::node()/descendant::" to
14165
                    * "descendant::"
14166
                    */
14167
23.7k
                    op->ch1   = prevop->ch1;
14168
23.7k
                    op->value = AXIS_DESCENDANT;
14169
23.7k
                    break;
14170
0
                case AXIS_SELF:
14171
973
                case AXIS_DESCENDANT_OR_SELF:
14172
                    /*
14173
                    * Convert "descendant-or-self::node()/self::" or
14174
                    * "descendant-or-self::node()/descendant-or-self::" to
14175
                    * to "descendant-or-self::"
14176
                    */
14177
973
                    op->ch1   = prevop->ch1;
14178
973
                    op->value = AXIS_DESCENDANT_OR_SELF;
14179
973
                    break;
14180
5.41k
                default:
14181
5.41k
                    break;
14182
30.1k
            }
14183
30.1k
  }
14184
175k
    }
14185
14186
    /* OP_VALUE has invalid ch1. */
14187
476k
    if (op->op == XPATH_OP_VALUE)
14188
13.5k
        return;
14189
14190
    /* Recurse */
14191
462k
    ctxt = pctxt->context;
14192
462k
    if (ctxt != NULL) {
14193
462k
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14194
0
            return;
14195
462k
        ctxt->depth += 1;
14196
462k
    }
14197
462k
    if (op->ch1 != -1)
14198
329k
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14199
462k
    if (op->ch2 != -1)
14200
141k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14201
462k
    if (ctxt != NULL)
14202
462k
        ctxt->depth -= 1;
14203
462k
}
14204
14205
/**
14206
 * xmlXPathCtxtCompile:
14207
 * @ctxt: an XPath context
14208
 * @str:  the XPath expression
14209
 *
14210
 * Compile an XPath expression
14211
 *
14212
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14213
 *         the caller has to free the object.
14214
 */
14215
xmlXPathCompExprPtr
14216
7.32k
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14217
7.32k
    xmlXPathParserContextPtr pctxt;
14218
7.32k
    xmlXPathCompExprPtr comp;
14219
7.32k
    int oldDepth = 0;
14220
14221
7.32k
#ifdef XPATH_STREAMING
14222
7.32k
    comp = xmlXPathTryStreamCompile(ctxt, str);
14223
7.32k
    if (comp != NULL)
14224
494
        return(comp);
14225
6.82k
#endif
14226
14227
6.82k
    xmlInitParser();
14228
14229
6.82k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14230
6.82k
    if (pctxt == NULL)
14231
0
        return NULL;
14232
6.82k
    if (ctxt != NULL)
14233
6.82k
        oldDepth = ctxt->depth;
14234
6.82k
    xmlXPathCompileExpr(pctxt, 1);
14235
6.82k
    if (ctxt != NULL)
14236
6.82k
        ctxt->depth = oldDepth;
14237
14238
6.82k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14239
1.66k
    {
14240
1.66k
        xmlXPathFreeParserContext(pctxt);
14241
1.66k
        return(NULL);
14242
1.66k
    }
14243
14244
5.16k
    if (*pctxt->cur != 0) {
14245
  /*
14246
   * aleksey: in some cases this line prints *second* error message
14247
   * (see bug #78858) and probably this should be fixed.
14248
   * However, we are not sure that all error messages are printed
14249
   * out in other places. It's not critical so we leave it as-is for now
14250
   */
14251
475
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14252
475
  comp = NULL;
14253
4.68k
    } else {
14254
4.68k
  comp = pctxt->comp;
14255
4.68k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14256
4.66k
            if (ctxt != NULL)
14257
4.66k
                oldDepth = ctxt->depth;
14258
4.66k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14259
4.66k
            if (ctxt != NULL)
14260
4.66k
                ctxt->depth = oldDepth;
14261
4.66k
  }
14262
4.68k
  pctxt->comp = NULL;
14263
4.68k
    }
14264
5.16k
    xmlXPathFreeParserContext(pctxt);
14265
14266
5.16k
    if (comp != NULL) {
14267
4.68k
  comp->expr = xmlStrdup(str);
14268
#ifdef DEBUG_EVAL_COUNTS
14269
  comp->string = xmlStrdup(str);
14270
  comp->nb = 0;
14271
#endif
14272
4.68k
    }
14273
5.16k
    return(comp);
14274
6.82k
}
14275
14276
/**
14277
 * xmlXPathCompile:
14278
 * @str:  the XPath expression
14279
 *
14280
 * Compile an XPath expression
14281
 *
14282
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14283
 *         the caller has to free the object.
14284
 */
14285
xmlXPathCompExprPtr
14286
0
xmlXPathCompile(const xmlChar *str) {
14287
0
    return(xmlXPathCtxtCompile(NULL, str));
14288
0
}
14289
14290
/**
14291
 * xmlXPathCompiledEvalInternal:
14292
 * @comp:  the compiled XPath expression
14293
 * @ctxt:  the XPath context
14294
 * @resObj: the resulting XPath object or NULL
14295
 * @toBool: 1 if only a boolean result is requested
14296
 *
14297
 * Evaluate the Precompiled XPath expression in the given context.
14298
 * The caller has to free @resObj.
14299
 *
14300
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14301
 *         the caller has to free the object.
14302
 */
14303
static int
14304
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14305
           xmlXPathContextPtr ctxt,
14306
           xmlXPathObjectPtr *resObjPtr,
14307
           int toBool)
14308
5.18k
{
14309
5.18k
    xmlXPathParserContextPtr pctxt;
14310
5.18k
    xmlXPathObjectPtr resObj;
14311
#ifndef LIBXML_THREAD_ENABLED
14312
    static int reentance = 0;
14313
#endif
14314
5.18k
    int res;
14315
14316
5.18k
    CHECK_CTXT_NEG(ctxt)
14317
14318
5.18k
    if (comp == NULL)
14319
0
  return(-1);
14320
5.18k
    xmlInitParser();
14321
14322
#ifndef LIBXML_THREAD_ENABLED
14323
    reentance++;
14324
    if (reentance > 1)
14325
  xmlXPathDisableOptimizer = 1;
14326
#endif
14327
14328
#ifdef DEBUG_EVAL_COUNTS
14329
    comp->nb++;
14330
    if ((comp->string != NULL) && (comp->nb > 100)) {
14331
  fprintf(stderr, "100 x %s\n", comp->string);
14332
  comp->nb = 0;
14333
    }
14334
#endif
14335
5.18k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14336
5.18k
    res = xmlXPathRunEval(pctxt, toBool);
14337
14338
5.18k
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14339
1.04k
        resObj = NULL;
14340
4.14k
    } else {
14341
4.14k
        resObj = valuePop(pctxt);
14342
4.14k
        if (resObj == NULL) {
14343
0
            if (!toBool)
14344
0
                xmlGenericError(xmlGenericErrorContext,
14345
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14346
4.14k
        } else if (pctxt->valueNr > 0) {
14347
0
            xmlGenericError(xmlGenericErrorContext,
14348
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14349
0
                pctxt->valueNr);
14350
0
        }
14351
4.14k
    }
14352
14353
5.18k
    if (resObjPtr)
14354
5.18k
        *resObjPtr = resObj;
14355
0
    else
14356
0
        xmlXPathReleaseObject(ctxt, resObj);
14357
14358
5.18k
    pctxt->comp = NULL;
14359
5.18k
    xmlXPathFreeParserContext(pctxt);
14360
#ifndef LIBXML_THREAD_ENABLED
14361
    reentance--;
14362
#endif
14363
14364
5.18k
    return(res);
14365
5.18k
}
14366
14367
/**
14368
 * xmlXPathCompiledEval:
14369
 * @comp:  the compiled XPath expression
14370
 * @ctx:  the XPath context
14371
 *
14372
 * Evaluate the Precompiled XPath expression in the given context.
14373
 *
14374
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14375
 *         the caller has to free the object.
14376
 */
14377
xmlXPathObjectPtr
14378
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14379
5.18k
{
14380
5.18k
    xmlXPathObjectPtr res = NULL;
14381
14382
5.18k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14383
5.18k
    return(res);
14384
5.18k
}
14385
14386
/**
14387
 * xmlXPathCompiledEvalToBoolean:
14388
 * @comp:  the compiled XPath expression
14389
 * @ctxt:  the XPath context
14390
 *
14391
 * Applies the XPath boolean() function on the result of the given
14392
 * compiled expression.
14393
 *
14394
 * Returns 1 if the expression evaluated to true, 0 if to false and
14395
 *         -1 in API and internal errors.
14396
 */
14397
int
14398
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14399
            xmlXPathContextPtr ctxt)
14400
0
{
14401
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14402
0
}
14403
14404
/**
14405
 * xmlXPathEvalExpr:
14406
 * @ctxt:  the XPath Parser context
14407
 *
14408
 * Parse and evaluate an XPath expression in the given context,
14409
 * then push the result on the context stack
14410
 */
14411
void
14412
363
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14413
363
#ifdef XPATH_STREAMING
14414
363
    xmlXPathCompExprPtr comp;
14415
363
#endif
14416
363
    int oldDepth = 0;
14417
14418
363
    if (ctxt == NULL) return;
14419
14420
363
#ifdef XPATH_STREAMING
14421
363
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14422
363
    if (comp != NULL) {
14423
0
        if (ctxt->comp != NULL)
14424
0
      xmlXPathFreeCompExpr(ctxt->comp);
14425
0
        ctxt->comp = comp;
14426
0
    } else
14427
363
#endif
14428
363
    {
14429
363
        if (ctxt->context != NULL)
14430
363
            oldDepth = ctxt->context->depth;
14431
363
  xmlXPathCompileExpr(ctxt, 1);
14432
363
        if (ctxt->context != NULL)
14433
363
            ctxt->context->depth = oldDepth;
14434
363
        CHECK_ERROR;
14435
14436
        /* Check for trailing characters. */
14437
363
        if (*ctxt->cur != 0)
14438
363
            XP_ERROR(XPATH_EXPR_ERROR);
14439
14440
363
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14441
363
            if (ctxt->context != NULL)
14442
363
                oldDepth = ctxt->context->depth;
14443
363
      xmlXPathOptimizeExpression(ctxt,
14444
363
    &ctxt->comp->steps[ctxt->comp->last]);
14445
363
            if (ctxt->context != NULL)
14446
363
                ctxt->context->depth = oldDepth;
14447
363
        }
14448
363
    }
14449
14450
363
    xmlXPathRunEval(ctxt, 0);
14451
363
}
14452
14453
/**
14454
 * xmlXPathEval:
14455
 * @str:  the XPath expression
14456
 * @ctx:  the XPath context
14457
 *
14458
 * Evaluate the XPath Location Path in the given context.
14459
 *
14460
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14461
 *         the caller has to free the object.
14462
 */
14463
xmlXPathObjectPtr
14464
363
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14465
363
    xmlXPathParserContextPtr ctxt;
14466
363
    xmlXPathObjectPtr res;
14467
14468
363
    CHECK_CTXT(ctx)
14469
14470
363
    xmlInitParser();
14471
14472
363
    ctxt = xmlXPathNewParserContext(str, ctx);
14473
363
    if (ctxt == NULL)
14474
0
        return NULL;
14475
363
    xmlXPathEvalExpr(ctxt);
14476
14477
363
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14478
0
  res = NULL;
14479
363
    } else {
14480
363
  res = valuePop(ctxt);
14481
363
        if (res == NULL) {
14482
0
            xmlGenericError(xmlGenericErrorContext,
14483
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14484
363
        } else if (ctxt->valueNr > 0) {
14485
0
            xmlGenericError(xmlGenericErrorContext,
14486
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14487
0
                ctxt->valueNr);
14488
0
        }
14489
363
    }
14490
14491
363
    xmlXPathFreeParserContext(ctxt);
14492
363
    return(res);
14493
363
}
14494
14495
/**
14496
 * xmlXPathSetContextNode:
14497
 * @node: the node to to use as the context node
14498
 * @ctx:  the XPath context
14499
 *
14500
 * Sets 'node' as the context node. The node must be in the same
14501
 * document as that associated with the context.
14502
 *
14503
 * Returns -1 in case of error or 0 if successful
14504
 */
14505
int
14506
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14507
0
    if ((node == NULL) || (ctx == NULL))
14508
0
        return(-1);
14509
14510
0
    if (node->doc == ctx->doc) {
14511
0
        ctx->node = node;
14512
0
  return(0);
14513
0
    }
14514
0
    return(-1);
14515
0
}
14516
14517
/**
14518
 * xmlXPathNodeEval:
14519
 * @node: the node to to use as the context node
14520
 * @str:  the XPath expression
14521
 * @ctx:  the XPath context
14522
 *
14523
 * Evaluate the XPath Location Path in the given context. The node 'node'
14524
 * is set as the context node. The context node is not restored.
14525
 *
14526
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14527
 *         the caller has to free the object.
14528
 */
14529
xmlXPathObjectPtr
14530
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14531
0
    if (str == NULL)
14532
0
        return(NULL);
14533
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14534
0
        return(NULL);
14535
0
    return(xmlXPathEval(str, ctx));
14536
0
}
14537
14538
/**
14539
 * xmlXPathEvalExpression:
14540
 * @str:  the XPath expression
14541
 * @ctxt:  the XPath context
14542
 *
14543
 * Alias for xmlXPathEval().
14544
 *
14545
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14546
 *         the caller has to free the object.
14547
 */
14548
xmlXPathObjectPtr
14549
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14550
0
    return(xmlXPathEval(str, ctxt));
14551
0
}
14552
14553
/************************************************************************
14554
 *                  *
14555
 *  Extra functions not pertaining to the XPath spec    *
14556
 *                  *
14557
 ************************************************************************/
14558
/**
14559
 * xmlXPathEscapeUriFunction:
14560
 * @ctxt:  the XPath Parser context
14561
 * @nargs:  the number of arguments
14562
 *
14563
 * Implement the escape-uri() XPath function
14564
 *    string escape-uri(string $str, bool $escape-reserved)
14565
 *
14566
 * This function applies the URI escaping rules defined in section 2 of [RFC
14567
 * 2396] to the string supplied as $uri-part, which typically represents all
14568
 * or part of a URI. The effect of the function is to replace any special
14569
 * character in the string by an escape sequence of the form %xx%yy...,
14570
 * where xxyy... is the hexadecimal representation of the octets used to
14571
 * represent the character in UTF-8.
14572
 *
14573
 * The set of characters that are escaped depends on the setting of the
14574
 * boolean argument $escape-reserved.
14575
 *
14576
 * If $escape-reserved is true, all characters are escaped other than lower
14577
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14578
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14579
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14580
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14581
 * A-F).
14582
 *
14583
 * If $escape-reserved is false, the behavior differs in that characters
14584
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14585
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14586
 *
14587
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14588
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14589
 * compared using string comparison functions, this function must always use
14590
 * the upper-case letters A-F.
14591
 *
14592
 * Generally, $escape-reserved should be set to true when escaping a string
14593
 * that is to form a single part of a URI, and to false when escaping an
14594
 * entire URI or URI reference.
14595
 *
14596
 * In the case of non-ascii characters, the string is encoded according to
14597
 * utf-8 and then converted according to RFC 2396.
14598
 *
14599
 * Examples
14600
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14601
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14602
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14603
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14604
 *
14605
 */
14606
static void
14607
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14608
0
    xmlXPathObjectPtr str;
14609
0
    int escape_reserved;
14610
0
    xmlBufPtr target;
14611
0
    xmlChar *cptr;
14612
0
    xmlChar escape[4];
14613
14614
0
    CHECK_ARITY(2);
14615
14616
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14617
14618
0
    CAST_TO_STRING;
14619
0
    str = valuePop(ctxt);
14620
14621
0
    target = xmlBufCreate();
14622
14623
0
    escape[0] = '%';
14624
0
    escape[3] = 0;
14625
14626
0
    if (target) {
14627
0
  for (cptr = str->stringval; *cptr; cptr++) {
14628
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14629
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14630
0
    (*cptr >= '0' && *cptr <= '9') ||
14631
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14632
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14633
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14634
0
    (*cptr == '%' &&
14635
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14636
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14637
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14638
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14639
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14640
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14641
0
    (!escape_reserved &&
14642
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14643
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14644
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14645
0
      *cptr == ','))) {
14646
0
    xmlBufAdd(target, cptr, 1);
14647
0
      } else {
14648
0
    if ((*cptr >> 4) < 10)
14649
0
        escape[1] = '0' + (*cptr >> 4);
14650
0
    else
14651
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14652
0
    if ((*cptr & 0xF) < 10)
14653
0
        escape[2] = '0' + (*cptr & 0xF);
14654
0
    else
14655
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14656
14657
0
    xmlBufAdd(target, &escape[0], 3);
14658
0
      }
14659
0
  }
14660
0
    }
14661
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14662
0
  xmlBufContent(target)));
14663
0
    xmlBufFree(target);
14664
0
    xmlXPathReleaseObject(ctxt->context, str);
14665
0
}
14666
14667
/**
14668
 * xmlXPathRegisterAllFunctions:
14669
 * @ctxt:  the XPath context
14670
 *
14671
 * Registers all default XPath functions in this context
14672
 */
14673
void
14674
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14675
726
{
14676
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14677
726
                         xmlXPathBooleanFunction);
14678
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14679
726
                         xmlXPathCeilingFunction);
14680
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14681
726
                         xmlXPathCountFunction);
14682
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14683
726
                         xmlXPathConcatFunction);
14684
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14685
726
                         xmlXPathContainsFunction);
14686
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14687
726
                         xmlXPathIdFunction);
14688
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14689
726
                         xmlXPathFalseFunction);
14690
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14691
726
                         xmlXPathFloorFunction);
14692
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14693
726
                         xmlXPathLastFunction);
14694
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14695
726
                         xmlXPathLangFunction);
14696
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14697
726
                         xmlXPathLocalNameFunction);
14698
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14699
726
                         xmlXPathNotFunction);
14700
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14701
726
                         xmlXPathNameFunction);
14702
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14703
726
                         xmlXPathNamespaceURIFunction);
14704
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14705
726
                         xmlXPathNormalizeFunction);
14706
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14707
726
                         xmlXPathNumberFunction);
14708
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14709
726
                         xmlXPathPositionFunction);
14710
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14711
726
                         xmlXPathRoundFunction);
14712
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14713
726
                         xmlXPathStringFunction);
14714
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14715
726
                         xmlXPathStringLengthFunction);
14716
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14717
726
                         xmlXPathStartsWithFunction);
14718
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14719
726
                         xmlXPathSubstringFunction);
14720
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14721
726
                         xmlXPathSubstringBeforeFunction);
14722
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14723
726
                         xmlXPathSubstringAfterFunction);
14724
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14725
726
                         xmlXPathSumFunction);
14726
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14727
726
                         xmlXPathTrueFunction);
14728
726
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14729
726
                         xmlXPathTranslateFunction);
14730
14731
726
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14732
726
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14733
726
                         xmlXPathEscapeUriFunction);
14734
726
}
14735
14736
#endif /* LIBXML_XPATH_ENABLED */