Coverage Report

Created: 2024-08-20 14:13

/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
29.4k
    xmlGenericError(xmlGenericErrorContext,       \
62
29.4k
      "Unimplemented block at %s:%d\n",       \
63
29.4k
            __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
1.92M
#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
15.0k
#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
7.37M
#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
244M
#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
75.9M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
162
75.9M
    int depth1, depth2;
163
75.9M
    int misc = 0, precedence1 = 0, precedence2 = 0;
164
75.9M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
165
75.9M
    xmlNodePtr cur, root;
166
75.9M
    ptrdiff_t l1, l2;
167
168
75.9M
    if ((node1 == NULL) || (node2 == NULL))
169
0
  return(-2);
170
171
75.9M
    if (node1 == node2)
172
0
  return(0);
173
174
    /*
175
     * a couple of optimizations which will avoid computations in most cases
176
     */
177
75.9M
    switch (node1->type) {
178
48.9M
  case XML_ELEMENT_NODE:
179
48.9M
      if (node2->type == XML_ELEMENT_NODE) {
180
38.3M
    if ((0 > (ptrdiff_t) node1->content) &&
181
38.3M
        (0 > (ptrdiff_t) node2->content) &&
182
38.3M
        (node1->doc == node2->doc))
183
28.3M
    {
184
28.3M
        l1 = -((ptrdiff_t) node1->content);
185
28.3M
        l2 = -((ptrdiff_t) node2->content);
186
28.3M
        if (l1 < l2)
187
23.0M
      return(1);
188
5.26M
        if (l1 > l2)
189
5.26M
      return(-1);
190
5.26M
    } else
191
9.97M
        goto turtle_comparison;
192
38.3M
      }
193
10.5M
      break;
194
10.5M
  case XML_ATTRIBUTE_NODE:
195
755k
      precedence1 = 1; /* element is owner */
196
755k
      miscNode1 = node1;
197
755k
      node1 = node1->parent;
198
755k
      misc = 1;
199
755k
      break;
200
20.9M
  case XML_TEXT_NODE:
201
21.7M
  case XML_CDATA_SECTION_NODE:
202
23.1M
  case XML_COMMENT_NODE:
203
24.6M
  case XML_PI_NODE: {
204
24.6M
      miscNode1 = node1;
205
      /*
206
      * Find nearest element node.
207
      */
208
24.6M
      if (node1->prev != NULL) {
209
19.0M
    do {
210
19.0M
        node1 = node1->prev;
211
19.0M
        if (node1->type == XML_ELEMENT_NODE) {
212
13.1M
      precedence1 = 3; /* element in prev-sibl axis */
213
13.1M
      break;
214
13.1M
        }
215
5.96M
        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
5.96M
    } while (1);
225
13.1M
      } else {
226
11.5M
    precedence1 = 2; /* element is parent */
227
11.5M
    node1 = node1->parent;
228
11.5M
      }
229
24.6M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
230
24.6M
    (0 <= (ptrdiff_t) node1->content)) {
231
    /*
232
    * Fallback for whatever case.
233
    */
234
3.71M
    node1 = miscNode1;
235
3.71M
    precedence1 = 0;
236
3.71M
      } else
237
20.9M
    misc = 1;
238
24.6M
  }
239
0
      break;
240
820k
  case XML_NAMESPACE_DECL:
241
      /*
242
      * TODO: why do we return 1 for namespace nodes?
243
      */
244
820k
      return(1);
245
849k
  default:
246
849k
      break;
247
75.9M
    }
248
36.8M
    switch (node2->type) {
249
11.1M
  case XML_ELEMENT_NODE:
250
11.1M
      break;
251
657k
  case XML_ATTRIBUTE_NODE:
252
657k
      precedence2 = 1; /* element is owner */
253
657k
      miscNode2 = node2;
254
657k
      node2 = node2->parent;
255
657k
      misc = 1;
256
657k
      break;
257
20.0M
  case XML_TEXT_NODE:
258
20.9M
  case XML_CDATA_SECTION_NODE:
259
22.3M
  case XML_COMMENT_NODE:
260
23.7M
  case XML_PI_NODE: {
261
23.7M
      miscNode2 = node2;
262
23.7M
      if (node2->prev != NULL) {
263
19.9M
    do {
264
19.9M
        node2 = node2->prev;
265
19.9M
        if (node2->type == XML_ELEMENT_NODE) {
266
13.0M
      precedence2 = 3; /* element in prev-sibl axis */
267
13.0M
      break;
268
13.0M
        }
269
6.91M
        if (node2->prev == NULL) {
270
0
      precedence2 = 2; /* element is parent */
271
0
      node2 = node2->parent;
272
0
      break;
273
0
        }
274
6.91M
    } while (1);
275
13.0M
      } else {
276
10.6M
    precedence2 = 2; /* element is parent */
277
10.6M
    node2 = node2->parent;
278
10.6M
      }
279
23.7M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
280
23.7M
    (0 <= (ptrdiff_t) node2->content))
281
3.29M
      {
282
3.29M
    node2 = miscNode2;
283
3.29M
    precedence2 = 0;
284
3.29M
      } else
285
20.4M
    misc = 1;
286
23.7M
  }
287
0
      break;
288
113k
  case XML_NAMESPACE_DECL:
289
113k
      return(1);
290
1.16M
  default:
291
1.16M
      break;
292
36.8M
    }
293
36.7M
    if (misc) {
294
30.1M
  if (node1 == node2) {
295
16.0M
      if (precedence1 == precedence2) {
296
    /*
297
    * The ugly case; but normally there aren't many
298
    * adjacent non-element nodes around.
299
    */
300
4.04M
    cur = miscNode2->prev;
301
4.30M
    while (cur != NULL) {
302
4.29M
        if (cur == miscNode1)
303
3.89M
      return(1);
304
393k
        if (cur->type == XML_ELEMENT_NODE)
305
132k
      return(-1);
306
261k
        cur = cur->prev;
307
261k
    }
308
9.99k
    return (-1);
309
11.9M
      } 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
11.9M
    if (precedence1 < precedence2)
316
11.3M
        return(1);
317
642k
    else
318
642k
        return(-1);
319
11.9M
      }
320
16.0M
  }
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
14.1M
  if ((precedence2 == 3) && (precedence1 > 1)) {
331
2.50M
      cur = node1->parent;
332
5.35M
      while (cur) {
333
4.20M
    if (cur == node2)
334
1.35M
        return(1);
335
2.84M
    cur = cur->parent;
336
2.84M
      }
337
2.50M
  }
338
12.7M
  if ((precedence1 == 3) && (precedence2 > 1)) {
339
1.45M
      cur = node2->parent;
340
4.70M
      while (cur) {
341
3.43M
    if (cur == node1)
342
189k
        return(-1);
343
3.24M
    cur = cur->parent;
344
3.24M
      }
345
1.45M
  }
346
12.7M
    }
347
348
    /*
349
     * Speedup using document order if available.
350
     */
351
19.1M
    if ((node1->type == XML_ELEMENT_NODE) &&
352
19.1M
  (node2->type == XML_ELEMENT_NODE) &&
353
19.1M
  (0 > (ptrdiff_t) node1->content) &&
354
19.1M
  (0 > (ptrdiff_t) node2->content) &&
355
19.1M
  (node1->doc == node2->doc)) {
356
357
11.8M
  l1 = -((ptrdiff_t) node1->content);
358
11.8M
  l2 = -((ptrdiff_t) node2->content);
359
11.8M
  if (l1 < l2)
360
9.21M
      return(1);
361
2.59M
  if (l1 > l2)
362
2.59M
      return(-1);
363
2.59M
    }
364
365
17.3M
turtle_comparison:
366
367
17.3M
    if (node1 == node2->prev)
368
9.82M
  return(1);
369
7.47M
    if (node1 == node2->next)
370
218k
  return(-1);
371
    /*
372
     * compute depth to root
373
     */
374
13.7M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
375
8.16M
  if (cur->parent == node1)
376
1.69M
      return(1);
377
6.47M
  depth2++;
378
6.47M
    }
379
5.56M
    root = cur;
380
13.8M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
381
9.76M
  if (cur->parent == node2)
382
1.44M
      return(-1);
383
8.31M
  depth1++;
384
8.31M
    }
385
    /*
386
     * Distinct document (or distinct entities :-( ) case.
387
     */
388
4.11M
    if (root != cur) {
389
489k
  return(-2);
390
489k
    }
391
    /*
392
     * get the nearest common ancestor.
393
     */
394
5.34M
    while (depth1 > depth2) {
395
1.71M
  depth1--;
396
1.71M
  node1 = node1->parent;
397
1.71M
    }
398
4.47M
    while (depth2 > depth1) {
399
843k
  depth2--;
400
843k
  node2 = node2->parent;
401
843k
    }
402
4.55M
    while (node1->parent != node2->parent) {
403
929k
  node1 = node1->parent;
404
929k
  node2 = node2->parent;
405
  /* should not happen but just in case ... */
406
929k
  if ((node1 == NULL) || (node2 == NULL))
407
0
      return(-2);
408
929k
    }
409
    /*
410
     * Find who's first.
411
     */
412
3.62M
    if (node1 == node2->prev)
413
1.31M
  return(1);
414
2.31M
    if (node1 == node2->next)
415
813k
  return(-1);
416
    /*
417
     * Speedup using document order if available.
418
     */
419
1.50M
    if ((node1->type == XML_ELEMENT_NODE) &&
420
1.50M
  (node2->type == XML_ELEMENT_NODE) &&
421
1.50M
  (0 > (ptrdiff_t) node1->content) &&
422
1.50M
  (0 > (ptrdiff_t) node2->content) &&
423
1.50M
  (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
194M
    for (cur = node1->next;cur != NULL;cur = cur->next)
434
193M
  if (cur == node2)
435
671k
      return(1);
436
830k
    return(-1); /* assume there is no sibling list corruption */
437
1.50M
}
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
55.7M
#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
75.8M
    {
461
75.8M
        int res = xmlXPathCmpNodesExt(x, y);
462
75.8M
        return res == -2 ? res : -res;
463
75.8M
    }
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
75.8M
#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
3.33k
xmlInitXPathInternal(void) {
505
3.33k
#if defined(NAN) && defined(INFINITY)
506
3.33k
    xmlXPathNAN = NAN;
507
3.33k
    xmlXPathPINF = INFINITY;
508
3.33k
    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
3.33k
}
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
18.8M
xmlXPathIsNaN(double val) {
526
18.8M
#ifdef isnan
527
18.8M
    return isnan(val);
528
#else
529
    return !(val == val);
530
#endif
531
18.8M
}
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
4.97M
xmlXPathIsInf(double val) {
541
4.97M
#ifdef isinf
542
4.97M
    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
4.97M
}
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
561k
    { 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
16.6M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
632
16.6M
       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
16.6M
{
704
16.6M
    if ((error < 0) || (error > MAXERRNO))
705
0
  error = MAXERRNO;
706
16.6M
    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
16.6M
    ctxt->error = error;
716
16.6M
    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
16.6M
    xmlResetError(&ctxt->context->lastError);
729
730
16.6M
    ctxt->context->lastError.domain = XML_FROM_XPATH;
731
16.6M
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732
16.6M
                           XPATH_EXPRESSION_OK;
733
16.6M
    ctxt->context->lastError.level = XML_ERR_ERROR;
734
16.6M
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735
16.6M
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736
16.6M
    ctxt->context->lastError.node = ctxt->context->debugNode;
737
16.6M
    if (ctxt->context->error != NULL) {
738
0
  ctxt->context->error(ctxt->context->userData,
739
0
                       &ctxt->context->lastError);
740
16.6M
    } else {
741
16.6M
  __xmlRaiseError(NULL, NULL, NULL,
742
16.6M
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743
16.6M
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744
16.6M
      XML_ERR_ERROR, NULL, 0,
745
16.6M
      (const char *) ctxt->base, NULL, NULL,
746
16.6M
      ctxt->cur - ctxt->base, 0,
747
16.6M
      "%s", xmlXPathErrorMessages[error]);
748
16.6M
    }
749
750
16.6M
}
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
1.04M
              int line ATTRIBUTE_UNUSED, int no) {
764
1.04M
    xmlXPathErr(ctxt, no);
765
1.04M
}
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
607M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
777
607M
    xmlXPathContextPtr xpctxt = ctxt->context;
778
779
607M
    if ((opCount > xpctxt->opLimit) ||
780
607M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
781
36
        xpctxt->opCount = xpctxt->opLimit;
782
36
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
783
36
        return(-1);
784
36
    }
785
786
607M
    xpctxt->opCount += opCount;
787
607M
    return(0);
788
607M
}
789
790
#define OP_LIMIT_EXCEEDED(ctxt, n) \
791
591M
    ((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
156M
{
820
156M
    if (list->items == NULL) {
821
940k
  if (initialSize <= 0)
822
0
      initialSize = 1;
823
940k
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
824
940k
  if (list->items == NULL) {
825
0
      xmlXPathErrMemory(NULL,
826
0
    "xmlPointerListCreate: allocating item\n");
827
0
      return(-1);
828
0
  }
829
940k
  list->number = 0;
830
940k
  list->size = initialSize;
831
155M
    } else if (list->size <= list->number) {
832
590k
        if (list->size > 50000000) {
833
0
      xmlXPathErrMemory(NULL,
834
0
    "xmlPointerListAddSize: re-allocating item\n");
835
0
            return(-1);
836
0
        }
837
590k
  list->size *= 2;
838
590k
  list->items = (void **) xmlRealloc(list->items,
839
590k
      list->size * sizeof(void *));
840
590k
  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
590k
    }
847
156M
    list->items[list->number++] = item;
848
156M
    return(0);
849
156M
}
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
940k
{
861
940k
    xmlPointerListPtr ret;
862
863
940k
    ret = xmlMalloc(sizeof(xmlPointerList));
864
940k
    if (ret == NULL) {
865
0
  xmlXPathErrMemory(NULL,
866
0
      "xmlPointerListCreate: allocating item\n");
867
0
  return (NULL);
868
0
    }
869
940k
    memset(ret, 0, sizeof(xmlPointerList));
870
940k
    if (initialSize > 0) {
871
940k
  xmlPointerListAddSize(ret, NULL, initialSize);
872
940k
  ret->number = 0;
873
940k
    }
874
940k
    return (ret);
875
940k
}
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
939k
{
886
939k
    if (list == NULL)
887
0
  return;
888
939k
    if (list->items != NULL)
889
939k
  xmlFree(list->items);
890
939k
    xmlFree(list);
891
939k
}
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.41M
xmlXPathNewCompExpr(void) {
1024
7.41M
    xmlXPathCompExprPtr cur;
1025
1026
7.41M
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1027
7.41M
    if (cur == NULL) {
1028
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1029
0
  return(NULL);
1030
0
    }
1031
7.41M
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1032
7.41M
    cur->maxStep = 10;
1033
7.41M
    cur->nbStep = 0;
1034
7.41M
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1035
7.41M
                                     sizeof(xmlXPathStepOp));
1036
7.41M
    if (cur->steps == NULL) {
1037
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1038
0
  xmlFree(cur);
1039
0
  return(NULL);
1040
0
    }
1041
7.41M
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1042
7.41M
    cur->last = -1;
1043
#ifdef DEBUG_EVAL_COUNTS
1044
    cur->nb = 0;
1045
#endif
1046
7.41M
    return(cur);
1047
7.41M
}
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.41M
{
1058
7.41M
    xmlXPathStepOpPtr op;
1059
7.41M
    int i;
1060
1061
7.41M
    if (comp == NULL)
1062
0
        return;
1063
7.41M
    if (comp->dict == NULL) {
1064
71.8M
  for (i = 0; i < comp->nbStep; i++) {
1065
64.4M
      op = &comp->steps[i];
1066
64.4M
      if (op->value4 != NULL) {
1067
4.41M
    if (op->op == XPATH_OP_VALUE)
1068
2.89M
        xmlXPathFreeObject(op->value4);
1069
1.51M
    else
1070
1.51M
        xmlFree(op->value4);
1071
4.41M
      }
1072
64.4M
      if (op->value5 != NULL)
1073
7.79M
    xmlFree(op->value5);
1074
64.4M
  }
1075
7.41M
    } 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.41M
    if (comp->steps != NULL) {
1086
7.41M
        xmlFree(comp->steps);
1087
7.41M
    }
1088
#ifdef DEBUG_EVAL_COUNTS
1089
    if (comp->string != NULL) {
1090
        xmlFree(comp->string);
1091
    }
1092
#endif
1093
7.41M
#ifdef XPATH_STREAMING
1094
7.41M
    if (comp->stream != NULL) {
1095
1.28M
        xmlFreePatternList(comp->stream);
1096
1.28M
    }
1097
7.41M
#endif
1098
7.41M
    if (comp->expr != NULL) {
1099
834k
        xmlFree(comp->expr);
1100
834k
    }
1101
1102
7.41M
    xmlFree(comp);
1103
7.41M
}
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
64.5M
   int value2, int value3, void *value4, void *value5) {
1125
64.5M
    xmlXPathCompExprPtr comp = ctxt->comp;
1126
64.5M
    if (comp->nbStep >= comp->maxStep) {
1127
1.92M
  xmlXPathStepOp *real;
1128
1129
1.92M
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1130
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1131
0
      return(-1);
1132
0
        }
1133
1.92M
  comp->maxStep *= 2;
1134
1.92M
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1135
1.92M
                          comp->maxStep * sizeof(xmlXPathStepOp));
1136
1.92M
  if (real == NULL) {
1137
0
      comp->maxStep /= 2;
1138
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1139
0
      return(-1);
1140
0
  }
1141
1.92M
  comp->steps = real;
1142
1.92M
    }
1143
64.5M
    comp->last = comp->nbStep;
1144
64.5M
    comp->steps[comp->nbStep].ch1 = ch1;
1145
64.5M
    comp->steps[comp->nbStep].ch2 = ch2;
1146
64.5M
    comp->steps[comp->nbStep].op = op;
1147
64.5M
    comp->steps[comp->nbStep].value = value;
1148
64.5M
    comp->steps[comp->nbStep].value2 = value2;
1149
64.5M
    comp->steps[comp->nbStep].value3 = value3;
1150
64.5M
    if ((comp->dict != NULL) &&
1151
64.5M
        ((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
64.5M
    } else {
1166
64.5M
  comp->steps[comp->nbStep].value4 = value4;
1167
64.5M
  comp->steps[comp->nbStep].value5 = value5;
1168
64.5M
    }
1169
64.5M
    comp->steps[comp->nbStep].cache = NULL;
1170
64.5M
    return(comp->nbStep++);
1171
64.5M
}
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
136k
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1182
136k
    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
136k
    tmp = op->ch1;
1195
136k
    op->ch1 = op->ch2;
1196
136k
    op->ch2 = tmp;
1197
136k
}
1198
1199
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1200
12.1M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1201
12.1M
                  (op), (val), (val2), (val3), (val4), (val5))
1202
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1203
7.69M
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1204
7.69M
                  (op), (val), (val2), (val3), (val4), (val5))
1205
1206
22.4M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1207
22.4M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1208
1209
3.38M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1210
3.38M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1211
1212
18.8M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1213
18.8M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1214
18.8M
      (val), (val2), 0 ,NULL ,NULL)
1215
1216
/************************************************************************
1217
 *                  *
1218
 *    XPath object cache structures       *
1219
 *                  *
1220
 ************************************************************************/
1221
1222
/* #define XP_DEFAULT_CACHE_ON */
1223
1224
22.7M
#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
817
    xmlGenericError(xmlGenericErrorContext,       \
1276
817
      "Internal error at %s:%d\n",        \
1277
817
            __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
1.72M
{
2212
1.72M
    xmlXPathContextCachePtr ret;
2213
2214
1.72M
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2215
1.72M
    if (ret == NULL) {
2216
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2217
0
  return(NULL);
2218
0
    }
2219
1.72M
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2220
1.72M
    ret->maxNodeset = 100;
2221
1.72M
    ret->maxString = 100;
2222
1.72M
    ret->maxBoolean = 100;
2223
1.72M
    ret->maxNumber = 100;
2224
1.72M
    ret->maxMisc = 100;
2225
1.72M
    return(ret);
2226
1.72M
}
2227
2228
static void
2229
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2230
939k
{
2231
939k
    int i;
2232
939k
    xmlXPathObjectPtr obj;
2233
2234
939k
    if (list == NULL)
2235
0
  return;
2236
2237
15.2M
    for (i = 0; i < list->number; i++) {
2238
14.2M
  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
14.2M
  if (obj->nodesetval != NULL) {
2244
10.8M
      if (obj->nodesetval->nodeTab != NULL)
2245
8.95M
    xmlFree(obj->nodesetval->nodeTab);
2246
10.8M
      xmlFree(obj->nodesetval);
2247
10.8M
  }
2248
14.2M
  xmlFree(obj);
2249
#ifdef XP_DEBUG_OBJ_USAGE
2250
  xmlXPathDebugObjCounterAll--;
2251
#endif
2252
14.2M
    }
2253
939k
    xmlPointerListFree(list);
2254
939k
}
2255
2256
static void
2257
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2258
1.71M
{
2259
1.71M
    if (cache == NULL)
2260
0
  return;
2261
1.71M
    if (cache->nodesetObjs)
2262
306k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2263
1.71M
    if (cache->stringObjs)
2264
183k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2265
1.71M
    if (cache->booleanObjs)
2266
121k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2267
1.71M
    if (cache->numberObjs)
2268
167k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2269
1.71M
    if (cache->miscObjs)
2270
159k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2271
1.71M
    xmlFree(cache);
2272
1.71M
}
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
3.43M
{
2302
3.43M
    if (ctxt == NULL)
2303
0
  return(-1);
2304
3.43M
    if (active) {
2305
1.72M
  xmlXPathContextCachePtr cache;
2306
2307
1.72M
  if (ctxt->cache == NULL) {
2308
1.72M
      ctxt->cache = xmlXPathNewCache();
2309
1.72M
      if (ctxt->cache == NULL)
2310
0
    return(-1);
2311
1.72M
  }
2312
1.72M
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2313
1.72M
  if (options == 0) {
2314
1.72M
      if (value < 0)
2315
1.72M
    value = 100;
2316
1.72M
      cache->maxNodeset = value;
2317
1.72M
      cache->maxString = value;
2318
1.72M
      cache->maxNumber = value;
2319
1.72M
      cache->maxBoolean = value;
2320
1.72M
      cache->maxMisc = value;
2321
1.72M
  }
2322
1.72M
    } else if (ctxt->cache != NULL) {
2323
1.71M
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2324
1.71M
  ctxt->cache = NULL;
2325
1.71M
    }
2326
3.43M
    return(0);
2327
3.43M
}
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
50.7M
{
2342
50.7M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2343
50.7M
  xmlXPathContextCachePtr cache =
2344
50.7M
      (xmlXPathContextCachePtr) ctxt->cache;
2345
2346
50.7M
  if ((cache->miscObjs != NULL) &&
2347
50.7M
      (cache->miscObjs->number != 0))
2348
38.0M
  {
2349
38.0M
      xmlXPathObjectPtr ret;
2350
2351
38.0M
      ret = (xmlXPathObjectPtr)
2352
38.0M
    cache->miscObjs->items[--cache->miscObjs->number];
2353
38.0M
      ret->type = XPATH_NODESET;
2354
38.0M
      ret->nodesetval = val;
2355
#ifdef XP_DEBUG_OBJ_USAGE
2356
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2357
#endif
2358
38.0M
      return(ret);
2359
38.0M
  }
2360
50.7M
    }
2361
2362
12.7M
    return(xmlXPathWrapNodeSet(val));
2363
2364
50.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
2.45M
{
2379
2.45M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2380
2.45M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2381
2382
2.45M
  if ((cache->stringObjs != NULL) &&
2383
2.45M
      (cache->stringObjs->number != 0))
2384
860k
  {
2385
2386
860k
      xmlXPathObjectPtr ret;
2387
2388
860k
      ret = (xmlXPathObjectPtr)
2389
860k
    cache->stringObjs->items[--cache->stringObjs->number];
2390
860k
      ret->type = XPATH_STRING;
2391
860k
      ret->stringval = val;
2392
#ifdef XP_DEBUG_OBJ_USAGE
2393
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2394
#endif
2395
860k
      return(ret);
2396
1.59M
  } else if ((cache->miscObjs != NULL) &&
2397
1.59M
      (cache->miscObjs->number != 0))
2398
979k
  {
2399
979k
      xmlXPathObjectPtr ret;
2400
      /*
2401
      * Fallback to misc-cache.
2402
      */
2403
979k
      ret = (xmlXPathObjectPtr)
2404
979k
    cache->miscObjs->items[--cache->miscObjs->number];
2405
2406
979k
      ret->type = XPATH_STRING;
2407
979k
      ret->stringval = val;
2408
#ifdef XP_DEBUG_OBJ_USAGE
2409
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2410
#endif
2411
979k
      return(ret);
2412
979k
  }
2413
2.45M
    }
2414
619k
    return(xmlXPathWrapString(val));
2415
2.45M
}
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
46.6M
{
2431
46.6M
    if ((ctxt != NULL) && (ctxt->cache)) {
2432
46.6M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2433
2434
46.6M
  if ((cache->nodesetObjs != NULL) &&
2435
46.6M
      (cache->nodesetObjs->number != 0))
2436
44.2M
  {
2437
44.2M
      xmlXPathObjectPtr ret;
2438
      /*
2439
      * Use the nodeset-cache.
2440
      */
2441
44.2M
      ret = (xmlXPathObjectPtr)
2442
44.2M
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2443
44.2M
      ret->type = XPATH_NODESET;
2444
44.2M
      ret->boolval = 0;
2445
44.2M
      if (val) {
2446
43.5M
    if ((ret->nodesetval->nodeMax == 0) ||
2447
43.5M
        (val->type == XML_NAMESPACE_DECL))
2448
7.32M
    {
2449
                    /* TODO: Check memory error. */
2450
7.32M
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2451
36.1M
    } else {
2452
36.1M
        ret->nodesetval->nodeTab[0] = val;
2453
36.1M
        ret->nodesetval->nodeNr = 1;
2454
36.1M
    }
2455
43.5M
      }
2456
#ifdef XP_DEBUG_OBJ_USAGE
2457
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2458
#endif
2459
44.2M
      return(ret);
2460
44.2M
  } else if ((cache->miscObjs != NULL) &&
2461
2.39M
      (cache->miscObjs->number != 0))
2462
63.8k
  {
2463
63.8k
      xmlXPathObjectPtr ret;
2464
      /*
2465
      * Fallback to misc-cache.
2466
      */
2467
2468
63.8k
      ret = (xmlXPathObjectPtr)
2469
63.8k
    cache->miscObjs->items[--cache->miscObjs->number];
2470
2471
63.8k
      ret->type = XPATH_NODESET;
2472
63.8k
      ret->boolval = 0;
2473
63.8k
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2474
63.8k
      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
63.8k
      return(ret);
2483
63.8k
  }
2484
46.6M
    }
2485
2.34M
    return(xmlXPathNewNodeSet(val));
2486
46.6M
}
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
261k
{
2501
261k
    if ((ctxt != NULL) && (ctxt->cache)) {
2502
261k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2503
2504
261k
  if ((cache->stringObjs != NULL) &&
2505
261k
      (cache->stringObjs->number != 0))
2506
220k
  {
2507
220k
      xmlXPathObjectPtr ret;
2508
2509
220k
      ret = (xmlXPathObjectPtr)
2510
220k
    cache->stringObjs->items[--cache->stringObjs->number];
2511
2512
220k
      ret->type = XPATH_STRING;
2513
220k
      ret->stringval = xmlStrdup(BAD_CAST val);
2514
#ifdef XP_DEBUG_OBJ_USAGE
2515
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2516
#endif
2517
220k
      return(ret);
2518
220k
  } else if ((cache->miscObjs != NULL) &&
2519
40.5k
      (cache->miscObjs->number != 0))
2520
22.6k
  {
2521
22.6k
      xmlXPathObjectPtr ret;
2522
2523
22.6k
      ret = (xmlXPathObjectPtr)
2524
22.6k
    cache->miscObjs->items[--cache->miscObjs->number];
2525
2526
22.6k
      ret->type = XPATH_STRING;
2527
22.6k
      ret->stringval = xmlStrdup(BAD_CAST val);
2528
#ifdef XP_DEBUG_OBJ_USAGE
2529
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2530
#endif
2531
22.6k
      return(ret);
2532
22.6k
  }
2533
261k
    }
2534
17.9k
    return(xmlXPathNewCString(val));
2535
261k
}
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
17.6M
{
2550
17.6M
    if ((ctxt != NULL) && (ctxt->cache)) {
2551
17.6M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2552
2553
17.6M
  if ((cache->stringObjs != NULL) &&
2554
17.6M
      (cache->stringObjs->number != 0))
2555
13.4M
  {
2556
13.4M
      xmlXPathObjectPtr ret;
2557
2558
13.4M
      ret = (xmlXPathObjectPtr)
2559
13.4M
    cache->stringObjs->items[--cache->stringObjs->number];
2560
13.4M
      ret->type = XPATH_STRING;
2561
13.4M
      if (val != NULL)
2562
13.4M
    ret->stringval = xmlStrdup(val);
2563
40.5k
      else
2564
40.5k
    ret->stringval = xmlStrdup((const xmlChar *)"");
2565
#ifdef XP_DEBUG_OBJ_USAGE
2566
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2567
#endif
2568
13.4M
      return(ret);
2569
13.4M
  } else if ((cache->miscObjs != NULL) &&
2570
4.16M
      (cache->miscObjs->number != 0))
2571
2.19M
  {
2572
2.19M
      xmlXPathObjectPtr ret;
2573
2574
2.19M
      ret = (xmlXPathObjectPtr)
2575
2.19M
    cache->miscObjs->items[--cache->miscObjs->number];
2576
2577
2.19M
      ret->type = XPATH_STRING;
2578
2.19M
      if (val != NULL)
2579
2.17M
    ret->stringval = xmlStrdup(val);
2580
18.6k
      else
2581
18.6k
    ret->stringval = xmlStrdup((const xmlChar *)"");
2582
#ifdef XP_DEBUG_OBJ_USAGE
2583
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2584
#endif
2585
2.19M
      return(ret);
2586
2.19M
  }
2587
17.6M
    }
2588
1.96M
    return(xmlXPathNewString(val));
2589
17.6M
}
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
14.2M
{
2604
14.2M
    if ((ctxt != NULL) && (ctxt->cache)) {
2605
14.2M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2606
2607
14.2M
  if ((cache->booleanObjs != NULL) &&
2608
14.2M
      (cache->booleanObjs->number != 0))
2609
13.6M
  {
2610
13.6M
      xmlXPathObjectPtr ret;
2611
2612
13.6M
      ret = (xmlXPathObjectPtr)
2613
13.6M
    cache->booleanObjs->items[--cache->booleanObjs->number];
2614
13.6M
      ret->type = XPATH_BOOLEAN;
2615
13.6M
      ret->boolval = (val != 0);
2616
#ifdef XP_DEBUG_OBJ_USAGE
2617
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2618
#endif
2619
13.6M
      return(ret);
2620
13.6M
  } else if ((cache->miscObjs != NULL) &&
2621
668k
      (cache->miscObjs->number != 0))
2622
238k
  {
2623
238k
      xmlXPathObjectPtr ret;
2624
2625
238k
      ret = (xmlXPathObjectPtr)
2626
238k
    cache->miscObjs->items[--cache->miscObjs->number];
2627
2628
238k
      ret->type = XPATH_BOOLEAN;
2629
238k
      ret->boolval = (val != 0);
2630
#ifdef XP_DEBUG_OBJ_USAGE
2631
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2632
#endif
2633
238k
      return(ret);
2634
238k
  }
2635
14.2M
    }
2636
429k
    return(xmlXPathNewBoolean(val));
2637
14.2M
}
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
29.6M
{
2652
29.6M
     if ((ctxt != NULL) && (ctxt->cache)) {
2653
29.6M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2654
2655
29.6M
  if ((cache->numberObjs != NULL) &&
2656
29.6M
      (cache->numberObjs->number != 0))
2657
25.7M
  {
2658
25.7M
      xmlXPathObjectPtr ret;
2659
2660
25.7M
      ret = (xmlXPathObjectPtr)
2661
25.7M
    cache->numberObjs->items[--cache->numberObjs->number];
2662
25.7M
      ret->type = XPATH_NUMBER;
2663
25.7M
      ret->floatval = val;
2664
#ifdef XP_DEBUG_OBJ_USAGE
2665
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2666
#endif
2667
25.7M
      return(ret);
2668
25.7M
  } else if ((cache->miscObjs != NULL) &&
2669
3.85M
      (cache->miscObjs->number != 0))
2670
1.09M
  {
2671
1.09M
      xmlXPathObjectPtr ret;
2672
2673
1.09M
      ret = (xmlXPathObjectPtr)
2674
1.09M
    cache->miscObjs->items[--cache->miscObjs->number];
2675
2676
1.09M
      ret->type = XPATH_NUMBER;
2677
1.09M
      ret->floatval = val;
2678
#ifdef XP_DEBUG_OBJ_USAGE
2679
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2680
#endif
2681
1.09M
      return(ret);
2682
1.09M
  }
2683
29.6M
    }
2684
2.76M
    return(xmlXPathNewFloat(val));
2685
29.6M
}
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
7.10M
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2701
7.10M
    xmlChar *res = NULL;
2702
2703
7.10M
    if (val == NULL)
2704
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2705
2706
7.10M
    switch (val->type) {
2707
0
    case XPATH_UNDEFINED:
2708
#ifdef DEBUG_EXPR
2709
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2710
#endif
2711
0
  break;
2712
1.80M
    case XPATH_NODESET:
2713
1.80M
    case XPATH_XSLT_TREE:
2714
1.80M
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2715
1.80M
  break;
2716
4.81M
    case XPATH_STRING:
2717
4.81M
  return(val);
2718
110k
    case XPATH_BOOLEAN:
2719
110k
  res = xmlXPathCastBooleanToString(val->boolval);
2720
110k
  break;
2721
380k
    case XPATH_NUMBER:
2722
380k
  res = xmlXPathCastNumberToString(val->floatval);
2723
380k
  break;
2724
647
    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
647
  TODO;
2731
647
  break;
2732
7.10M
    }
2733
2.29M
    xmlXPathReleaseObject(ctxt, val);
2734
2.29M
    if (res == NULL)
2735
647
  return(xmlXPathCacheNewCString(ctxt, ""));
2736
2.29M
    return(xmlXPathCacheWrapString(ctxt, res));
2737
2.29M
}
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
22.7M
{
2752
22.7M
    if (val == NULL)
2753
5.31k
  return(NULL);
2754
2755
22.7M
    if (XP_HAS_CACHE(ctxt)) {
2756
22.7M
  switch (val->type) {
2757
0
      case XPATH_NODESET:
2758
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2759
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2760
13.2M
      case XPATH_STRING:
2761
13.2M
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2762
0
      case XPATH_BOOLEAN:
2763
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2764
9.47M
      case XPATH_NUMBER:
2765
9.47M
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2766
0
      default:
2767
0
    break;
2768
22.7M
  }
2769
22.7M
    }
2770
562
    return(xmlXPathObjectCopy(val));
2771
22.7M
}
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.16M
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2786
1.16M
    xmlXPathObjectPtr ret;
2787
2788
1.16M
    if (val == NULL)
2789
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2790
1.16M
    if (val->type == XPATH_BOOLEAN)
2791
198k
  return(val);
2792
964k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2793
964k
    xmlXPathReleaseObject(ctxt, val);
2794
964k
    return(ret);
2795
1.16M
}
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
16.7M
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2810
16.7M
    xmlXPathObjectPtr ret;
2811
2812
16.7M
    if (val == NULL)
2813
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2814
16.7M
    if (val->type == XPATH_NUMBER)
2815
8.22k
  return(val);
2816
16.7M
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2817
16.7M
    xmlXPathReleaseObject(ctxt, val);
2818
16.7M
    return(ret);
2819
16.7M
}
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
13.7M
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2837
13.7M
    int ret;
2838
2839
13.7M
    if (ctxt == NULL)
2840
0
        return(0);
2841
13.7M
    ret = ctxt->valueFrame;
2842
13.7M
    ctxt->valueFrame = ctxt->valueNr;
2843
13.7M
    return(ret);
2844
13.7M
}
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
13.5M
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2855
13.5M
    if (ctxt == NULL)
2856
0
        return;
2857
13.5M
    if (ctxt->valueNr < ctxt->valueFrame) {
2858
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2859
0
    }
2860
13.5M
    ctxt->valueFrame = frame;
2861
13.5M
}
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
192M
{
2874
192M
    xmlXPathObjectPtr ret;
2875
2876
192M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2877
160k
        return (NULL);
2878
2879
192M
    if (ctxt->valueNr <= ctxt->valueFrame) {
2880
75
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2881
75
        return (NULL);
2882
75
    }
2883
2884
192M
    ctxt->valueNr--;
2885
192M
    if (ctxt->valueNr > 0)
2886
163M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2887
28.4M
    else
2888
28.4M
        ctxt->value = NULL;
2889
192M
    ret = ctxt->valueTab[ctxt->valueNr];
2890
192M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2891
192M
    return (ret);
2892
192M
}
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
193M
{
2906
193M
    if (ctxt == NULL) return(-1);
2907
193M
    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
2.78k
  ctxt->error = XPATH_MEMORY_ERROR;
2913
2.78k
        return(-1);
2914
2.78k
    }
2915
193M
    if (ctxt->valueNr >= ctxt->valueMax) {
2916
15.0k
        xmlXPathObjectPtr *tmp;
2917
2918
15.0k
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2919
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2920
0
            return (-1);
2921
0
        }
2922
15.0k
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2923
15.0k
                                             2 * ctxt->valueMax *
2924
15.0k
                                             sizeof(ctxt->valueTab[0]));
2925
15.0k
        if (tmp == NULL) {
2926
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2927
0
            return (-1);
2928
0
        }
2929
15.0k
        ctxt->valueMax *= 2;
2930
15.0k
  ctxt->valueTab = tmp;
2931
15.0k
    }
2932
193M
    ctxt->valueTab[ctxt->valueNr] = value;
2933
193M
    ctxt->value = value;
2934
193M
    return (ctxt->valueNr++);
2935
193M
}
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
70.8k
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2948
70.8k
    xmlXPathObjectPtr obj;
2949
70.8k
    int ret;
2950
2951
70.8k
    obj = valuePop(ctxt);
2952
70.8k
    if (obj == NULL) {
2953
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2954
0
  return(0);
2955
0
    }
2956
70.8k
    if (obj->type != XPATH_BOOLEAN)
2957
19.6k
  ret = xmlXPathCastToBoolean(obj);
2958
51.2k
    else
2959
51.2k
        ret = obj->boolval;
2960
70.8k
    xmlXPathReleaseObject(ctxt->context, obj);
2961
70.8k
    return(ret);
2962
70.8k
}
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
250k
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2975
250k
    xmlXPathObjectPtr obj;
2976
250k
    double ret;
2977
2978
250k
    obj = valuePop(ctxt);
2979
250k
    if (obj == NULL) {
2980
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2981
0
  return(0);
2982
0
    }
2983
250k
    if (obj->type != XPATH_NUMBER)
2984
80.0k
  ret = xmlXPathCastToNumber(obj);
2985
170k
    else
2986
170k
        ret = obj->floatval;
2987
250k
    xmlXPathReleaseObject(ctxt->context, obj);
2988
250k
    return(ret);
2989
250k
}
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
6.50M
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
3002
6.50M
    xmlXPathObjectPtr obj;
3003
6.50M
    xmlChar * ret;
3004
3005
6.50M
    obj = valuePop(ctxt);
3006
6.50M
    if (obj == NULL) {
3007
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3008
0
  return(NULL);
3009
0
    }
3010
6.50M
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
3011
    /* TODO: needs refactoring somewhere else */
3012
6.50M
    if (obj->stringval == ret)
3013
0
  obj->stringval = NULL;
3014
6.50M
    xmlXPathReleaseObject(ctxt->context, obj);
3015
6.50M
    return(ret);
3016
6.50M
}
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
2.76M
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3029
2.76M
    xmlXPathObjectPtr obj;
3030
2.76M
    xmlNodeSetPtr ret;
3031
3032
2.76M
    if (ctxt == NULL) return(NULL);
3033
2.76M
    if (ctxt->value == NULL) {
3034
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3035
0
  return(NULL);
3036
0
    }
3037
2.76M
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3038
30.2k
  xmlXPathSetTypeError(ctxt);
3039
30.2k
  return(NULL);
3040
30.2k
    }
3041
2.73M
    obj = valuePop(ctxt);
3042
2.73M
    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
2.73M
    obj->nodesetval = NULL;
3049
2.73M
    xmlXPathReleaseObject(ctxt->context, obj);
3050
2.73M
    return(ret);
3051
2.76M
}
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
5.41k
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3064
5.41k
    xmlXPathObjectPtr obj;
3065
5.41k
    void * ret;
3066
3067
5.41k
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3068
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3069
0
  return(NULL);
3070
0
    }
3071
5.41k
    if (ctxt->value->type != XPATH_USERS) {
3072
0
  xmlXPathSetTypeError(ctxt);
3073
0
  return(NULL);
3074
0
    }
3075
5.41k
    obj = valuePop(ctxt);
3076
5.41k
    ret = obj->user;
3077
5.41k
    obj->user = NULL;
3078
5.41k
    xmlXPathReleaseObject(ctxt->context, obj);
3079
5.41k
    return(ret);
3080
5.41k
}
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
710M
#define CUR (*ctxt->cur)
3106
4.21M
#define SKIP(val) ctxt->cur += (val)
3107
51.1M
#define NXT(val) ctxt->cur[(val)]
3108
1.60M
#define CUR_PTR ctxt->cur
3109
124M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3110
3111
#define COPY_BUF(l,b,i,v)                                              \
3112
49.3M
    if (l == 1) b[i++] = v;                                            \
3113
49.3M
    else i += xmlCopyChar(l,&b[i],v)
3114
3115
100M
#define NEXTL(l)  ctxt->cur += l
3116
3117
#define SKIP_BLANKS             \
3118
295M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3119
3120
#define CURRENT (*ctxt->cur)
3121
353M
#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
140k
#define UPPER_DOUBLE 1E9
3132
93.3k
#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
48.3k
#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
290k
{
3150
290k
    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
290k
    default:
3160
290k
  if (xmlXPathIsNaN(number)) {
3161
0
      if (buffersize > (int)sizeof("NaN"))
3162
0
    snprintf(buffer, buffersize, "NaN");
3163
290k
  } else if (number == 0) {
3164
            /* Omit sign for negative zero. */
3165
0
      snprintf(buffer, buffersize, "0");
3166
290k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3167
290k
                   (number == (int) number)) {
3168
150k
      char work[30];
3169
150k
      char *ptr, *cur;
3170
150k
      int value = (int) number;
3171
3172
150k
            ptr = &buffer[0];
3173
150k
      if (value == 0) {
3174
0
    *ptr++ = '0';
3175
150k
      } else {
3176
150k
    snprintf(work, 29, "%d", value);
3177
150k
    cur = &work[0];
3178
415k
    while ((*cur) && (ptr - buffer < buffersize)) {
3179
265k
        *ptr++ = *cur++;
3180
265k
    }
3181
150k
      }
3182
150k
      if (ptr - buffer < buffersize) {
3183
150k
    *ptr = 0;
3184
150k
      } else if (buffersize > 0) {
3185
0
    ptr--;
3186
0
    *ptr = 0;
3187
0
      }
3188
150k
  } 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
140k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3199
140k
      int integer_place, fraction_place;
3200
140k
      char *ptr;
3201
140k
      char *after_fraction;
3202
140k
      double absolute_value;
3203
140k
      int size;
3204
3205
140k
      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
140k
      if ( ((absolute_value > UPPER_DOUBLE) ||
3213
140k
      (absolute_value < LOWER_DOUBLE)) &&
3214
140k
     (absolute_value != 0.0) ) {
3215
    /* Use scientific notation */
3216
48.3k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3217
48.3k
    fraction_place = DBL_DIG - 1;
3218
48.3k
    size = snprintf(work, sizeof(work),"%*.*e",
3219
48.3k
       integer_place, fraction_place, number);
3220
244k
    while ((size > 0) && (work[size] != 'e')) size--;
3221
3222
48.3k
      }
3223
92.1k
      else {
3224
    /* Use regular notation */
3225
92.1k
    if (absolute_value > 0.0) {
3226
92.1k
        integer_place = (int)log10(absolute_value);
3227
92.1k
        if (integer_place > 0)
3228
19.8k
            fraction_place = DBL_DIG - integer_place - 1;
3229
72.3k
        else
3230
72.3k
            fraction_place = DBL_DIG - integer_place;
3231
92.1k
    } else {
3232
0
        fraction_place = 1;
3233
0
    }
3234
92.1k
    size = snprintf(work, sizeof(work), "%0.*f",
3235
92.1k
        fraction_place, number);
3236
92.1k
      }
3237
3238
      /* Remove leading spaces sometimes inserted by snprintf */
3239
183k
      while (work[0] == ' ') {
3240
904k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3241
43.0k
    size--;
3242
43.0k
      }
3243
3244
      /* Remove fractional trailing zeroes */
3245
140k
      after_fraction = work + size;
3246
140k
      ptr = after_fraction;
3247
1.48M
      while (*(--ptr) == '0')
3248
1.34M
    ;
3249
140k
      if (*ptr != '.')
3250
127k
          ptr++;
3251
336k
      while ((*ptr++ = *after_fraction++) != 0);
3252
3253
      /* Finally copy result back to caller */
3254
140k
      size = strlen(work) + 1;
3255
140k
      if (size > buffersize) {
3256
0
    work[buffersize - 1] = 0;
3257
0
    size = buffersize;
3258
0
      }
3259
140k
      memmove(buffer, work, size);
3260
140k
  }
3261
290k
  break;
3262
290k
    }
3263
290k
}
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
3.33k
xmlXPathOrderDocElems(xmlDocPtr doc) {
3287
3.33k
    ptrdiff_t count = 0;
3288
3.33k
    xmlNodePtr cur;
3289
3290
3.33k
    if (doc == NULL)
3291
0
  return(-1);
3292
3.33k
    cur = doc->children;
3293
133k
    while (cur != NULL) {
3294
130k
  if (cur->type == XML_ELEMENT_NODE) {
3295
40.0k
      cur->content = (void *) (-(++count));
3296
40.0k
      if (cur->children != NULL) {
3297
30.0k
    cur = cur->children;
3298
30.0k
    continue;
3299
30.0k
      }
3300
40.0k
  }
3301
100k
  if (cur->next != NULL) {
3302
70.0k
      cur = cur->next;
3303
70.0k
      continue;
3304
70.0k
  }
3305
33.3k
  do {
3306
33.3k
      cur = cur->parent;
3307
33.3k
      if (cur == NULL)
3308
0
    break;
3309
33.3k
      if (cur == (xmlNodePtr) doc) {
3310
3.33k
    cur = NULL;
3311
3.33k
    break;
3312
3.33k
      }
3313
30.0k
      if (cur->next != NULL) {
3314
26.6k
    cur = cur->next;
3315
26.6k
    break;
3316
26.6k
      }
3317
30.0k
  } while (cur != NULL);
3318
30.0k
    }
3319
3.33k
    return(count);
3320
3.33k
}
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
671k
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3334
671k
    int depth1, depth2;
3335
671k
    int attr1 = 0, attr2 = 0;
3336
671k
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3337
671k
    xmlNodePtr cur, root;
3338
3339
671k
    if ((node1 == NULL) || (node2 == NULL))
3340
0
  return(-2);
3341
    /*
3342
     * a couple of optimizations which will avoid computations in most cases
3343
     */
3344
671k
    if (node1 == node2)    /* trivial case */
3345
0
  return(0);
3346
671k
    if (node1->type == XML_ATTRIBUTE_NODE) {
3347
20.0k
  attr1 = 1;
3348
20.0k
  attrNode1 = node1;
3349
20.0k
  node1 = node1->parent;
3350
20.0k
    }
3351
671k
    if (node2->type == XML_ATTRIBUTE_NODE) {
3352
29.9k
  attr2 = 1;
3353
29.9k
  attrNode2 = node2;
3354
29.9k
  node2 = node2->parent;
3355
29.9k
    }
3356
671k
    if (node1 == node2) {
3357
4.75k
  if (attr1 == attr2) {
3358
      /* not required, but we keep attributes in order */
3359
1.34k
      if (attr1 != 0) {
3360
1.34k
          cur = attrNode2->prev;
3361
1.34k
    while (cur != NULL) {
3362
1.32k
        if (cur == attrNode1)
3363
1.32k
            return (1);
3364
0
        cur = cur->prev;
3365
0
    }
3366
22
    return (-1);
3367
1.34k
      }
3368
0
      return(0);
3369
1.34k
  }
3370
3.41k
  if (attr2 == 1)
3371
3.12k
      return(1);
3372
284
  return(-1);
3373
3.41k
    }
3374
666k
    if ((node1->type == XML_NAMESPACE_DECL) ||
3375
666k
        (node2->type == XML_NAMESPACE_DECL))
3376
86.1k
  return(1);
3377
580k
    if (node1 == node2->prev)
3378
8.02k
  return(1);
3379
572k
    if (node1 == node2->next)
3380
351
  return(-1);
3381
3382
    /*
3383
     * Speedup using document order if available.
3384
     */
3385
572k
    if ((node1->type == XML_ELEMENT_NODE) &&
3386
572k
  (node2->type == XML_ELEMENT_NODE) &&
3387
572k
  (0 > (ptrdiff_t) node1->content) &&
3388
572k
  (0 > (ptrdiff_t) node2->content) &&
3389
572k
  (node1->doc == node2->doc)) {
3390
97.9k
  ptrdiff_t l1, l2;
3391
3392
97.9k
  l1 = -((ptrdiff_t) node1->content);
3393
97.9k
  l2 = -((ptrdiff_t) node2->content);
3394
97.9k
  if (l1 < l2)
3395
96.6k
      return(1);
3396
1.26k
  if (l1 > l2)
3397
1.26k
      return(-1);
3398
1.26k
    }
3399
3400
    /*
3401
     * compute depth to root
3402
     */
3403
1.47M
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3404
1.13M
  if (cur->parent == node1)
3405
132k
      return(1);
3406
1.00M
  depth2++;
3407
1.00M
    }
3408
342k
    root = cur;
3409
897k
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3410
558k
  if (cur->parent == node2)
3411
2.73k
      return(-1);
3412
555k
  depth1++;
3413
555k
    }
3414
    /*
3415
     * Distinct document (or distinct entities :-( ) case.
3416
     */
3417
339k
    if (root != cur) {
3418
47.8k
  return(-2);
3419
47.8k
    }
3420
    /*
3421
     * get the nearest common ancestor.
3422
     */
3423
300k
    while (depth1 > depth2) {
3424
9.38k
  depth1--;
3425
9.38k
  node1 = node1->parent;
3426
9.38k
    }
3427
581k
    while (depth2 > depth1) {
3428
289k
  depth2--;
3429
289k
  node2 = node2->parent;
3430
289k
    }
3431
303k
    while (node1->parent != node2->parent) {
3432
12.1k
  node1 = node1->parent;
3433
12.1k
  node2 = node2->parent;
3434
  /* should not happen but just in case ... */
3435
12.1k
  if ((node1 == NULL) || (node2 == NULL))
3436
0
      return(-2);
3437
12.1k
    }
3438
    /*
3439
     * Find who's first.
3440
     */
3441
291k
    if (node1 == node2->prev)
3442
143k
  return(1);
3443
147k
    if (node1 == node2->next)
3444
592
  return(-1);
3445
    /*
3446
     * Speedup using document order if available.
3447
     */
3448
147k
    if ((node1->type == XML_ELEMENT_NODE) &&
3449
147k
  (node2->type == XML_ELEMENT_NODE) &&
3450
147k
  (0 > (ptrdiff_t) node1->content) &&
3451
147k
  (0 > (ptrdiff_t) node2->content) &&
3452
147k
  (node1->doc == node2->doc)) {
3453
21.7k
  ptrdiff_t l1, l2;
3454
3455
21.7k
  l1 = -((ptrdiff_t) node1->content);
3456
21.7k
  l2 = -((ptrdiff_t) node2->content);
3457
21.7k
  if (l1 < l2)
3458
21.3k
      return(1);
3459
454
  if (l1 > l2)
3460
454
      return(-1);
3461
454
    }
3462
3463
441M
    for (cur = node1->next;cur != NULL;cur = cur->next)
3464
441M
  if (cur == node2)
3465
125k
      return(1);
3466
376
    return(-1); /* assume there is no sibling list corruption */
3467
125k
}
3468
3469
/**
3470
 * xmlXPathNodeSetSort:
3471
 * @set:  the node set
3472
 *
3473
 * Sort the node set in document order
3474
 */
3475
void
3476
5.75M
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3477
#ifndef WITH_TIM_SORT
3478
    int i, j, incr, len;
3479
    xmlNodePtr tmp;
3480
#endif
3481
3482
5.75M
    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
5.75M
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3514
5.75M
#endif /* WITH_TIM_SORT */
3515
5.75M
}
3516
3517
85.2M
#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
3.74M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3531
3.74M
    xmlNsPtr cur;
3532
3533
3.74M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3534
0
  return(NULL);
3535
3.74M
    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
3.74M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3542
3.74M
    if (cur == NULL) {
3543
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3544
0
  return(NULL);
3545
0
    }
3546
3.74M
    memset(cur, 0, sizeof(xmlNs));
3547
3.74M
    cur->type = XML_NAMESPACE_DECL;
3548
3.74M
    if (ns->href != NULL)
3549
3.74M
  cur->href = xmlStrdup(ns->href);
3550
3.74M
    if (ns->prefix != NULL)
3551
3.74M
  cur->prefix = xmlStrdup(ns->prefix);
3552
3.74M
    cur->next = (xmlNsPtr) node;
3553
3.74M
    return((xmlNodePtr) cur);
3554
3.74M
}
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
3.70M
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3566
3.70M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3567
0
  return;
3568
3569
3.70M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3570
3.70M
  if (ns->href != NULL)
3571
3.70M
      xmlFree((xmlChar *)ns->href);
3572
3.70M
  if (ns->prefix != NULL)
3573
3.70M
      xmlFree((xmlChar *)ns->prefix);
3574
3.70M
  xmlFree(ns);
3575
3.70M
    }
3576
3.70M
}
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
57.5M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3588
57.5M
    xmlNodeSetPtr ret;
3589
3590
57.5M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3591
57.5M
    if (ret == NULL) {
3592
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3593
0
  return(NULL);
3594
0
    }
3595
57.5M
    memset(ret, 0 , sizeof(xmlNodeSet));
3596
57.5M
    if (val != NULL) {
3597
3.09M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3598
3.09M
               sizeof(xmlNodePtr));
3599
3.09M
  if (ret->nodeTab == NULL) {
3600
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3601
0
      xmlFree(ret);
3602
0
      return(NULL);
3603
0
  }
3604
3.09M
  memset(ret->nodeTab, 0 ,
3605
3.09M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3606
3.09M
        ret->nodeMax = XML_NODESET_DEFAULT;
3607
3.09M
  if (val->type == XML_NAMESPACE_DECL) {
3608
34.5k
      xmlNsPtr ns = (xmlNsPtr) val;
3609
3610
            /* TODO: Check memory error. */
3611
34.5k
      ret->nodeTab[ret->nodeNr++] =
3612
34.5k
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3613
34.5k
  } else
3614
3.05M
      ret->nodeTab[ret->nodeNr++] = val;
3615
3.09M
    }
3616
57.5M
    return(ret);
3617
57.5M
}
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
375k
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3630
375k
    int i;
3631
3632
375k
    if ((cur == NULL) || (val == NULL)) return(0);
3633
375k
    if (val->type == XML_NAMESPACE_DECL) {
3634
64.6k
  for (i = 0; i < cur->nodeNr; i++) {
3635
53.2k
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3636
10.4k
    xmlNsPtr ns1, ns2;
3637
3638
10.4k
    ns1 = (xmlNsPtr) val;
3639
10.4k
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3640
10.4k
    if (ns1 == ns2)
3641
0
        return(1);
3642
10.4k
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3643
10.4k
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3644
527
        return(1);
3645
10.4k
      }
3646
53.2k
  }
3647
363k
    } else {
3648
1.52M
  for (i = 0; i < cur->nodeNr; i++) {
3649
1.24M
      if (cur->nodeTab[i] == val)
3650
89.5k
    return(1);
3651
1.24M
  }
3652
363k
    }
3653
285k
    return(0);
3654
375k
}
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
1.28M
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3668
1.28M
    int i;
3669
3670
3671
1.28M
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3672
1.28M
        (ns->type != XML_NAMESPACE_DECL) ||
3673
1.28M
  (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
2.21M
    for (i = 0;i < cur->nodeNr;i++) {
3681
926k
        if ((cur->nodeTab[i] != NULL) &&
3682
926k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3683
926k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3684
926k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3685
0
      return(0);
3686
926k
    }
3687
3688
    /*
3689
     * grow the nodeTab if needed
3690
     */
3691
1.28M
    if (cur->nodeMax == 0) {
3692
197k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3693
197k
               sizeof(xmlNodePtr));
3694
197k
  if (cur->nodeTab == NULL) {
3695
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3696
0
      return(-1);
3697
0
  }
3698
197k
  memset(cur->nodeTab, 0 ,
3699
197k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3700
197k
        cur->nodeMax = XML_NODESET_DEFAULT;
3701
1.08M
    } 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
1.28M
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3719
1.28M
    return(0);
3720
1.28M
}
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
1.35M
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3733
1.35M
    int i;
3734
3735
1.35M
    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
36.5M
    for (i = 0;i < cur->nodeNr;i++)
3742
36.0M
        if (cur->nodeTab[i] == val) return(0);
3743
3744
    /*
3745
     * grow the nodeTab if needed
3746
     */
3747
512k
    if (cur->nodeMax == 0) {
3748
65.7k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3749
65.7k
               sizeof(xmlNodePtr));
3750
65.7k
  if (cur->nodeTab == NULL) {
3751
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3752
0
      return(-1);
3753
0
  }
3754
65.7k
  memset(cur->nodeTab, 0 ,
3755
65.7k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3756
65.7k
        cur->nodeMax = XML_NODESET_DEFAULT;
3757
447k
    } else if (cur->nodeNr == cur->nodeMax) {
3758
22.4k
        xmlNodePtr *temp;
3759
3760
22.4k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3761
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3762
0
            return(-1);
3763
0
        }
3764
22.4k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3765
22.4k
              sizeof(xmlNodePtr));
3766
22.4k
  if (temp == NULL) {
3767
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3768
0
      return(-1);
3769
0
  }
3770
22.4k
        cur->nodeMax *= 2;
3771
22.4k
  cur->nodeTab = temp;
3772
22.4k
    }
3773
512k
    if (val->type == XML_NAMESPACE_DECL) {
3774
43.0k
  xmlNsPtr ns = (xmlNsPtr) val;
3775
3776
        /* TODO: Check memory error. */
3777
43.0k
  cur->nodeTab[cur->nodeNr++] =
3778
43.0k
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3779
43.0k
    } else
3780
469k
  cur->nodeTab[cur->nodeNr++] = val;
3781
512k
    return(0);
3782
512k
}
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
163M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3796
163M
    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
163M
    if (cur->nodeMax == 0) {
3803
22.0M
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3804
22.0M
               sizeof(xmlNodePtr));
3805
22.0M
  if (cur->nodeTab == NULL) {
3806
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3807
0
      return(-1);
3808
0
  }
3809
22.0M
  memset(cur->nodeTab, 0 ,
3810
22.0M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3811
22.0M
        cur->nodeMax = XML_NODESET_DEFAULT;
3812
141M
    } else if (cur->nodeNr == cur->nodeMax) {
3813
6.32M
        xmlNodePtr *temp;
3814
3815
6.32M
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3816
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3817
0
            return(-1);
3818
0
        }
3819
6.32M
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3820
6.32M
              sizeof(xmlNodePtr));
3821
6.32M
  if (temp == NULL) {
3822
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3823
0
      return(-1);
3824
0
  }
3825
6.32M
  cur->nodeTab = temp;
3826
6.32M
        cur->nodeMax *= 2;
3827
6.32M
    }
3828
163M
    if (val->type == XML_NAMESPACE_DECL) {
3829
1.76M
  xmlNsPtr ns = (xmlNsPtr) val;
3830
3831
        /* TODO: Check memory error. */
3832
1.76M
  cur->nodeTab[cur->nodeNr++] =
3833
1.76M
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3834
1.76M
    } else
3835
162M
  cur->nodeTab[cur->nodeNr++] = val;
3836
163M
    return(0);
3837
163M
}
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
6.69M
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3851
6.69M
    int i, j, initNr, skip;
3852
6.69M
    xmlNodePtr n1, n2;
3853
3854
6.69M
    if (val2 == NULL) return(val1);
3855
6.15M
    if (val1 == NULL) {
3856
1.37M
  val1 = xmlXPathNodeSetCreate(NULL);
3857
1.37M
    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
1.37M
    }
3887
3888
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3889
6.15M
    initNr = val1->nodeNr;
3890
3891
27.5M
    for (i = 0;i < val2->nodeNr;i++) {
3892
21.4M
  n2 = val2->nodeTab[i];
3893
  /*
3894
   * check against duplicates
3895
   */
3896
21.4M
  skip = 0;
3897
232M
  for (j = 0; j < initNr; j++) {
3898
216M
      n1 = val1->nodeTab[j];
3899
216M
      if (n1 == n2) {
3900
5.62M
    skip = 1;
3901
5.62M
    break;
3902
210M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3903
210M
           (n2->type == XML_NAMESPACE_DECL)) {
3904
679k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3905
679k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3906
108k
      ((xmlNsPtr) n2)->prefix)))
3907
74.1k
    {
3908
74.1k
        skip = 1;
3909
74.1k
        break;
3910
74.1k
    }
3911
679k
      }
3912
216M
  }
3913
21.4M
  if (skip)
3914
5.70M
      continue;
3915
3916
  /*
3917
   * grow the nodeTab if needed
3918
   */
3919
15.7M
  if (val1->nodeMax == 0) {
3920
1.58M
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3921
1.58M
                sizeof(xmlNodePtr));
3922
1.58M
      if (val1->nodeTab == NULL) {
3923
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3924
0
    return(NULL);
3925
0
      }
3926
1.58M
      memset(val1->nodeTab, 0 ,
3927
1.58M
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3928
1.58M
      val1->nodeMax = XML_NODESET_DEFAULT;
3929
14.1M
  } else if (val1->nodeNr == val1->nodeMax) {
3930
662k
      xmlNodePtr *temp;
3931
3932
662k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3933
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3934
0
                return(NULL);
3935
0
            }
3936
662k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3937
662k
               sizeof(xmlNodePtr));
3938
662k
      if (temp == NULL) {
3939
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3940
0
    return(NULL);
3941
0
      }
3942
662k
      val1->nodeTab = temp;
3943
662k
      val1->nodeMax *= 2;
3944
662k
  }
3945
15.7M
  if (n2->type == XML_NAMESPACE_DECL) {
3946
615k
      xmlNsPtr ns = (xmlNsPtr) n2;
3947
3948
            /* TODO: Check memory error. */
3949
615k
      val1->nodeTab[val1->nodeNr++] =
3950
615k
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3951
615k
  } else
3952
15.0M
      val1->nodeTab[val1->nodeNr++] = n2;
3953
15.7M
    }
3954
3955
6.15M
    return(val1);
3956
6.15M
}
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
4.55M
{
3972
4.55M
    {
3973
4.55M
  int i, j, initNbSet1;
3974
4.55M
  xmlNodePtr n1, n2;
3975
3976
4.55M
  initNbSet1 = set1->nodeNr;
3977
14.3M
  for (i = 0;i < set2->nodeNr;i++) {
3978
9.79M
      n2 = set2->nodeTab[i];
3979
      /*
3980
      * Skip duplicates.
3981
      */
3982
9.25G
      for (j = 0; j < initNbSet1; j++) {
3983
9.25G
    n1 = set1->nodeTab[j];
3984
9.25G
    if (n1 == n2) {
3985
6.91M
        goto skip_node;
3986
9.24G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3987
9.24G
        (n2->type == XML_NAMESPACE_DECL))
3988
1.36M
    {
3989
1.36M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3990
1.36M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3991
96.1k
      ((xmlNsPtr) n2)->prefix)))
3992
12.5k
        {
3993
      /*
3994
      * Free the namespace node.
3995
      */
3996
12.5k
      set2->nodeTab[i] = NULL;
3997
12.5k
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3998
12.5k
      goto skip_node;
3999
12.5k
        }
4000
1.36M
    }
4001
9.25G
      }
4002
      /*
4003
      * grow the nodeTab if needed
4004
      */
4005
2.87M
      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.87M
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
96.5k
    xmlNodePtr *temp;
4017
4018
96.5k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    return(NULL);
4021
0
                }
4022
96.5k
    temp = (xmlNodePtr *) xmlRealloc(
4023
96.5k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
96.5k
    if (temp == NULL) {
4025
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
0
        return(NULL);
4027
0
    }
4028
96.5k
    set1->nodeTab = temp;
4029
96.5k
    set1->nodeMax *= 2;
4030
96.5k
      }
4031
2.87M
      set1->nodeTab[set1->nodeNr++] = n2;
4032
9.79M
skip_node:
4033
9.79M
      {}
4034
9.79M
  }
4035
4.55M
    }
4036
4.55M
    set2->nodeNr = 0;
4037
4.55M
    return(set1);
4038
4.55M
}
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.62M
{
4053
2.62M
    {
4054
2.62M
  int i;
4055
2.62M
  xmlNodePtr n2;
4056
4057
7.04M
  for (i = 0;i < set2->nodeNr;i++) {
4058
4.42M
      n2 = set2->nodeTab[i];
4059
4.42M
      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
4.42M
      } else if (set1->nodeNr >= set1->nodeMax) {
4070
267k
    xmlNodePtr *temp;
4071
4072
267k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4073
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4074
0
                    return(NULL);
4075
0
                }
4076
267k
    temp = (xmlNodePtr *) xmlRealloc(
4077
267k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4078
267k
    if (temp == NULL) {
4079
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4080
0
        return(NULL);
4081
0
    }
4082
267k
    set1->nodeTab = temp;
4083
267k
    set1->nodeMax *= 2;
4084
267k
      }
4085
4.42M
      set1->nodeTab[set1->nodeNr++] = n2;
4086
4.42M
  }
4087
2.62M
    }
4088
2.62M
    set2->nodeNr = 0;
4089
2.62M
    return(set1);
4090
2.62M
}
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
46.7M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4157
46.7M
    if (obj == NULL) return;
4158
46.6M
    if (obj->nodeTab != NULL) {
4159
17.9M
  int i;
4160
4161
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4162
143M
  for (i = 0;i < obj->nodeNr;i++)
4163
125M
      if ((obj->nodeTab[i] != NULL) &&
4164
125M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4165
1.36M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4166
17.9M
  xmlFree(obj->nodeTab);
4167
17.9M
    }
4168
46.6M
    xmlFree(obj);
4169
46.6M
}
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
85.1k
{
4183
85.1k
    if ((set == NULL) || (pos >= set->nodeNr))
4184
0
  return;
4185
85.1k
    else if ((hasNsNodes)) {
4186
31.3k
  int i;
4187
31.3k
  xmlNodePtr node;
4188
4189
258k
  for (i = pos; i < set->nodeNr; i++) {
4190
227k
      node = set->nodeTab[i];
4191
227k
      if ((node != NULL) &&
4192
227k
    (node->type == XML_NAMESPACE_DECL))
4193
15.5k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4194
227k
  }
4195
31.3k
    }
4196
85.1k
    set->nodeNr = pos;
4197
85.1k
}
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
58.5k
{
4210
58.5k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4211
58.5k
}
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
25.7k
{
4224
25.7k
    int i;
4225
25.7k
    xmlNodePtr node;
4226
4227
25.7k
    if ((set == NULL) || (set->nodeNr <= 1))
4228
0
  return;
4229
263k
    for (i = 0; i < set->nodeNr - 1; i++) {
4230
237k
        node = set->nodeTab[i];
4231
237k
        if ((node != NULL) &&
4232
237k
            (node->type == XML_NAMESPACE_DECL))
4233
8.97k
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4234
237k
    }
4235
25.7k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4236
25.7k
    set->nodeNr = 1;
4237
25.7k
}
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
12.6M
xmlXPathNewNodeSet(xmlNodePtr val) {
4319
12.6M
    xmlXPathObjectPtr ret;
4320
4321
12.6M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4322
12.6M
    if (ret == NULL) {
4323
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4324
0
  return(NULL);
4325
0
    }
4326
12.6M
    memset(ret, 0 , sizeof(xmlXPathObject));
4327
12.6M
    ret->type = XPATH_NODESET;
4328
12.6M
    ret->boolval = 0;
4329
    /* TODO: Check memory error. */
4330
12.6M
    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
12.6M
    return(ret);
4336
12.6M
}
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
13.0M
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4410
13.0M
    xmlXPathObjectPtr ret;
4411
4412
13.0M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4413
13.0M
    if (ret == NULL) {
4414
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4415
0
  return(NULL);
4416
0
    }
4417
13.0M
    memset(ret, 0 , sizeof(xmlXPathObject));
4418
13.0M
    ret->type = XPATH_NODESET;
4419
13.0M
    ret->nodesetval = val;
4420
#ifdef XP_DEBUG_OBJ_USAGE
4421
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4422
#endif
4423
13.0M
    return(ret);
4424
13.0M
}
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
32.0k
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4455
32.0k
    xmlNodeSetPtr ret;
4456
32.0k
    int i, l1;
4457
32.0k
    xmlNodePtr cur;
4458
4459
32.0k
    if (xmlXPathNodeSetIsEmpty(nodes2))
4460
14.2k
  return(nodes1);
4461
4462
    /* TODO: Check memory error. */
4463
17.7k
    ret = xmlXPathNodeSetCreate(NULL);
4464
17.7k
    if (xmlXPathNodeSetIsEmpty(nodes1))
4465
7.07k
  return(ret);
4466
4467
10.7k
    l1 = xmlXPathNodeSetGetLength(nodes1);
4468
4469
146k
    for (i = 0; i < l1; i++) {
4470
135k
  cur = xmlXPathNodeSetItem(nodes1, i);
4471
135k
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4472
            /* TODO: Propagate memory error. */
4473
97.5k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4474
0
          break;
4475
97.5k
  }
4476
135k
    }
4477
10.7k
    return(ret);
4478
17.7k
}
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
33.1k
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4493
33.1k
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4494
33.1k
    int i, l1;
4495
33.1k
    xmlNodePtr cur;
4496
4497
33.1k
    if (ret == NULL)
4498
0
        return(ret);
4499
33.1k
    if (xmlXPathNodeSetIsEmpty(nodes1))
4500
9.80k
  return(ret);
4501
23.3k
    if (xmlXPathNodeSetIsEmpty(nodes2))
4502
12.2k
  return(ret);
4503
4504
11.0k
    l1 = xmlXPathNodeSetGetLength(nodes1);
4505
4506
191k
    for (i = 0; i < l1; i++) {
4507
180k
  cur = xmlXPathNodeSetItem(nodes1, i);
4508
180k
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4509
            /* TODO: Propagate memory error. */
4510
31.3k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4511
0
          break;
4512
31.3k
  }
4513
180k
    }
4514
11.0k
    return(ret);
4515
23.3k
}
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
41.5k
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4529
41.5k
    xmlNodeSetPtr ret;
4530
41.5k
    xmlHashTablePtr hash;
4531
41.5k
    int i, l;
4532
41.5k
    xmlChar * strval;
4533
41.5k
    xmlNodePtr cur;
4534
4535
41.5k
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
23.3k
  return(nodes);
4537
4538
18.1k
    ret = xmlXPathNodeSetCreate(NULL);
4539
18.1k
    if (ret == NULL)
4540
0
        return(ret);
4541
18.1k
    l = xmlXPathNodeSetGetLength(nodes);
4542
18.1k
    hash = xmlHashCreate (l);
4543
176k
    for (i = 0; i < l; i++) {
4544
158k
  cur = xmlXPathNodeSetItem(nodes, i);
4545
158k
  strval = xmlXPathCastNodeToString(cur);
4546
158k
  if (xmlHashLookup(hash, strval) == NULL) {
4547
87.5k
      xmlHashAddEntry(hash, strval, strval);
4548
            /* TODO: Propagate memory error. */
4549
87.5k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4550
0
          break;
4551
87.5k
  } else {
4552
70.8k
      xmlFree(strval);
4553
70.8k
  }
4554
158k
    }
4555
18.1k
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4556
18.1k
    return(ret);
4557
18.1k
}
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
40.2k
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4593
40.2k
    int i, l;
4594
40.2k
    xmlNodePtr cur;
4595
4596
40.2k
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4597
40.2k
  xmlXPathNodeSetIsEmpty(nodes2))
4598
31.6k
  return(0);
4599
4600
8.58k
    l = xmlXPathNodeSetGetLength(nodes1);
4601
35.8k
    for (i = 0; i < l; i++) {
4602
32.5k
  cur = xmlXPathNodeSetItem(nodes1, i);
4603
32.5k
  if (xmlXPathNodeSetContains(nodes2, cur))
4604
5.23k
      return(1);
4605
32.5k
    }
4606
3.34k
    return(0);
4607
8.58k
}
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
26.2k
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4623
26.2k
    int i, l;
4624
26.2k
    xmlNodePtr cur;
4625
26.2k
    xmlNodeSetPtr ret;
4626
4627
26.2k
    if (node == NULL)
4628
0
  return(nodes);
4629
4630
26.2k
    ret = xmlXPathNodeSetCreate(NULL);
4631
26.2k
    if (ret == NULL)
4632
0
        return(ret);
4633
26.2k
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4634
26.2k
  (!xmlXPathNodeSetContains(nodes, node)))
4635
19.2k
  return(ret);
4636
4637
7.04k
    l = xmlXPathNodeSetGetLength(nodes);
4638
38.0k
    for (i = 0; i < l; i++) {
4639
38.0k
  cur = xmlXPathNodeSetItem(nodes, i);
4640
38.0k
  if (cur == node)
4641
7.04k
      break;
4642
        /* TODO: Propagate memory error. */
4643
30.9k
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4644
0
      break;
4645
30.9k
    }
4646
7.04k
    return(ret);
4647
26.2k
}
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
27.9k
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4729
27.9k
    int i, l;
4730
27.9k
    xmlNodePtr cur;
4731
27.9k
    xmlNodeSetPtr ret;
4732
4733
27.9k
    if (node == NULL)
4734
0
  return(nodes);
4735
4736
27.9k
    ret = xmlXPathNodeSetCreate(NULL);
4737
27.9k
    if (ret == NULL)
4738
0
        return(ret);
4739
27.9k
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4740
27.9k
  (!xmlXPathNodeSetContains(nodes, node)))
4741
19.3k
  return(ret);
4742
4743
8.60k
    l = xmlXPathNodeSetGetLength(nodes);
4744
84.9k
    for (i = l - 1; i >= 0; i--) {
4745
84.9k
  cur = xmlXPathNodeSetItem(nodes, i);
4746
84.9k
  if (cur == node)
4747
8.58k
      break;
4748
        /* TODO: Propagate memory error. */
4749
76.3k
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4750
0
      break;
4751
76.3k
    }
4752
8.60k
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4753
8.60k
    return(ret);
4754
27.9k
}
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
2.71M
         xmlXPathFunction f) {
4841
2.71M
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4842
2.71M
}
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
2.81M
           const xmlChar *ns_uri, xmlXPathFunction f) {
4858
2.81M
    if (ctxt == NULL)
4859
0
  return(-1);
4860
2.81M
    if (name == NULL)
4861
0
  return(-1);
4862
4863
2.81M
    if (ctxt->funcHash == NULL)
4864
0
  ctxt->funcHash = xmlHashCreate(0);
4865
2.81M
    if (ctxt->funcHash == NULL)
4866
0
  return(-1);
4867
2.81M
    if (f == NULL)
4868
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4869
2.81M
XML_IGNORE_FPTR_CAST_WARNINGS
4870
2.81M
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4871
2.81M
XML_POP_WARNINGS
4872
2.81M
}
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
3.33k
          void *funcCtxt) {
4886
3.33k
    if (ctxt == NULL)
4887
0
  return;
4888
3.33k
    ctxt->funcLookupFunc = f;
4889
3.33k
    ctxt->funcLookupData = funcCtxt;
4890
3.33k
}
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
580k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4904
580k
    if (ctxt == NULL)
4905
0
  return (NULL);
4906
4907
580k
    if (ctxt->funcLookupFunc != NULL) {
4908
579k
  xmlXPathFunction ret;
4909
579k
  xmlXPathFuncLookupFunc f;
4910
4911
579k
  f = ctxt->funcLookupFunc;
4912
579k
  ret = f(ctxt->funcLookupData, name, NULL);
4913
579k
  if (ret != NULL)
4914
0
      return(ret);
4915
579k
    }
4916
580k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4917
580k
}
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
989k
       const xmlChar *ns_uri) {
4933
989k
    xmlXPathFunction ret;
4934
4935
989k
    if (ctxt == NULL)
4936
0
  return(NULL);
4937
989k
    if (name == NULL)
4938
0
  return(NULL);
4939
4940
989k
    if (ctxt->funcLookupFunc != NULL) {
4941
989k
  xmlXPathFuncLookupFunc f;
4942
4943
989k
  f = ctxt->funcLookupFunc;
4944
989k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4945
989k
  if (ret != NULL)
4946
384k
      return(ret);
4947
989k
    }
4948
4949
605k
    if (ctxt->funcHash == NULL)
4950
0
  return(NULL);
4951
4952
605k
XML_IGNORE_FPTR_CAST_WARNINGS
4953
605k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4954
605k
XML_POP_WARNINGS
4955
605k
    return(ret);
4956
605k
}
4957
4958
/**
4959
 * xmlXPathRegisteredFuncsCleanup:
4960
 * @ctxt:  the XPath context
4961
 *
4962
 * Cleanup the XPath context data associated to registered functions
4963
 */
4964
void
4965
92.6k
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4966
92.6k
    if (ctxt == NULL)
4967
0
  return;
4968
4969
92.6k
    xmlHashFree(ctxt->funcHash, NULL);
4970
92.6k
    ctxt->funcHash = NULL;
4971
92.6k
}
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
13.3k
       xmlXPathObjectPtr value) {
4993
13.3k
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4994
13.3k
}
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
13.3k
         xmlXPathObjectPtr value) {
5012
13.3k
    if (ctxt == NULL)
5013
0
  return(-1);
5014
13.3k
    if (name == NULL)
5015
0
  return(-1);
5016
5017
13.3k
    if (ctxt->varHash == NULL)
5018
3.33k
  ctxt->varHash = xmlHashCreate(0);
5019
13.3k
    if (ctxt->varHash == NULL)
5020
0
  return(-1);
5021
13.3k
    if (value == NULL)
5022
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5023
0
                             xmlXPathFreeObjectEntry));
5024
13.3k
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5025
13.3k
             (void *) value, xmlXPathFreeObjectEntry));
5026
13.3k
}
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
3.33k
   xmlXPathVariableLookupFunc f, void *data) {
5039
3.33k
    if (ctxt == NULL)
5040
0
  return;
5041
3.33k
    ctxt->varLookupFunc = f;
5042
3.33k
    ctxt->varLookupData = data;
5043
3.33k
}
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
42.7k
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5057
42.7k
    if (ctxt == NULL)
5058
0
  return(NULL);
5059
5060
42.7k
    if (ctxt->varLookupFunc != NULL) {
5061
42.7k
  xmlXPathObjectPtr ret;
5062
5063
42.7k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5064
42.7k
          (ctxt->varLookupData, name, NULL);
5065
42.7k
  return(ret);
5066
42.7k
    }
5067
5
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5068
42.7k
}
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
5.31k
       const xmlChar *ns_uri) {
5084
5.31k
    if (ctxt == NULL)
5085
0
  return(NULL);
5086
5087
5.31k
    if (ctxt->varLookupFunc != NULL) {
5088
5.31k
  xmlXPathObjectPtr ret;
5089
5090
5.31k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5091
5.31k
          (ctxt->varLookupData, name, ns_uri);
5092
5.31k
  if (ret != NULL) return(ret);
5093
5.31k
    }
5094
5095
5.31k
    if (ctxt->varHash == NULL)
5096
5
  return(NULL);
5097
5.31k
    if (name == NULL)
5098
0
  return(NULL);
5099
5100
5.31k
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5101
5.31k
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5102
5.31k
}
5103
5104
/**
5105
 * xmlXPathRegisteredVariablesCleanup:
5106
 * @ctxt:  the XPath context
5107
 *
5108
 * Cleanup the XPath context data associated to registered variables
5109
 */
5110
void
5111
92.6k
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5112
92.6k
    if (ctxt == NULL)
5113
0
  return;
5114
5115
92.6k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5116
92.6k
    ctxt->varHash = NULL;
5117
92.6k
}
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
42.1k
         const xmlChar *ns_uri) {
5133
42.1k
    if (ctxt == NULL)
5134
0
  return(-1);
5135
42.1k
    if (prefix == NULL)
5136
0
  return(-1);
5137
42.1k
    if (prefix[0] == 0)
5138
0
  return(-1);
5139
5140
42.1k
    if (ctxt->nsHash == NULL)
5141
4.80k
  ctxt->nsHash = xmlHashCreate(10);
5142
42.1k
    if (ctxt->nsHash == NULL)
5143
0
  return(-1);
5144
42.1k
    if (ns_uri == NULL)
5145
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5146
0
                            xmlHashDefaultDeallocator));
5147
42.1k
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5148
42.1k
            xmlHashDefaultDeallocator));
5149
42.1k
}
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
1.45M
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5163
1.45M
    if (ctxt == NULL)
5164
0
  return(NULL);
5165
1.45M
    if (prefix == NULL)
5166
0
  return(NULL);
5167
5168
1.45M
#ifdef XML_XML_NAMESPACE
5169
1.45M
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5170
14.7k
  return(XML_XML_NAMESPACE);
5171
1.44M
#endif
5172
5173
1.44M
    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
1.44M
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5184
1.44M
}
5185
5186
/**
5187
 * xmlXPathRegisteredNsCleanup:
5188
 * @ctxt:  the XPath context
5189
 *
5190
 * Cleanup the XPath context data associated to registered variables
5191
 */
5192
void
5193
92.6k
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5194
92.6k
    if (ctxt == NULL)
5195
0
  return;
5196
5197
92.6k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5198
92.6k
    ctxt->nsHash = NULL;
5199
92.6k
}
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
3.64M
xmlXPathNewFloat(double val) {
5219
3.64M
    xmlXPathObjectPtr ret;
5220
5221
3.64M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5222
3.64M
    if (ret == NULL) {
5223
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5224
0
  return(NULL);
5225
0
    }
5226
3.64M
    memset(ret, 0 , sizeof(xmlXPathObject));
5227
3.64M
    ret->type = XPATH_NUMBER;
5228
3.64M
    ret->floatval = val;
5229
#ifdef XP_DEBUG_OBJ_USAGE
5230
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5231
#endif
5232
3.64M
    return(ret);
5233
3.64M
}
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
576k
xmlXPathNewBoolean(int val) {
5245
576k
    xmlXPathObjectPtr ret;
5246
5247
576k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5248
576k
    if (ret == NULL) {
5249
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5250
0
  return(NULL);
5251
0
    }
5252
576k
    memset(ret, 0 , sizeof(xmlXPathObject));
5253
576k
    ret->type = XPATH_BOOLEAN;
5254
576k
    ret->boolval = (val != 0);
5255
#ifdef XP_DEBUG_OBJ_USAGE
5256
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5257
#endif
5258
576k
    return(ret);
5259
576k
}
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.09M
xmlXPathNewString(const xmlChar *val) {
5271
3.09M
    xmlXPathObjectPtr ret;
5272
5273
3.09M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5274
3.09M
    if (ret == NULL) {
5275
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5276
0
  return(NULL);
5277
0
    }
5278
3.09M
    memset(ret, 0 , sizeof(xmlXPathObject));
5279
3.09M
    ret->type = XPATH_STRING;
5280
3.09M
    if (val != NULL)
5281
3.08M
  ret->stringval = xmlStrdup(val);
5282
7.18k
    else
5283
7.18k
  ret->stringval = xmlStrdup((const xmlChar *)"");
5284
#ifdef XP_DEBUG_OBJ_USAGE
5285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5286
#endif
5287
3.09M
    return(ret);
5288
3.09M
}
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
1.34M
xmlXPathWrapString (xmlChar *val) {
5300
1.34M
    xmlXPathObjectPtr ret;
5301
5302
1.34M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5303
1.34M
    if (ret == NULL) {
5304
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5305
0
  return(NULL);
5306
0
    }
5307
1.34M
    memset(ret, 0 , sizeof(xmlXPathObject));
5308
1.34M
    ret->type = XPATH_STRING;
5309
1.34M
    ret->stringval = val;
5310
#ifdef XP_DEBUG_OBJ_USAGE
5311
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5312
#endif
5313
1.34M
    return(ret);
5314
1.34M
}
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
1.19M
xmlXPathNewCString(const char *val) {
5326
1.19M
    xmlXPathObjectPtr ret;
5327
5328
1.19M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5329
1.19M
    if (ret == NULL) {
5330
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5331
0
  return(NULL);
5332
0
    }
5333
1.19M
    memset(ret, 0 , sizeof(xmlXPathObject));
5334
1.19M
    ret->type = XPATH_STRING;
5335
1.19M
    ret->stringval = xmlStrdup(BAD_CAST val);
5336
#ifdef XP_DEBUG_OBJ_USAGE
5337
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5338
#endif
5339
1.19M
    return(ret);
5340
1.19M
}
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
35.8k
xmlXPathWrapExternal (void *val) {
5365
35.8k
    xmlXPathObjectPtr ret;
5366
5367
35.8k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5368
35.8k
    if (ret == NULL) {
5369
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5370
0
  return(NULL);
5371
0
    }
5372
35.8k
    memset(ret, 0 , sizeof(xmlXPathObject));
5373
35.8k
    ret->type = XPATH_USERS;
5374
35.8k
    ret->user = val;
5375
#ifdef XP_DEBUG_OBJ_USAGE
5376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5377
#endif
5378
35.8k
    return(ret);
5379
35.8k
}
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
229k
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5391
229k
    xmlXPathObjectPtr ret;
5392
5393
229k
    if (val == NULL)
5394
0
  return(NULL);
5395
5396
229k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5397
229k
    if (ret == NULL) {
5398
0
        xmlXPathErrMemory(NULL, "copying object\n");
5399
0
  return(NULL);
5400
0
    }
5401
229k
    memcpy(ret, val , sizeof(xmlXPathObject));
5402
#ifdef XP_DEBUG_OBJ_USAGE
5403
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5404
#endif
5405
229k
    switch (val->type) {
5406
0
  case XPATH_BOOLEAN:
5407
562
  case XPATH_NUMBER:
5408
#ifdef LIBXML_XPTR_LOCS_ENABLED
5409
  case XPATH_POINT:
5410
  case XPATH_RANGE:
5411
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5412
562
      break;
5413
31.0k
  case XPATH_STRING:
5414
31.0k
      ret->stringval = xmlStrdup(val->stringval);
5415
31.0k
      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
198k
  case XPATH_NODESET:
5450
            /* TODO: Check memory error. */
5451
198k
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5452
      /* Do not deallocate the copied tree value */
5453
198k
      ret->boolval = 0;
5454
198k
      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
229k
    }
5472
229k
    return(ret);
5473
229k
}
5474
5475
/**
5476
 * xmlXPathFreeObject:
5477
 * @obj:  the object to free
5478
 *
5479
 * Free up an xmlXPathObjectPtr object.
5480
 */
5481
void
5482
24.6M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5483
24.6M
    if (obj == NULL) return;
5484
20.3M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5485
8.79M
  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
8.79M
  } else {
5496
8.79M
      if (obj->nodesetval != NULL)
5497
8.27M
    xmlXPathFreeNodeSet(obj->nodesetval);
5498
8.79M
  }
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
11.5M
    } else if (obj->type == XPATH_STRING) {
5505
7.37M
  if (obj->stringval != NULL)
5506
7.37M
      xmlFree(obj->stringval);
5507
7.37M
    }
5508
#ifdef XP_DEBUG_OBJ_USAGE
5509
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5510
#endif
5511
20.3M
    xmlFree(obj);
5512
20.3M
}
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
156M
{
5529
156M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5530
940k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5531
155M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5532
5533
191M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5534
5535
156M
    if (obj == NULL)
5536
0
  return;
5537
156M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5538
24.7k
   xmlXPathFreeObject(obj);
5539
156M
    } else {
5540
156M
  xmlXPathContextCachePtr cache =
5541
156M
      (xmlXPathContextCachePtr) ctxt->cache;
5542
5543
156M
  switch (obj->type) {
5544
99.4M
      case XPATH_NODESET:
5545
99.4M
      case XPATH_XSLT_TREE:
5546
99.4M
    if (obj->nodesetval != NULL) {
5547
89.6M
        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
89.6M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5557
89.6M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5558
89.5M
          cache->maxNodeset)))
5559
55.1M
        {
5560
55.1M
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5561
55.1M
      goto obj_cached;
5562
55.1M
        } else {
5563
34.5M
      xmlXPathFreeNodeSet(obj->nodesetval);
5564
34.5M
      obj->nodesetval = NULL;
5565
34.5M
        }
5566
89.6M
    }
5567
44.3M
    break;
5568
44.3M
      case XPATH_STRING:
5569
16.0M
    if (obj->stringval != NULL)
5570
16.0M
        xmlFree(obj->stringval);
5571
5572
16.0M
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5573
15.4M
        XP_CACHE_ADD(cache->stringObjs, obj);
5574
15.4M
        goto obj_cached;
5575
15.4M
    }
5576
556k
    break;
5577
13.9M
      case XPATH_BOOLEAN:
5578
13.9M
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5579
13.8M
        XP_CACHE_ADD(cache->booleanObjs, obj);
5580
13.8M
        goto obj_cached;
5581
13.8M
    }
5582
63.8k
    break;
5583
26.8M
      case XPATH_NUMBER:
5584
26.8M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5585
26.5M
        XP_CACHE_ADD(cache->numberObjs, obj);
5586
26.5M
        goto obj_cached;
5587
26.5M
    }
5588
327k
    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
327k
      default:
5597
35.8k
    goto free_obj;
5598
156M
  }
5599
5600
  /*
5601
  * Fallback to adding to the misc-objects slot.
5602
  */
5603
45.3M
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5604
44.1M
      XP_CACHE_ADD(cache->miscObjs, obj);
5605
44.1M
  } else
5606
1.17M
      goto free_obj;
5607
5608
155M
obj_cached:
5609
5610
#ifdef XP_DEBUG_OBJ_USAGE
5611
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5612
#endif
5613
5614
155M
  if (obj->nodesetval != NULL) {
5615
55.1M
      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
55.1M
      if (tmpset->nodeNr > 1) {
5624
2.45M
    int i;
5625
2.45M
    xmlNodePtr node;
5626
5627
35.7M
    for (i = 0; i < tmpset->nodeNr; i++) {
5628
33.3M
        node = tmpset->nodeTab[i];
5629
33.3M
        if ((node != NULL) &&
5630
33.3M
      (node->type == XML_NAMESPACE_DECL))
5631
407k
        {
5632
407k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5633
407k
        }
5634
33.3M
    }
5635
52.6M
      } else if (tmpset->nodeNr == 1) {
5636
44.2M
    if ((tmpset->nodeTab[0] != NULL) &&
5637
44.2M
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5638
1.60M
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5639
44.2M
      }
5640
55.1M
      tmpset->nodeNr = 0;
5641
55.1M
      memset(obj, 0, sizeof(xmlXPathObject));
5642
55.1M
      obj->nodesetval = tmpset;
5643
55.1M
  } else
5644
100M
      memset(obj, 0, sizeof(xmlXPathObject));
5645
5646
155M
  return;
5647
5648
1.20M
free_obj:
5649
  /*
5650
  * Cache is full; free the object.
5651
  */
5652
1.20M
  if (obj->nodesetval != NULL)
5653
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5654
#ifdef XP_DEBUG_OBJ_USAGE
5655
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5656
#endif
5657
1.20M
  xmlFree(obj);
5658
1.20M
    }
5659
1.23M
    return;
5660
156M
}
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
225k
xmlXPathCastBooleanToString (int val) {
5679
225k
    xmlChar *ret;
5680
225k
    if (val)
5681
73.2k
  ret = xmlStrdup((const xmlChar *) "true");
5682
151k
    else
5683
151k
  ret = xmlStrdup((const xmlChar *) "false");
5684
225k
    return(ret);
5685
225k
}
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
948k
xmlXPathCastNumberToString (double val) {
5697
948k
    xmlChar *ret;
5698
948k
    switch (xmlXPathIsInf(val)) {
5699
12.4k
    case 1:
5700
12.4k
  ret = xmlStrdup((const xmlChar *) "Infinity");
5701
12.4k
  break;
5702
9.70k
    case -1:
5703
9.70k
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5704
9.70k
  break;
5705
926k
    default:
5706
926k
  if (xmlXPathIsNaN(val)) {
5707
405k
      ret = xmlStrdup((const xmlChar *) "NaN");
5708
521k
  } else if (val == 0) {
5709
            /* Omit sign for negative zero. */
5710
230k
      ret = xmlStrdup((const xmlChar *) "0");
5711
290k
  } else {
5712
      /* could be improved */
5713
290k
      char buf[100];
5714
290k
      xmlXPathFormatNumber(val, buf, 99);
5715
290k
      buf[99] = 0;
5716
290k
      ret = xmlStrdup((const xmlChar *) buf);
5717
290k
  }
5718
948k
    }
5719
948k
    return(ret);
5720
948k
}
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
16.1M
xmlXPathCastNodeToString (xmlNodePtr node) {
5732
16.1M
xmlChar *ret;
5733
16.1M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5734
0
  ret = xmlStrdup((const xmlChar *) "");
5735
16.1M
    return(ret);
5736
16.1M
}
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
21.9M
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5748
21.9M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5749
14.7M
  return(xmlStrdup((const xmlChar *) ""));
5750
5751
7.18M
    if (ns->nodeNr > 1)
5752
3.46M
  xmlXPathNodeSetSort(ns);
5753
7.18M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5754
21.9M
}
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
6.50M
xmlXPathCastToString(xmlXPathObjectPtr val) {
5767
6.50M
    xmlChar *ret = NULL;
5768
5769
6.50M
    if (val == NULL)
5770
0
  return(xmlStrdup((const xmlChar *) ""));
5771
6.50M
    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
88.1k
        case XPATH_NODESET:
5779
88.1k
        case XPATH_XSLT_TREE:
5780
88.1k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5781
88.1k
      break;
5782
6.04M
  case XPATH_STRING:
5783
6.04M
      return(xmlStrdup(val->stringval));
5784
103k
        case XPATH_BOOLEAN:
5785
103k
      ret = xmlXPathCastBooleanToString(val->boolval);
5786
103k
      break;
5787
272k
  case XPATH_NUMBER: {
5788
272k
      ret = xmlXPathCastNumberToString(val->floatval);
5789
272k
      break;
5790
88.1k
  }
5791
834
  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
834
      TODO
5798
834
      ret = xmlStrdup((const xmlChar *) "");
5799
834
      break;
5800
6.50M
    }
5801
464k
    return(ret);
5802
6.50M
}
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
27.3k
xmlXPathConvertString(xmlXPathObjectPtr val) {
5815
27.3k
    xmlChar *res = NULL;
5816
5817
27.3k
    if (val == NULL)
5818
0
  return(xmlXPathNewCString(""));
5819
5820
27.3k
    switch (val->type) {
5821
0
    case XPATH_UNDEFINED:
5822
#ifdef DEBUG_EXPR
5823
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5824
#endif
5825
0
  break;
5826
4.04k
    case XPATH_NODESET:
5827
4.04k
    case XPATH_XSLT_TREE:
5828
4.04k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5829
4.04k
  break;
5830
0
    case XPATH_STRING:
5831
0
  return(val);
5832
11.3k
    case XPATH_BOOLEAN:
5833
11.3k
  res = xmlXPathCastBooleanToString(val->boolval);
5834
11.3k
  break;
5835
11.9k
    case XPATH_NUMBER:
5836
11.9k
  res = xmlXPathCastNumberToString(val->floatval);
5837
11.9k
  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
27.3k
    }
5847
27.3k
    xmlXPathFreeObject(val);
5848
27.3k
    if (res == NULL)
5849
0
  return(xmlXPathNewCString(""));
5850
27.3k
    return(xmlXPathWrapString(res));
5851
27.3k
}
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.08M
xmlXPathCastBooleanToNumber(int val) {
5863
2.08M
    if (val)
5864
494k
  return(1.0);
5865
1.59M
    return(0.0);
5866
2.08M
}
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
33.1M
xmlXPathCastStringToNumber(const xmlChar * val) {
5878
33.1M
    return(xmlXPathStringEvalNumber(val));
5879
33.1M
}
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
4.75M
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5891
4.75M
    xmlChar *strval;
5892
4.75M
    double ret;
5893
5894
4.75M
    if (node == NULL)
5895
0
  return(xmlXPathNAN);
5896
4.75M
    strval = xmlXPathCastNodeToString(node);
5897
4.75M
    if (strval == NULL)
5898
0
  return(xmlXPathNAN);
5899
4.75M
    ret = xmlXPathCastStringToNumber(strval);
5900
4.75M
    xmlFree(strval);
5901
5902
4.75M
    return(ret);
5903
4.75M
}
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
21.7M
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5915
21.7M
    xmlChar *str;
5916
21.7M
    double ret;
5917
5918
21.7M
    if (ns == NULL)
5919
1.68M
  return(xmlXPathNAN);
5920
20.0M
    str = xmlXPathCastNodeSetToString(ns);
5921
20.0M
    ret = xmlXPathCastStringToNumber(str);
5922
20.0M
    xmlFree(str);
5923
20.0M
    return(ret);
5924
21.7M
}
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
38.5M
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5936
38.5M
    double ret = 0.0;
5937
5938
38.5M
    if (val == NULL)
5939
0
  return(xmlXPathNAN);
5940
38.5M
    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
21.7M
    case XPATH_NODESET:
5948
21.7M
    case XPATH_XSLT_TREE:
5949
21.7M
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5950
21.7M
  break;
5951
8.27M
    case XPATH_STRING:
5952
8.27M
  ret = xmlXPathCastStringToNumber(val->stringval);
5953
8.27M
  break;
5954
6.47M
    case XPATH_NUMBER:
5955
6.47M
  ret = val->floatval;
5956
6.47M
  break;
5957
2.08M
    case XPATH_BOOLEAN:
5958
2.08M
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5959
2.08M
  break;
5960
5.23k
    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
5.23k
  TODO;
5967
5.23k
  ret = xmlXPathNAN;
5968
5.23k
  break;
5969
38.5M
    }
5970
38.5M
    return(ret);
5971
38.5M
}
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
2.55M
xmlXPathCastNumberToBoolean (double val) {
6005
2.55M
     if (xmlXPathIsNaN(val) || (val == 0.0))
6006
1.38M
   return(0);
6007
1.17M
     return(1);
6008
2.55M
}
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
62.1k
xmlXPathCastStringToBoolean (const xmlChar *val) {
6020
62.1k
    if ((val == NULL) || (xmlStrlen(val) == 0))
6021
1.69k
  return(0);
6022
60.4k
    return(1);
6023
62.1k
}
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
804k
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6035
804k
    if ((ns == NULL) || (ns->nodeNr == 0))
6036
571k
  return(0);
6037
233k
    return(1);
6038
804k
}
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
983k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6050
983k
    int ret = 0;
6051
6052
983k
    if (val == NULL)
6053
0
  return(0);
6054
983k
    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
804k
    case XPATH_NODESET:
6062
804k
    case XPATH_XSLT_TREE:
6063
804k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6064
804k
  break;
6065
62.1k
    case XPATH_STRING:
6066
62.1k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6067
62.1k
  break;
6068
116k
    case XPATH_NUMBER:
6069
116k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6070
116k
  break;
6071
0
    case XPATH_BOOLEAN:
6072
0
  ret = val->boolval;
6073
0
  break;
6074
1.21k
    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
1.21k
  TODO;
6081
1.21k
  ret = 0;
6082
1.21k
  break;
6083
983k
    }
6084
983k
    return(ret);
6085
983k
}
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
99.3k
xmlXPathNewContext(xmlDocPtr doc) {
6126
99.3k
    xmlXPathContextPtr ret;
6127
6128
99.3k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6129
99.3k
    if (ret == NULL) {
6130
0
        xmlXPathErrMemory(NULL, "creating context\n");
6131
0
  return(NULL);
6132
0
    }
6133
99.3k
    memset(ret, 0 , sizeof(xmlXPathContext));
6134
99.3k
    ret->doc = doc;
6135
99.3k
    ret->node = NULL;
6136
6137
99.3k
    ret->varHash = NULL;
6138
6139
99.3k
    ret->nb_types = 0;
6140
99.3k
    ret->max_types = 0;
6141
99.3k
    ret->types = NULL;
6142
6143
99.3k
    ret->funcHash = xmlHashCreate(0);
6144
6145
99.3k
    ret->nb_axis = 0;
6146
99.3k
    ret->max_axis = 0;
6147
99.3k
    ret->axis = NULL;
6148
6149
99.3k
    ret->nsHash = NULL;
6150
99.3k
    ret->user = NULL;
6151
6152
99.3k
    ret->contextSize = -1;
6153
99.3k
    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
99.3k
    xmlXPathRegisterAllFunctions(ret);
6163
6164
99.3k
    return(ret);
6165
99.3k
}
6166
6167
/**
6168
 * xmlXPathFreeContext:
6169
 * @ctxt:  the context to free
6170
 *
6171
 * Free up an xmlXPathContext
6172
 */
6173
void
6174
92.6k
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6175
92.6k
    if (ctxt == NULL) return;
6176
6177
92.6k
    if (ctxt->cache != NULL)
6178
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6179
92.6k
    xmlXPathRegisteredNsCleanup(ctxt);
6180
92.6k
    xmlXPathRegisteredFuncsCleanup(ctxt);
6181
92.6k
    xmlXPathRegisteredVariablesCleanup(ctxt);
6182
92.6k
    xmlResetError(&ctxt->lastError);
6183
92.6k
    xmlFree(ctxt);
6184
92.6k
}
6185
6186
/************************************************************************
6187
 *                  *
6188
 *    Routines to handle XPath parser contexts    *
6189
 *                  *
6190
 ************************************************************************/
6191
6192
#define CHECK_CTXT(ctxt)            \
6193
48.5k
    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.22M
    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
6.11M
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6234
6.11M
    xmlXPathParserContextPtr ret;
6235
6236
6.11M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6237
6.11M
    if (ret == NULL) {
6238
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6239
0
  return(NULL);
6240
0
    }
6241
6.11M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6242
6.11M
    ret->cur = ret->base = str;
6243
6.11M
    ret->context = ctxt;
6244
6245
6.11M
    ret->comp = xmlXPathNewCompExpr();
6246
6.11M
    if (ret->comp == NULL) {
6247
0
  xmlFree(ret->valueTab);
6248
0
  xmlFree(ret);
6249
0
  return(NULL);
6250
0
    }
6251
6.11M
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6252
0
        ret->comp->dict = ctxt->dict;
6253
0
  xmlDictReference(ret->comp->dict);
6254
0
    }
6255
6256
6.11M
    return(ret);
6257
6.11M
}
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.22M
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6270
5.22M
    xmlXPathParserContextPtr ret;
6271
6272
5.22M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6273
5.22M
    if (ret == NULL) {
6274
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6275
0
  return(NULL);
6276
0
    }
6277
5.22M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6278
6279
    /* Allocate the value stack */
6280
5.22M
    ret->valueTab = (xmlXPathObjectPtr *)
6281
5.22M
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6282
5.22M
    if (ret->valueTab == NULL) {
6283
0
  xmlFree(ret);
6284
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6285
0
  return(NULL);
6286
0
    }
6287
5.22M
    ret->valueNr = 0;
6288
5.22M
    ret->valueMax = 10;
6289
5.22M
    ret->value = NULL;
6290
5.22M
    ret->valueFrame = 0;
6291
6292
5.22M
    ret->context = ctxt;
6293
5.22M
    ret->comp = comp;
6294
6295
5.22M
    return(ret);
6296
5.22M
}
6297
6298
/**
6299
 * xmlXPathFreeParserContext:
6300
 * @ctxt:  the context to free
6301
 *
6302
 * Free up an xmlXPathParserContext
6303
 */
6304
void
6305
11.3M
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6306
11.3M
    int i;
6307
6308
11.3M
    if (ctxt->valueTab != NULL) {
6309
6.82M
        for (i = 0; i < ctxt->valueNr; i++) {
6310
1.48M
            if (ctxt->context)
6311
1.48M
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6312
0
            else
6313
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6314
1.48M
        }
6315
5.34M
        xmlFree(ctxt->valueTab);
6316
5.34M
    }
6317
11.3M
    if (ctxt->comp != NULL) {
6318
5.28M
#ifdef XPATH_STREAMING
6319
5.28M
  if (ctxt->comp->stream != NULL) {
6320
9.28k
      xmlFreePatternList(ctxt->comp->stream);
6321
9.28k
      ctxt->comp->stream = NULL;
6322
9.28k
  }
6323
5.28M
#endif
6324
5.28M
  xmlXPathFreeCompExpr(ctxt->comp);
6325
5.28M
    }
6326
11.3M
    xmlFree(ctxt);
6327
11.3M
}
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
2.14M
xmlXPathNodeValHash(xmlNodePtr node) {
6346
2.14M
    int len = 2;
6347
2.14M
    const xmlChar * string = NULL;
6348
2.14M
    xmlNodePtr tmp = NULL;
6349
2.14M
    unsigned int ret = 0;
6350
6351
2.14M
    if (node == NULL)
6352
0
  return(0);
6353
6354
2.14M
    if (node->type == XML_DOCUMENT_NODE) {
6355
178k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6356
178k
  if (tmp == NULL)
6357
83
      node = node->children;
6358
178k
  else
6359
178k
      node = tmp;
6360
6361
178k
  if (node == NULL)
6362
0
      return(0);
6363
178k
    }
6364
6365
2.14M
    switch (node->type) {
6366
48.9k
  case XML_COMMENT_NODE:
6367
100k
  case XML_PI_NODE:
6368
130k
  case XML_CDATA_SECTION_NODE:
6369
763k
  case XML_TEXT_NODE:
6370
763k
      string = node->content;
6371
763k
      if (string == NULL)
6372
0
    return(0);
6373
763k
      if (string[0] == 0)
6374
1.46k
    return(0);
6375
762k
      return(string[0] + (string[1] << 8));
6376
33.7k
  case XML_NAMESPACE_DECL:
6377
33.7k
      string = ((xmlNsPtr)node)->href;
6378
33.7k
      if (string == NULL)
6379
0
    return(0);
6380
33.7k
      if (string[0] == 0)
6381
0
    return(0);
6382
33.7k
      return(string[0] + (string[1] << 8));
6383
144k
  case XML_ATTRIBUTE_NODE:
6384
144k
      tmp = ((xmlAttrPtr) node)->children;
6385
144k
      break;
6386
1.19M
  case XML_ELEMENT_NODE:
6387
1.19M
      tmp = node->children;
6388
1.19M
      break;
6389
0
  default:
6390
0
      return(0);
6391
2.14M
    }
6392
1.51M
    while (tmp != NULL) {
6393
1.08M
  switch (tmp->type) {
6394
46.9k
      case XML_CDATA_SECTION_NODE:
6395
1.08M
      case XML_TEXT_NODE:
6396
1.08M
    string = tmp->content;
6397
1.08M
    break;
6398
0
      default:
6399
0
                string = NULL;
6400
0
    break;
6401
1.08M
  }
6402
1.08M
  if ((string != NULL) && (string[0] != 0)) {
6403
1.06M
      if (len == 1) {
6404
0
    return(ret + (string[0] << 8));
6405
0
      }
6406
1.06M
      if (string[1] == 0) {
6407
152k
    len = 1;
6408
152k
    ret = string[0];
6409
911k
      } else {
6410
911k
    return(string[0] + (string[1] << 8));
6411
911k
      }
6412
1.06M
  }
6413
  /*
6414
   * Skip to next node
6415
   */
6416
172k
  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
172k
  if (tmp == node)
6423
0
      break;
6424
6425
172k
  if (tmp->next != NULL) {
6426
0
      tmp = tmp->next;
6427
0
      continue;
6428
0
  }
6429
6430
172k
  do {
6431
172k
      tmp = tmp->parent;
6432
172k
      if (tmp == NULL)
6433
0
    break;
6434
172k
      if (tmp == node) {
6435
172k
    tmp = NULL;
6436
172k
    break;
6437
172k
      }
6438
0
      if (tmp->next != NULL) {
6439
0
    tmp = tmp->next;
6440
0
    break;
6441
0
      }
6442
0
  } while (tmp != NULL);
6443
172k
    }
6444
432k
    return(ret);
6445
1.34M
}
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
100k
xmlXPathStringHash(const xmlChar * string) {
6458
100k
    if (string == NULL)
6459
0
  return(0);
6460
100k
    if (string[0] == 0)
6461
32.3k
  return(0);
6462
68.2k
    return(string[0] + (string[1] << 8));
6463
100k
}
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
892k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6490
892k
    int i, ret = 0;
6491
892k
    xmlNodeSetPtr ns;
6492
892k
    xmlChar *str2;
6493
6494
892k
    if ((f == NULL) || (arg == NULL) ||
6495
892k
  ((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
892k
    ns = arg->nodesetval;
6501
892k
    if (ns != NULL) {
6502
1.82M
  for (i = 0;i < ns->nodeNr;i++) {
6503
1.08M
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6504
1.08M
       if (str2 != NULL) {
6505
1.08M
     valuePush(ctxt,
6506
1.08M
         xmlXPathCacheNewString(ctxt->context, str2));
6507
1.08M
     xmlFree(str2);
6508
1.08M
     xmlXPathNumberFunction(ctxt, 1);
6509
1.08M
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6510
1.08M
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6511
1.08M
     if (ret)
6512
46.6k
         break;
6513
1.08M
       }
6514
1.08M
  }
6515
788k
    }
6516
892k
    xmlXPathReleaseObject(ctxt->context, arg);
6517
892k
    xmlXPathReleaseObject(ctxt->context, f);
6518
892k
    return(ret);
6519
892k
}
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
167k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6545
167k
    int i, ret = 0;
6546
167k
    xmlNodeSetPtr ns;
6547
167k
    xmlChar *str2;
6548
6549
167k
    if ((s == NULL) || (arg == NULL) ||
6550
167k
  ((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
167k
    ns = arg->nodesetval;
6556
167k
    if (ns != NULL) {
6557
952k
  for (i = 0;i < ns->nodeNr;i++) {
6558
823k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6559
823k
       if (str2 != NULL) {
6560
823k
     valuePush(ctxt,
6561
823k
         xmlXPathCacheNewString(ctxt->context, str2));
6562
823k
     xmlFree(str2);
6563
823k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6564
823k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6565
823k
     if (ret)
6566
10.7k
         break;
6567
823k
       }
6568
823k
  }
6569
139k
    }
6570
167k
    xmlXPathReleaseObject(ctxt->context, arg);
6571
167k
    xmlXPathReleaseObject(ctxt->context, s);
6572
167k
    return(ret);
6573
167k
}
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
1.16M
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6606
1.16M
    int i, j, init = 0;
6607
1.16M
    double val1;
6608
1.16M
    double *values2;
6609
1.16M
    int ret = 0;
6610
1.16M
    xmlNodeSetPtr ns1;
6611
1.16M
    xmlNodeSetPtr ns2;
6612
6613
1.16M
    if ((arg1 == NULL) ||
6614
1.16M
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6615
0
  xmlXPathFreeObject(arg2);
6616
0
        return(0);
6617
0
    }
6618
1.16M
    if ((arg2 == NULL) ||
6619
1.16M
  ((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
1.16M
    ns1 = arg1->nodesetval;
6626
1.16M
    ns2 = arg2->nodesetval;
6627
6628
1.16M
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6629
630k
  xmlXPathFreeObject(arg1);
6630
630k
  xmlXPathFreeObject(arg2);
6631
630k
  return(0);
6632
630k
    }
6633
531k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6634
268k
  xmlXPathFreeObject(arg1);
6635
268k
  xmlXPathFreeObject(arg2);
6636
268k
  return(0);
6637
268k
    }
6638
6639
263k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6640
263k
    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
3.44M
    for (i = 0;i < ns1->nodeNr;i++) {
6648
3.21M
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6649
3.21M
  if (xmlXPathIsNaN(val1))
6650
2.94M
      continue;
6651
1.33M
  for (j = 0;j < ns2->nodeNr;j++) {
6652
1.10M
      if (init == 0) {
6653
675k
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6654
675k
      }
6655
1.10M
      if (xmlXPathIsNaN(values2[j]))
6656
957k
    continue;
6657
143k
      if (inf && strict)
6658
35.5k
    ret = (val1 < values2[j]);
6659
108k
      else if (inf && !strict)
6660
36.7k
    ret = (val1 <= values2[j]);
6661
71.5k
      else if (!inf && strict)
6662
44.1k
    ret = (val1 > values2[j]);
6663
27.4k
      else if (!inf && !strict)
6664
27.4k
    ret = (val1 >= values2[j]);
6665
143k
      if (ret)
6666
36.9k
    break;
6667
143k
  }
6668
271k
  if (ret)
6669
36.9k
      break;
6670
234k
  init = 1;
6671
234k
    }
6672
263k
    xmlFree(values2);
6673
263k
    xmlXPathFreeObject(arg1);
6674
263k
    xmlXPathFreeObject(arg2);
6675
263k
    return(ret);
6676
263k
}
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.70M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6702
1.70M
    if ((val == NULL) || (arg == NULL) ||
6703
1.70M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6704
0
        return(0);
6705
6706
1.70M
    switch(val->type) {
6707
892k
        case XPATH_NUMBER:
6708
892k
      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
167k
        case XPATH_STRING:
6713
167k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6714
643k
        case XPATH_BOOLEAN:
6715
643k
      valuePush(ctxt, arg);
6716
643k
      xmlXPathBooleanFunction(ctxt, 1);
6717
643k
      valuePush(ctxt, val);
6718
643k
      return(xmlXPathCompareValues(ctxt, inf, strict));
6719
27
  default:
6720
27
            xmlGenericError(xmlGenericErrorContext,
6721
27
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6722
27
                    "and object of type %d\n",
6723
27
                    val->type);
6724
27
            xmlXPathReleaseObject(ctxt->context, arg);
6725
27
            xmlXPathReleaseObject(ctxt->context, val);
6726
27
            XP_ERROR0(XPATH_INVALID_TYPE);
6727
1.70M
    }
6728
0
    return(0);
6729
1.70M
}
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
247k
{
6748
247k
    int i;
6749
247k
    xmlNodeSetPtr ns;
6750
247k
    xmlChar *str2;
6751
247k
    unsigned int hash;
6752
6753
247k
    if ((str == NULL) || (arg == NULL) ||
6754
247k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6755
0
        return (0);
6756
247k
    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
247k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6762
147k
        return (0);
6763
100k
    hash = xmlXPathStringHash(str);
6764
1.05M
    for (i = 0; i < ns->nodeNr; i++) {
6765
983k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6766
41.8k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6767
41.8k
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6768
15.0k
                xmlFree(str2);
6769
15.0k
    if (neq)
6770
5.85k
        continue;
6771
9.23k
                return (1);
6772
26.7k
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6773
0
    if (neq)
6774
0
        continue;
6775
0
                return (1);
6776
26.7k
            } else if (neq) {
6777
2.60k
    if (str2 != NULL)
6778
2.60k
        xmlFree(str2);
6779
2.60k
    return (1);
6780
2.60k
      }
6781
24.1k
            if (str2 != NULL)
6782
24.1k
                xmlFree(str2);
6783
941k
        } else if (neq)
6784
17.6k
      return (1);
6785
983k
    }
6786
71.0k
    return (0);
6787
100k
}
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
1.23M
    xmlXPathObjectPtr arg, double f, int neq) {
6807
1.23M
  int i, ret=0;
6808
1.23M
  xmlNodeSetPtr ns;
6809
1.23M
  xmlChar *str2;
6810
1.23M
  xmlXPathObjectPtr val;
6811
1.23M
  double v;
6812
6813
1.23M
    if ((arg == NULL) ||
6814
1.23M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6815
0
        return(0);
6816
6817
1.23M
    ns = arg->nodesetval;
6818
1.23M
    if (ns != NULL) {
6819
2.55M
  for (i=0;i<ns->nodeNr;i++) {
6820
1.43M
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6821
1.43M
      if (str2 != NULL) {
6822
1.43M
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6823
1.43M
    xmlFree(str2);
6824
1.43M
    xmlXPathNumberFunction(ctxt, 1);
6825
1.43M
    val = valuePop(ctxt);
6826
1.43M
    v = val->floatval;
6827
1.43M
    xmlXPathReleaseObject(ctxt->context, val);
6828
1.43M
    if (!xmlXPathIsNaN(v)) {
6829
253k
        if ((!neq) && (v==f)) {
6830
10.9k
      ret = 1;
6831
10.9k
      break;
6832
242k
        } else if ((neq) && (v!=f)) {
6833
37.9k
      ret = 1;
6834
37.9k
      break;
6835
37.9k
        }
6836
1.18M
    } else { /* NaN is unequal to any value */
6837
1.18M
        if (neq)
6838
139k
      ret = 1;
6839
1.18M
    }
6840
1.43M
      }
6841
1.43M
  }
6842
1.17M
    }
6843
6844
1.23M
    return(ret);
6845
1.23M
}
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
1.00M
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6867
1.00M
    int i, j;
6868
1.00M
    unsigned int *hashs1;
6869
1.00M
    unsigned int *hashs2;
6870
1.00M
    xmlChar **values1;
6871
1.00M
    xmlChar **values2;
6872
1.00M
    int ret = 0;
6873
1.00M
    xmlNodeSetPtr ns1;
6874
1.00M
    xmlNodeSetPtr ns2;
6875
6876
1.00M
    if ((arg1 == NULL) ||
6877
1.00M
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6878
0
        return(0);
6879
1.00M
    if ((arg2 == NULL) ||
6880
1.00M
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6881
0
        return(0);
6882
6883
1.00M
    ns1 = arg1->nodesetval;
6884
1.00M
    ns2 = arg2->nodesetval;
6885
6886
1.00M
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6887
405k
  return(0);
6888
604k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6889
292k
  return(0);
6890
6891
    /*
6892
     * for equal, check if there is a node pertaining to both sets
6893
     */
6894
312k
    if (neq == 0)
6895
859k
  for (i = 0;i < ns1->nodeNr;i++)
6896
2.50M
      for (j = 0;j < ns2->nodeNr;j++)
6897
1.84M
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6898
52.6k
        return(1);
6899
6900
259k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6901
259k
    if (values1 == NULL) {
6902
        /* TODO: Propagate memory error. */
6903
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6904
0
  return(0);
6905
0
    }
6906
259k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6907
259k
    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
259k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6914
259k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6915
259k
    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
259k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6923
259k
    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
259k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6932
737k
    for (i = 0;i < ns1->nodeNr;i++) {
6933
602k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6934
1.78M
  for (j = 0;j < ns2->nodeNr;j++) {
6935
1.31M
      if (i == 0)
6936
555k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6937
1.31M
      if (hashs1[i] != hashs2[j]) {
6938
1.14M
    if (neq) {
6939
91.1k
        ret = 1;
6940
91.1k
        break;
6941
91.1k
    }
6942
1.14M
      }
6943
164k
      else {
6944
164k
    if (values1[i] == NULL)
6945
114k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6946
164k
    if (values2[j] == NULL)
6947
103k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6948
164k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6949
164k
    if (ret)
6950
33.6k
        break;
6951
164k
      }
6952
1.31M
  }
6953
602k
  if (ret)
6954
124k
      break;
6955
602k
    }
6956
1.13M
    for (i = 0;i < ns1->nodeNr;i++)
6957
870k
  if (values1[i] != NULL)
6958
114k
      xmlFree(values1[i]);
6959
938k
    for (j = 0;j < ns2->nodeNr;j++)
6960
678k
  if (values2[j] != NULL)
6961
103k
      xmlFree(values2[j]);
6962
259k
    xmlFree(values1);
6963
259k
    xmlFree(values2);
6964
259k
    xmlFree(hashs1);
6965
259k
    xmlFree(hashs2);
6966
259k
    return(ret);
6967
259k
}
6968
6969
static int
6970
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6971
4.40M
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6972
4.40M
    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
4.40M
    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
3.27M
        case XPATH_BOOLEAN:
6985
3.27M
      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.06M
    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.06M
        ret = (arg1->boolval == arg2->boolval);
6999
1.06M
        break;
7000
2.04M
    case XPATH_NUMBER:
7001
2.04M
        ret = (arg1->boolval ==
7002
2.04M
         xmlXPathCastNumberToBoolean(arg2->floatval));
7003
2.04M
        break;
7004
152k
    case XPATH_STRING:
7005
152k
        if ((arg2->stringval == NULL) ||
7006
152k
      (arg2->stringval[0] == 0)) ret = 0;
7007
92.5k
        else
7008
92.5k
      ret = 1;
7009
152k
        ret = (arg1->boolval == ret);
7010
152k
        break;
7011
7.14k
    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
7.14k
        TODO
7018
7.14k
        break;
7019
0
    case XPATH_NODESET:
7020
0
    case XPATH_XSLT_TREE:
7021
0
        break;
7022
3.27M
      }
7023
3.27M
      break;
7024
3.27M
        case XPATH_NUMBER:
7025
875k
      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
391k
    case XPATH_BOOLEAN:
7033
391k
        ret = (arg2->boolval==
7034
391k
         xmlXPathCastNumberToBoolean(arg1->floatval));
7035
391k
        break;
7036
36.6k
    case XPATH_STRING:
7037
36.6k
        valuePush(ctxt, arg2);
7038
36.6k
        xmlXPathNumberFunction(ctxt, 1);
7039
36.6k
        arg2 = valuePop(ctxt);
7040
                    /* Falls through. */
7041
480k
    case XPATH_NUMBER:
7042
        /* Hand check NaN and Infinity equalities */
7043
480k
        if (xmlXPathIsNaN(arg1->floatval) ||
7044
480k
          xmlXPathIsNaN(arg2->floatval)) {
7045
429k
            ret = 0;
7046
429k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7047
7.03k
            if (xmlXPathIsInf(arg2->floatval) == 1)
7048
2.95k
          ret = 1;
7049
4.08k
      else
7050
4.08k
          ret = 0;
7051
44.3k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7052
6.08k
      if (xmlXPathIsInf(arg2->floatval) == -1)
7053
23
          ret = 1;
7054
6.06k
      else
7055
6.06k
          ret = 0;
7056
38.2k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7057
7.21k
      if (xmlXPathIsInf(arg1->floatval) == 1)
7058
0
          ret = 1;
7059
7.21k
      else
7060
7.21k
          ret = 0;
7061
31.0k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7062
6.48k
      if (xmlXPathIsInf(arg1->floatval) == -1)
7063
0
          ret = 1;
7064
6.48k
      else
7065
6.48k
          ret = 0;
7066
24.5k
        } else {
7067
24.5k
            ret = (arg1->floatval == arg2->floatval);
7068
24.5k
        }
7069
480k
        break;
7070
3.66k
    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
3.66k
        TODO
7077
3.66k
        break;
7078
0
    case XPATH_NODESET:
7079
0
    case XPATH_XSLT_TREE:
7080
0
        break;
7081
875k
      }
7082
875k
      break;
7083
875k
        case XPATH_STRING:
7084
252k
      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
20.7k
    case XPATH_BOOLEAN:
7092
20.7k
        if ((arg1->stringval == NULL) ||
7093
20.7k
      (arg1->stringval[0] == 0)) ret = 0;
7094
14.7k
        else
7095
14.7k
      ret = 1;
7096
20.7k
        ret = (arg2->boolval == ret);
7097
20.7k
        break;
7098
16.1k
    case XPATH_STRING:
7099
16.1k
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7100
16.1k
        break;
7101
212k
    case XPATH_NUMBER:
7102
212k
        valuePush(ctxt, arg1);
7103
212k
        xmlXPathNumberFunction(ctxt, 1);
7104
212k
        arg1 = valuePop(ctxt);
7105
        /* Hand check NaN and Infinity equalities */
7106
212k
        if (xmlXPathIsNaN(arg1->floatval) ||
7107
212k
          xmlXPathIsNaN(arg2->floatval)) {
7108
199k
            ret = 0;
7109
199k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7110
2.83k
      if (xmlXPathIsInf(arg2->floatval) == 1)
7111
190
          ret = 1;
7112
2.64k
      else
7113
2.64k
          ret = 0;
7114
10.7k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7115
1.11k
      if (xmlXPathIsInf(arg2->floatval) == -1)
7116
0
          ret = 1;
7117
1.11k
      else
7118
1.11k
          ret = 0;
7119
9.61k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7120
602
      if (xmlXPathIsInf(arg1->floatval) == 1)
7121
0
          ret = 1;
7122
602
      else
7123
602
          ret = 0;
7124
9.01k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7125
807
      if (xmlXPathIsInf(arg1->floatval) == -1)
7126
0
          ret = 1;
7127
807
      else
7128
807
          ret = 0;
7129
8.20k
        } else {
7130
8.20k
            ret = (arg1->floatval == arg2->floatval);
7131
8.20k
        }
7132
212k
        break;
7133
2.88k
    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
2.88k
        TODO
7140
2.88k
        break;
7141
0
    case XPATH_NODESET:
7142
0
    case XPATH_XSLT_TREE:
7143
0
        break;
7144
252k
      }
7145
252k
      break;
7146
252k
        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
1.94k
      TODO
7153
1.94k
      break;
7154
0
  case XPATH_NODESET:
7155
0
  case XPATH_XSLT_TREE:
7156
0
      break;
7157
4.40M
    }
7158
4.40M
    xmlXPathReleaseObject(ctxt->context, arg1);
7159
4.40M
    xmlXPathReleaseObject(ctxt->context, arg2);
7160
4.40M
    return(ret);
7161
4.40M
}
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
6.74M
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7173
6.74M
    xmlXPathObjectPtr arg1, arg2, argtmp;
7174
6.74M
    int ret = 0;
7175
7176
6.74M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7177
6.74M
    arg2 = valuePop(ctxt);
7178
6.74M
    arg1 = valuePop(ctxt);
7179
6.74M
    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
6.74M
    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
6.74M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7200
6.74M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7201
  /*
7202
   *Hack it to assure arg1 is the nodeset
7203
   */
7204
3.23M
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7205
1.97M
    argtmp = arg2;
7206
1.97M
    arg2 = arg1;
7207
1.97M
    arg1 = argtmp;
7208
1.97M
  }
7209
3.23M
  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
615k
      case XPATH_NODESET:
7217
615k
      case XPATH_XSLT_TREE:
7218
615k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7219
615k
    break;
7220
1.37M
      case XPATH_BOOLEAN:
7221
1.37M
    if ((arg1->nodesetval == NULL) ||
7222
1.37M
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7223
698k
    else
7224
698k
        ret = 1;
7225
1.37M
    ret = (ret == arg2->boolval);
7226
1.37M
    break;
7227
1.03M
      case XPATH_NUMBER:
7228
1.03M
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7229
1.03M
    break;
7230
209k
      case XPATH_STRING:
7231
209k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7232
209k
    break;
7233
4.05k
      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
4.05k
    TODO
7240
4.05k
    break;
7241
3.23M
  }
7242
3.23M
  xmlXPathReleaseObject(ctxt->context, arg1);
7243
3.23M
  xmlXPathReleaseObject(ctxt->context, arg2);
7244
3.23M
  return(ret);
7245
3.23M
    }
7246
7247
3.51M
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7248
6.74M
}
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
2.02M
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7260
2.02M
    xmlXPathObjectPtr arg1, arg2, argtmp;
7261
2.02M
    int ret = 0;
7262
7263
2.02M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7264
2.02M
    arg2 = valuePop(ctxt);
7265
2.02M
    arg1 = valuePop(ctxt);
7266
2.02M
    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
2.02M
    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
2.02M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7287
2.02M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7288
  /*
7289
   *Hack it to assure arg1 is the nodeset
7290
   */
7291
1.12M
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7292
576k
    argtmp = arg2;
7293
576k
    arg2 = arg1;
7294
576k
    arg1 = argtmp;
7295
576k
  }
7296
1.12M
  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
394k
      case XPATH_NODESET:
7304
394k
      case XPATH_XSLT_TREE:
7305
394k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7306
394k
    break;
7307
497k
      case XPATH_BOOLEAN:
7308
497k
    if ((arg1->nodesetval == NULL) ||
7309
497k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7310
224k
    else
7311
224k
        ret = 1;
7312
497k
    ret = (ret != arg2->boolval);
7313
497k
    break;
7314
197k
      case XPATH_NUMBER:
7315
197k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7316
197k
    break;
7317
38.3k
      case XPATH_STRING:
7318
38.3k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7319
38.3k
    break;
7320
1.84k
      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
1.84k
    TODO
7327
1.84k
    break;
7328
1.12M
  }
7329
1.12M
  xmlXPathReleaseObject(ctxt->context, arg1);
7330
1.12M
  xmlXPathReleaseObject(ctxt->context, arg2);
7331
1.12M
  return(ret);
7332
1.12M
    }
7333
7334
893k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7335
2.02M
}
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
6.99M
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7363
6.99M
    int ret = 0, arg1i = 0, arg2i = 0;
7364
6.99M
    xmlXPathObjectPtr arg1, arg2;
7365
7366
6.99M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7367
6.99M
    arg2 = valuePop(ctxt);
7368
6.99M
    arg1 = valuePop(ctxt);
7369
6.99M
    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
6.99M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7378
6.99M
      (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.86M
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7385
2.86M
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7386
1.16M
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7387
1.70M
  } else {
7388
1.70M
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7389
770k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7390
770k
                                arg1, arg2);
7391
932k
      } else {
7392
932k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7393
932k
                                arg2, arg1);
7394
932k
      }
7395
1.70M
  }
7396
2.86M
  return(ret);
7397
2.86M
    }
7398
7399
4.13M
    if (arg1->type != XPATH_NUMBER) {
7400
2.03M
  valuePush(ctxt, arg1);
7401
2.03M
  xmlXPathNumberFunction(ctxt, 1);
7402
2.03M
  arg1 = valuePop(ctxt);
7403
2.03M
    }
7404
4.13M
    if (arg1->type != XPATH_NUMBER) {
7405
0
  xmlXPathFreeObject(arg1);
7406
0
  xmlXPathFreeObject(arg2);
7407
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7408
0
    }
7409
4.13M
    if (arg2->type != XPATH_NUMBER) {
7410
1.64M
  valuePush(ctxt, arg2);
7411
1.64M
  xmlXPathNumberFunction(ctxt, 1);
7412
1.64M
  arg2 = valuePop(ctxt);
7413
1.64M
    }
7414
4.13M
    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
4.13M
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7425
2.88M
  ret=0;
7426
2.88M
    } else {
7427
1.24M
  arg1i=xmlXPathIsInf(arg1->floatval);
7428
1.24M
  arg2i=xmlXPathIsInf(arg2->floatval);
7429
1.24M
  if (inf && strict) {
7430
333k
      if ((arg1i == -1 && arg2i != -1) ||
7431
333k
    (arg2i == 1 && arg1i != 1)) {
7432
51.3k
    ret = 1;
7433
282k
      } else if (arg1i == 0 && arg2i == 0) {
7434
255k
    ret = (arg1->floatval < arg2->floatval);
7435
255k
      } else {
7436
26.6k
    ret = 0;
7437
26.6k
      }
7438
333k
  }
7439
910k
  else if (inf && !strict) {
7440
269k
      if (arg1i == -1 || arg2i == 1) {
7441
32.0k
    ret = 1;
7442
237k
      } else if (arg1i == 0 && arg2i == 0) {
7443
217k
    ret = (arg1->floatval <= arg2->floatval);
7444
217k
      } else {
7445
19.8k
    ret = 0;
7446
19.8k
      }
7447
269k
  }
7448
640k
  else if (!inf && strict) {
7449
446k
      if ((arg1i == 1 && arg2i != 1) ||
7450
446k
    (arg2i == -1 && arg1i != -1)) {
7451
19.8k
    ret = 1;
7452
426k
      } else if (arg1i == 0 && arg2i == 0) {
7453
411k
    ret = (arg1->floatval > arg2->floatval);
7454
411k
      } else {
7455
15.2k
    ret = 0;
7456
15.2k
      }
7457
446k
  }
7458
194k
  else if (!inf && !strict) {
7459
194k
      if (arg1i == 1 || arg2i == -1) {
7460
12.6k
    ret = 1;
7461
181k
      } else if (arg1i == 0 && arg2i == 0) {
7462
176k
    ret = (arg1->floatval >= arg2->floatval);
7463
176k
      } else {
7464
5.72k
    ret = 0;
7465
5.72k
      }
7466
194k
  }
7467
1.24M
    }
7468
4.13M
    xmlXPathReleaseObject(ctxt->context, arg1);
7469
4.13M
    xmlXPathReleaseObject(ctxt->context, arg2);
7470
4.13M
    return(ret);
7471
4.13M
}
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
3.86M
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7483
3.86M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7484
3.86M
    CAST_TO_NUMBER;
7485
3.86M
    CHECK_TYPE(XPATH_NUMBER);
7486
3.86M
    ctxt->value->floatval = -ctxt->value->floatval;
7487
3.86M
}
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
1.20M
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7499
1.20M
    xmlXPathObjectPtr arg;
7500
1.20M
    double val;
7501
7502
1.20M
    arg = valuePop(ctxt);
7503
1.20M
    if (arg == NULL)
7504
1.20M
  XP_ERROR(XPATH_INVALID_OPERAND);
7505
1.20M
    val = xmlXPathCastToNumber(arg);
7506
1.20M
    xmlXPathReleaseObject(ctxt->context, arg);
7507
1.20M
    CAST_TO_NUMBER;
7508
1.20M
    CHECK_TYPE(XPATH_NUMBER);
7509
1.20M
    ctxt->value->floatval += val;
7510
1.20M
}
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
6.47M
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7522
6.47M
    xmlXPathObjectPtr arg;
7523
6.47M
    double val;
7524
7525
6.47M
    arg = valuePop(ctxt);
7526
6.47M
    if (arg == NULL)
7527
6.47M
  XP_ERROR(XPATH_INVALID_OPERAND);
7528
6.47M
    val = xmlXPathCastToNumber(arg);
7529
6.47M
    xmlXPathReleaseObject(ctxt->context, arg);
7530
6.47M
    CAST_TO_NUMBER;
7531
6.47M
    CHECK_TYPE(XPATH_NUMBER);
7532
6.47M
    ctxt->value->floatval -= val;
7533
6.47M
}
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
13.9M
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7545
13.9M
    xmlXPathObjectPtr arg;
7546
13.9M
    double val;
7547
7548
13.9M
    arg = valuePop(ctxt);
7549
13.9M
    if (arg == NULL)
7550
13.9M
  XP_ERROR(XPATH_INVALID_OPERAND);
7551
13.9M
    val = xmlXPathCastToNumber(arg);
7552
13.9M
    xmlXPathReleaseObject(ctxt->context, arg);
7553
13.9M
    CAST_TO_NUMBER;
7554
13.9M
    CHECK_TYPE(XPATH_NUMBER);
7555
13.9M
    ctxt->value->floatval *= val;
7556
13.9M
}
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
69.8k
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7569
69.8k
    xmlXPathObjectPtr arg;
7570
69.8k
    double val;
7571
7572
69.8k
    arg = valuePop(ctxt);
7573
69.8k
    if (arg == NULL)
7574
69.8k
  XP_ERROR(XPATH_INVALID_OPERAND);
7575
69.8k
    val = xmlXPathCastToNumber(arg);
7576
69.8k
    xmlXPathReleaseObject(ctxt->context, arg);
7577
69.8k
    CAST_TO_NUMBER;
7578
69.8k
    CHECK_TYPE(XPATH_NUMBER);
7579
69.8k
    ctxt->value->floatval /= val;
7580
69.8k
}
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
100k
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7592
100k
    xmlXPathObjectPtr arg;
7593
100k
    double arg1, arg2;
7594
7595
100k
    arg = valuePop(ctxt);
7596
100k
    if (arg == NULL)
7597
100k
  XP_ERROR(XPATH_INVALID_OPERAND);
7598
100k
    arg2 = xmlXPathCastToNumber(arg);
7599
100k
    xmlXPathReleaseObject(ctxt->context, arg);
7600
100k
    CAST_TO_NUMBER;
7601
100k
    CHECK_TYPE(XPATH_NUMBER);
7602
100k
    arg1 = ctxt->value->floatval;
7603
100k
    if (arg2 == 0)
7604
7.12k
  ctxt->value->floatval = xmlXPathNAN;
7605
93.8k
    else {
7606
93.8k
  ctxt->value->floatval = fmod(arg1, arg2);
7607
93.8k
    }
7608
100k
}
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
137k
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7654
137k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7655
137k
    if (cur == NULL)
7656
69.8k
        return(ctxt->context->node);
7657
67.6k
    return(NULL);
7658
137k
}
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
4.86M
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7672
4.86M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7673
4.86M
    if (cur == NULL) {
7674
2.52M
  if (ctxt->context->node == NULL) return(NULL);
7675
2.52M
  switch (ctxt->context->node->type) {
7676
854k
            case XML_ELEMENT_NODE:
7677
2.01M
            case XML_TEXT_NODE:
7678
2.07M
            case XML_CDATA_SECTION_NODE:
7679
2.07M
            case XML_ENTITY_REF_NODE:
7680
2.07M
            case XML_ENTITY_NODE:
7681
2.16M
            case XML_PI_NODE:
7682
2.26M
            case XML_COMMENT_NODE:
7683
2.26M
            case XML_NOTATION_NODE:
7684
2.26M
            case XML_DTD_NODE:
7685
2.26M
    return(ctxt->context->node->children);
7686
227k
            case XML_DOCUMENT_NODE:
7687
227k
            case XML_DOCUMENT_TYPE_NODE:
7688
227k
            case XML_DOCUMENT_FRAG_NODE:
7689
227k
            case XML_HTML_DOCUMENT_NODE:
7690
227k
    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
14.4k
            case XML_ATTRIBUTE_NODE:
7695
32.1k
      case XML_NAMESPACE_DECL:
7696
32.1k
      case XML_XINCLUDE_START:
7697
32.1k
      case XML_XINCLUDE_END:
7698
32.1k
    return(NULL);
7699
2.52M
  }
7700
0
  return(NULL);
7701
2.52M
    }
7702
2.34M
    if ((cur->type == XML_DOCUMENT_NODE) ||
7703
2.34M
        (cur->type == XML_HTML_DOCUMENT_NODE))
7704
0
  return(NULL);
7705
2.34M
    return(cur->next);
7706
2.34M
}
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
100M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7720
100M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7721
100M
    if (cur == NULL) {
7722
55.2M
  cur = ctxt->context->node;
7723
55.2M
  if (cur == NULL) return(NULL);
7724
  /*
7725
  * Get the first element child.
7726
  */
7727
55.2M
  switch (cur->type) {
7728
33.0M
            case XML_ELEMENT_NODE:
7729
33.0M
      case XML_DOCUMENT_FRAG_NODE:
7730
33.0M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7731
33.0M
            case XML_ENTITY_NODE:
7732
33.0M
    cur = cur->children;
7733
33.0M
    if (cur != NULL) {
7734
25.8M
        if (cur->type == XML_ELEMENT_NODE)
7735
0
      return(cur);
7736
25.8M
        do {
7737
25.8M
      cur = cur->next;
7738
25.8M
        } while ((cur != NULL) &&
7739
25.8M
      (cur->type != XML_ELEMENT_NODE));
7740
25.8M
        return(cur);
7741
25.8M
    }
7742
7.24M
    return(NULL);
7743
4.21M
            case XML_DOCUMENT_NODE:
7744
4.21M
            case XML_HTML_DOCUMENT_NODE:
7745
4.21M
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7746
17.9M
      default:
7747
17.9M
    return(NULL);
7748
55.2M
  }
7749
0
  return(NULL);
7750
55.2M
    }
7751
    /*
7752
    * Get the next sibling element node.
7753
    */
7754
44.8M
    switch (cur->type) {
7755
44.8M
  case XML_ELEMENT_NODE:
7756
44.8M
  case XML_TEXT_NODE:
7757
44.8M
  case XML_ENTITY_REF_NODE:
7758
44.8M
  case XML_ENTITY_NODE:
7759
44.8M
  case XML_CDATA_SECTION_NODE:
7760
44.8M
  case XML_PI_NODE:
7761
44.8M
  case XML_COMMENT_NODE:
7762
44.8M
  case XML_XINCLUDE_END:
7763
44.8M
      break;
7764
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7765
0
  default:
7766
0
      return(NULL);
7767
44.8M
    }
7768
44.8M
    if (cur->next != NULL) {
7769
40.7M
  if (cur->next->type == XML_ELEMENT_NODE)
7770
10.1M
      return(cur->next);
7771
30.6M
  cur = cur->next;
7772
47.8M
  do {
7773
47.8M
      cur = cur->next;
7774
47.8M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7775
30.6M
  return(cur);
7776
40.7M
    }
7777
4.12M
    return(NULL);
7778
44.8M
}
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
217M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7865
217M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7866
217M
    if (cur == NULL) {
7867
6.44M
  if (ctxt->context->node == NULL)
7868
0
      return(NULL);
7869
6.44M
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7870
6.44M
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7871
162k
      return(NULL);
7872
7873
6.28M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7874
2.99M
      return(ctxt->context->doc->children);
7875
3.29M
        return(ctxt->context->node->children);
7876
6.28M
    }
7877
7878
211M
    if (cur->type == XML_NAMESPACE_DECL)
7879
0
        return(NULL);
7880
211M
    if (cur->children != NULL) {
7881
  /*
7882
   * Do not descend on entities declarations
7883
   */
7884
52.2M
  if (cur->children->type != XML_ENTITY_DECL) {
7885
52.2M
      cur = cur->children;
7886
      /*
7887
       * Skip DTDs
7888
       */
7889
52.2M
      if (cur->type != XML_DTD_NODE)
7890
52.2M
    return(cur);
7891
52.2M
  }
7892
52.2M
    }
7893
7894
159M
    if (cur == ctxt->context->node) return(NULL);
7895
7896
158M
    while (cur->next != NULL) {
7897
106M
  cur = cur->next;
7898
106M
  if ((cur->type != XML_ENTITY_DECL) &&
7899
106M
      (cur->type != XML_DTD_NODE))
7900
106M
      return(cur);
7901
106M
    }
7902
7903
56.5M
    do {
7904
56.5M
        cur = cur->parent;
7905
56.5M
  if (cur == NULL) break;
7906
56.5M
  if (cur == ctxt->context->node) return(NULL);
7907
48.4M
  if (cur->next != NULL) {
7908
43.8M
      cur = cur->next;
7909
43.8M
      return(cur);
7910
43.8M
  }
7911
48.4M
    } while (cur != NULL);
7912
0
    return(cur);
7913
51.9M
}
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
91.1M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7930
91.1M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7931
91.1M
    if (cur == NULL)
7932
4.49M
        return(ctxt->context->node);
7933
7934
86.6M
    if (ctxt->context->node == NULL)
7935
0
        return(NULL);
7936
86.6M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7937
86.6M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7938
220k
        return(NULL);
7939
7940
86.4M
    return(xmlXPathNextDescendant(ctxt, cur));
7941
86.6M
}
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
4.80M
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7955
4.80M
    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
4.80M
    if (cur == NULL) {
7962
2.48M
  if (ctxt->context->node == NULL) return(NULL);
7963
2.48M
  switch (ctxt->context->node->type) {
7964
946k
            case XML_ELEMENT_NODE:
7965
2.05M
            case XML_TEXT_NODE:
7966
2.10M
            case XML_CDATA_SECTION_NODE:
7967
2.10M
            case XML_ENTITY_REF_NODE:
7968
2.10M
            case XML_ENTITY_NODE:
7969
2.18M
            case XML_PI_NODE:
7970
2.26M
            case XML_COMMENT_NODE:
7971
2.26M
            case XML_NOTATION_NODE:
7972
2.26M
            case XML_DTD_NODE:
7973
2.26M
      case XML_ELEMENT_DECL:
7974
2.26M
      case XML_ATTRIBUTE_DECL:
7975
2.26M
      case XML_XINCLUDE_START:
7976
2.26M
      case XML_XINCLUDE_END:
7977
2.26M
      case XML_ENTITY_DECL:
7978
2.26M
    if (ctxt->context->node->parent == NULL)
7979
0
        return((xmlNodePtr) ctxt->context->doc);
7980
2.26M
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7981
2.26M
        ((ctxt->context->node->parent->name[0] == ' ') ||
7982
1.97M
         (xmlStrEqual(ctxt->context->node->parent->name,
7983
1.97M
         BAD_CAST "fake node libxslt"))))
7984
0
        return(NULL);
7985
2.26M
    return(ctxt->context->node->parent);
7986
39.5k
            case XML_ATTRIBUTE_NODE: {
7987
39.5k
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7988
7989
39.5k
    return(att->parent);
7990
2.26M
      }
7991
80.0k
            case XML_DOCUMENT_NODE:
7992
80.0k
            case XML_DOCUMENT_TYPE_NODE:
7993
80.0k
            case XML_DOCUMENT_FRAG_NODE:
7994
80.0k
            case XML_HTML_DOCUMENT_NODE:
7995
80.0k
                return(NULL);
7996
94.4k
      case XML_NAMESPACE_DECL: {
7997
94.4k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7998
7999
94.4k
    if ((ns->next != NULL) &&
8000
94.4k
        (ns->next->type != XML_NAMESPACE_DECL))
8001
94.4k
        return((xmlNodePtr) ns->next);
8002
0
                return(NULL);
8003
94.4k
      }
8004
2.48M
  }
8005
2.48M
    }
8006
2.32M
    return(NULL);
8007
4.80M
}
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
4.17M
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8025
4.17M
    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
4.17M
    if (cur == NULL) {
8032
821k
  if (ctxt->context->node == NULL) return(NULL);
8033
821k
  switch (ctxt->context->node->type) {
8034
469k
            case XML_ELEMENT_NODE:
8035
722k
            case XML_TEXT_NODE:
8036
733k
            case XML_CDATA_SECTION_NODE:
8037
733k
            case XML_ENTITY_REF_NODE:
8038
733k
            case XML_ENTITY_NODE:
8039
753k
            case XML_PI_NODE:
8040
773k
            case XML_COMMENT_NODE:
8041
773k
      case XML_DTD_NODE:
8042
773k
      case XML_ELEMENT_DECL:
8043
773k
      case XML_ATTRIBUTE_DECL:
8044
773k
      case XML_ENTITY_DECL:
8045
773k
            case XML_NOTATION_NODE:
8046
773k
      case XML_XINCLUDE_START:
8047
773k
      case XML_XINCLUDE_END:
8048
773k
    if (ctxt->context->node->parent == NULL)
8049
0
        return((xmlNodePtr) ctxt->context->doc);
8050
773k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8051
773k
        ((ctxt->context->node->parent->name[0] == ' ') ||
8052
578k
         (xmlStrEqual(ctxt->context->node->parent->name,
8053
578k
         BAD_CAST "fake node libxslt"))))
8054
0
        return(NULL);
8055
773k
    return(ctxt->context->node->parent);
8056
27.7k
            case XML_ATTRIBUTE_NODE: {
8057
27.7k
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8058
8059
27.7k
    return(tmp->parent);
8060
773k
      }
8061
14.6k
            case XML_DOCUMENT_NODE:
8062
14.6k
            case XML_DOCUMENT_TYPE_NODE:
8063
14.6k
            case XML_DOCUMENT_FRAG_NODE:
8064
14.6k
            case XML_HTML_DOCUMENT_NODE:
8065
14.6k
                return(NULL);
8066
5.61k
      case XML_NAMESPACE_DECL: {
8067
5.61k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8068
8069
5.61k
    if ((ns->next != NULL) &&
8070
5.61k
        (ns->next->type != XML_NAMESPACE_DECL))
8071
5.61k
        return((xmlNodePtr) ns->next);
8072
    /* Bad, how did that namespace end up here ? */
8073
0
                return(NULL);
8074
5.61k
      }
8075
821k
  }
8076
0
  return(NULL);
8077
821k
    }
8078
3.35M
    if (cur == ctxt->context->doc->children)
8079
8.60k
  return((xmlNodePtr) ctxt->context->doc);
8080
3.34M
    if (cur == (xmlNodePtr) ctxt->context->doc)
8081
1.09M
  return(NULL);
8082
2.25M
    switch (cur->type) {
8083
1.86M
  case XML_ELEMENT_NODE:
8084
2.16M
  case XML_TEXT_NODE:
8085
2.17M
  case XML_CDATA_SECTION_NODE:
8086
2.17M
  case XML_ENTITY_REF_NODE:
8087
2.17M
  case XML_ENTITY_NODE:
8088
2.18M
  case XML_PI_NODE:
8089
2.21M
  case XML_COMMENT_NODE:
8090
2.21M
  case XML_NOTATION_NODE:
8091
2.21M
  case XML_DTD_NODE:
8092
2.21M
        case XML_ELEMENT_DECL:
8093
2.21M
        case XML_ATTRIBUTE_DECL:
8094
2.21M
        case XML_ENTITY_DECL:
8095
2.21M
  case XML_XINCLUDE_START:
8096
2.21M
  case XML_XINCLUDE_END:
8097
2.21M
      if (cur->parent == NULL)
8098
0
    return(NULL);
8099
2.21M
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8100
2.21M
    ((cur->parent->name[0] == ' ') ||
8101
1.28M
     (xmlStrEqual(cur->parent->name,
8102
1.28M
            BAD_CAST "fake node libxslt"))))
8103
0
    return(NULL);
8104
2.21M
      return(cur->parent);
8105
15.2k
  case XML_ATTRIBUTE_NODE: {
8106
15.2k
      xmlAttrPtr att = (xmlAttrPtr) cur;
8107
8108
15.2k
      return(att->parent);
8109
2.21M
  }
8110
10.5k
  case XML_NAMESPACE_DECL: {
8111
10.5k
      xmlNsPtr ns = (xmlNsPtr) cur;
8112
8113
10.5k
      if ((ns->next != NULL) &&
8114
10.5k
          (ns->next->type != XML_NAMESPACE_DECL))
8115
10.5k
          return((xmlNodePtr) ns->next);
8116
      /* Bad, how did that namespace end up here ? */
8117
0
            return(NULL);
8118
10.5k
  }
8119
11.6k
  case XML_DOCUMENT_NODE:
8120
11.6k
  case XML_DOCUMENT_TYPE_NODE:
8121
11.6k
  case XML_DOCUMENT_FRAG_NODE:
8122
11.6k
  case XML_HTML_DOCUMENT_NODE:
8123
11.6k
      return(NULL);
8124
2.25M
    }
8125
0
    return(NULL);
8126
2.25M
}
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
2.69M
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8143
2.69M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8144
2.69M
    if (cur == NULL)
8145
581k
        return(ctxt->context->node);
8146
2.11M
    return(xmlXPathNextAncestor(ctxt, cur));
8147
2.69M
}
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
391k
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8162
391k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8163
391k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8164
391k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8165
19.2k
  return(NULL);
8166
372k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8167
0
        return(NULL);
8168
372k
    if (cur == NULL)
8169
75.6k
        return(ctxt->context->node->next);
8170
296k
    return(cur->next);
8171
372k
}
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
835k
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8187
835k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8188
835k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8189
835k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8190
15.8k
  return(NULL);
8191
819k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8192
0
        return(NULL);
8193
819k
    if (cur == NULL)
8194
190k
        return(ctxt->context->node->prev);
8195
629k
    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
629k
    return(cur->prev);
8201
629k
}
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
4.64M
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8218
4.64M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8219
4.64M
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8220
4.64M
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8221
847k
        return(cur->children);
8222
8223
3.79M
    if (cur == NULL) {
8224
259k
        cur = ctxt->context->node;
8225
259k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8226
11.4k
            cur = cur->parent;
8227
247k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8228
10.8k
            xmlNsPtr ns = (xmlNsPtr) cur;
8229
8230
10.8k
            if ((ns->next == NULL) ||
8231
10.8k
                (ns->next->type == XML_NAMESPACE_DECL))
8232
0
                return (NULL);
8233
10.8k
            cur = (xmlNodePtr) ns->next;
8234
10.8k
        }
8235
259k
    }
8236
3.79M
    if (cur == NULL) return(NULL) ; /* ERROR */
8237
3.79M
    if (cur->next != NULL) return(cur->next) ;
8238
1.49M
    do {
8239
1.49M
        cur = cur->parent;
8240
1.49M
        if (cur == NULL) break;
8241
1.48M
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8242
1.24M
        if (cur->next != NULL) return(cur->next);
8243
1.24M
    } while (cur != NULL);
8244
12.3k
    return(cur);
8245
1.25M
}
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
5.36M
{
8344
5.36M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8345
5.36M
    if (cur == NULL) {
8346
263k
        cur = ctxt->context->node;
8347
263k
        if (cur == NULL)
8348
0
            return (NULL);
8349
263k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8350
11.4k
            cur = cur->parent;
8351
251k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8352
6.45k
            xmlNsPtr ns = (xmlNsPtr) cur;
8353
8354
6.45k
            if ((ns->next == NULL) ||
8355
6.45k
                (ns->next->type == XML_NAMESPACE_DECL))
8356
0
                return (NULL);
8357
6.45k
            cur = (xmlNodePtr) ns->next;
8358
6.45k
        }
8359
263k
        ctxt->ancestor = cur->parent;
8360
263k
    }
8361
5.36M
    if (cur->type == XML_NAMESPACE_DECL)
8362
0
        return(NULL);
8363
5.36M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8364
0
  cur = cur->prev;
8365
5.93M
    while (cur->prev == NULL) {
8366
2.42M
        cur = cur->parent;
8367
2.42M
        if (cur == NULL)
8368
212k
            return (NULL);
8369
2.21M
        if (cur == ctxt->context->doc->children)
8370
37.9k
            return (NULL);
8371
2.17M
        if (cur != ctxt->ancestor)
8372
1.60M
            return (cur);
8373
570k
        ctxt->ancestor = cur->parent;
8374
570k
    }
8375
3.50M
    cur = cur->prev;
8376
5.15M
    while (cur->last != NULL)
8377
1.64M
        cur = cur->last;
8378
3.50M
    return (cur);
8379
5.36M
}
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
4.54M
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8397
4.54M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8398
4.54M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8399
3.10M
    if (cur == NULL) {
8400
895k
        if (ctxt->context->tmpNsList != NULL)
8401
70.7k
      xmlFree(ctxt->context->tmpNsList);
8402
895k
  ctxt->context->tmpNsList =
8403
895k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8404
895k
  ctxt->context->tmpNsNr = 0;
8405
895k
  if (ctxt->context->tmpNsList != NULL) {
8406
2.39M
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8407
1.52M
    ctxt->context->tmpNsNr++;
8408
1.52M
      }
8409
875k
  }
8410
895k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8411
895k
    }
8412
2.20M
    if (ctxt->context->tmpNsNr > 0) {
8413
1.41M
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8414
1.41M
    } else {
8415
789k
  if (ctxt->context->tmpNsList != NULL)
8416
773k
      xmlFree(ctxt->context->tmpNsList);
8417
789k
  ctxt->context->tmpNsList = NULL;
8418
789k
  return(NULL);
8419
789k
    }
8420
2.20M
}
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
12.8M
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8434
12.8M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8435
12.8M
    if (ctxt->context->node == NULL)
8436
0
  return(NULL);
8437
12.8M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8438
5.00M
  return(NULL);
8439
7.89M
    if (cur == NULL) {
8440
4.81M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8441
0
      return(NULL);
8442
4.81M
        return((xmlNodePtr)ctxt->context->node->properties);
8443
4.81M
    }
8444
3.08M
    return((xmlNodePtr)cur->next);
8445
7.89M
}
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
11.0M
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8470
11.0M
    if ((ctxt == NULL) || (ctxt->context == NULL))
8471
0
  return;
8472
11.0M
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8473
11.0M
  (xmlNodePtr) ctxt->context->doc));
8474
11.0M
}
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
1.31M
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8495
3.94M
    CHECK_ARITY(0);
8496
3.94M
    if (ctxt->context->contextSize >= 0) {
8497
1.31M
  valuePush(ctxt,
8498
1.31M
      xmlXPathCacheNewFloat(ctxt->context,
8499
1.31M
    (double) ctxt->context->contextSize));
8500
#ifdef DEBUG_EXPR
8501
  xmlGenericError(xmlGenericErrorContext,
8502
    "last() : %d\n", ctxt->context->contextSize);
8503
#endif
8504
1.31M
    } else {
8505
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8506
0
    }
8507
3.94M
}
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
6.25k
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522
15.0k
    CHECK_ARITY(0);
8523
15.0k
    if (ctxt->context->proximityPosition >= 0) {
8524
4.41k
  valuePush(ctxt,
8525
4.41k
        xmlXPathCacheNewFloat(ctxt->context,
8526
4.41k
    (double) ctxt->context->proximityPosition));
8527
#ifdef DEBUG_EXPR
8528
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8529
    ctxt->context->proximityPosition);
8530
#endif
8531
4.41k
    } else {
8532
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8533
0
    }
8534
15.0k
}
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
8.99k
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8546
8.99k
    xmlXPathObjectPtr cur;
8547
8548
22.7k
    CHECK_ARITY(1);
8549
22.7k
    if ((ctxt->value == NULL) ||
8550
6.86k
  ((ctxt->value->type != XPATH_NODESET) &&
8551
6.86k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8552
5.04k
  XP_ERROR(XPATH_INVALID_TYPE);
8553
5.04k
    cur = valuePop(ctxt);
8554
8555
5.04k
    if ((cur == NULL) || (cur->nodesetval == NULL))
8556
1.44k
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8557
3.60k
    else
8558
3.60k
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8559
3.60k
      (double) cur->nodesetval->nodeNr));
8560
5.04k
    xmlXPathReleaseObject(ctxt->context, cur);
8561
5.04k
}
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
301k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8574
301k
    xmlNodeSetPtr ret;
8575
301k
    const xmlChar *cur = ids;
8576
301k
    xmlChar *ID;
8577
301k
    xmlAttrPtr attr;
8578
301k
    xmlNodePtr elem = NULL;
8579
8580
301k
    if (ids == NULL) return(NULL);
8581
8582
301k
    ret = xmlXPathNodeSetCreate(NULL);
8583
301k
    if (ret == NULL)
8584
0
        return(ret);
8585
8586
1.49M
    while (IS_BLANK_CH(*cur)) cur++;
8587
852k
    while (*cur != 0) {
8588
3.91M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8589
3.36M
      cur++;
8590
8591
550k
        ID = xmlStrndup(ids, cur - ids);
8592
550k
  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
550k
      attr = xmlGetID(doc, ID);
8601
550k
      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
550k
      xmlFree(ID);
8613
550k
  }
8614
8615
5.27M
  while (IS_BLANK_CH(*cur)) cur++;
8616
550k
  ids = cur;
8617
550k
    }
8618
301k
    return(ret);
8619
301k
}
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
281k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8641
281k
    xmlChar *tokens;
8642
281k
    xmlNodeSetPtr ret;
8643
281k
    xmlXPathObjectPtr obj;
8644
8645
837k
    CHECK_ARITY(1);
8646
837k
    obj = valuePop(ctxt);
8647
837k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8648
277k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8649
227k
  xmlNodeSetPtr ns;
8650
227k
  int i;
8651
8652
        /* TODO: Check memory error. */
8653
227k
  ret = xmlXPathNodeSetCreate(NULL);
8654
8655
227k
  if (obj->nodesetval != NULL) {
8656
462k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8657
251k
    tokens =
8658
251k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8659
251k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8660
                /* TODO: Check memory error. */
8661
251k
    ret = xmlXPathNodeSetMerge(ret, ns);
8662
251k
    xmlXPathFreeNodeSet(ns);
8663
251k
    if (tokens != NULL)
8664
251k
        xmlFree(tokens);
8665
251k
      }
8666
211k
  }
8667
227k
  xmlXPathReleaseObject(ctxt->context, obj);
8668
227k
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8669
227k
  return;
8670
227k
    }
8671
50.3k
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8672
50.3k
    if (obj == NULL) return;
8673
50.3k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8674
50.3k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8675
50.3k
    xmlXPathReleaseObject(ctxt->context, obj);
8676
50.3k
    return;
8677
50.3k
}
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
144k
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8694
144k
    xmlXPathObjectPtr cur;
8695
8696
144k
    if (ctxt == NULL) return;
8697
8698
144k
    if (nargs == 0) {
8699
23.5k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8700
23.5k
      ctxt->context->node));
8701
23.5k
  nargs = 1;
8702
23.5k
    }
8703
8704
430k
    CHECK_ARITY(1);
8705
430k
    if ((ctxt->value == NULL) ||
8706
143k
  ((ctxt->value->type != XPATH_NODESET) &&
8707
143k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8708
142k
  XP_ERROR(XPATH_INVALID_TYPE);
8709
142k
    cur = valuePop(ctxt);
8710
8711
142k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8712
8.86k
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713
133k
    } else {
8714
133k
  int i = 0; /* Should be first in document order !!!!! */
8715
133k
  switch (cur->nodesetval->nodeTab[i]->type) {
8716
15.3k
  case XML_ELEMENT_NODE:
8717
16.8k
  case XML_ATTRIBUTE_NODE:
8718
25.0k
  case XML_PI_NODE:
8719
25.0k
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8720
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8721
25.0k
      else
8722
25.0k
    valuePush(ctxt,
8723
25.0k
          xmlXPathCacheNewString(ctxt->context,
8724
25.0k
      cur->nodesetval->nodeTab[i]->name));
8725
25.0k
      break;
8726
6.12k
  case XML_NAMESPACE_DECL:
8727
6.12k
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8728
6.12k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8729
6.12k
      break;
8730
102k
  default:
8731
102k
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8732
133k
  }
8733
133k
    }
8734
142k
    xmlXPathReleaseObject(ctxt->context, cur);
8735
142k
}
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
57.7k
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8753
57.7k
    xmlXPathObjectPtr cur;
8754
8755
57.7k
    if (ctxt == NULL) return;
8756
8757
57.7k
    if (nargs == 0) {
8758
4.68k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8759
4.68k
      ctxt->context->node));
8760
4.68k
  nargs = 1;
8761
4.68k
    }
8762
170k
    CHECK_ARITY(1);
8763
170k
    if ((ctxt->value == NULL) ||
8764
56.2k
  ((ctxt->value->type != XPATH_NODESET) &&
8765
56.2k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8766
54.9k
  XP_ERROR(XPATH_INVALID_TYPE);
8767
54.9k
    cur = valuePop(ctxt);
8768
8769
54.9k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8770
22.4k
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8771
32.5k
    } else {
8772
32.5k
  int i = 0; /* Should be first in document order !!!!! */
8773
32.5k
  switch (cur->nodesetval->nodeTab[i]->type) {
8774
21.1k
  case XML_ELEMENT_NODE:
8775
21.5k
  case XML_ATTRIBUTE_NODE:
8776
21.5k
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8777
11.4k
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8778
10.0k
      else
8779
10.0k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8780
10.0k
        cur->nodesetval->nodeTab[i]->ns->href));
8781
21.5k
      break;
8782
10.9k
  default:
8783
10.9k
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8784
32.5k
  }
8785
32.5k
    }
8786
54.9k
    xmlXPathReleaseObject(ctxt->context, cur);
8787
54.9k
}
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
339k
{
8814
339k
    xmlXPathObjectPtr cur;
8815
8816
339k
    if (nargs == 0) {
8817
278k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8818
278k
      ctxt->context->node));
8819
278k
        nargs = 1;
8820
278k
    }
8821
8822
1.01M
    CHECK_ARITY(1);
8823
1.01M
    if ((ctxt->value == NULL) ||
8824
337k
        ((ctxt->value->type != XPATH_NODESET) &&
8825
337k
         (ctxt->value->type != XPATH_XSLT_TREE)))
8826
335k
        XP_ERROR(XPATH_INVALID_TYPE);
8827
335k
    cur = valuePop(ctxt);
8828
8829
335k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8830
35.7k
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8831
300k
    } else {
8832
300k
        int i = 0;              /* Should be first in document order !!!!! */
8833
8834
300k
        switch (cur->nodesetval->nodeTab[i]->type) {
8835
198k
            case XML_ELEMENT_NODE:
8836
199k
            case XML_ATTRIBUTE_NODE:
8837
199k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8838
0
        valuePush(ctxt,
8839
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8840
199k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8841
199k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8842
40.9k
        valuePush(ctxt,
8843
40.9k
            xmlXPathCacheNewString(ctxt->context,
8844
40.9k
          cur->nodesetval->nodeTab[i]->name));
8845
158k
    } else {
8846
158k
        xmlChar *fullname;
8847
8848
158k
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8849
158k
             cur->nodesetval->nodeTab[i]->ns->prefix,
8850
158k
             NULL, 0);
8851
158k
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8852
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8853
158k
        if (fullname == NULL) {
8854
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8855
0
        }
8856
158k
        valuePush(ctxt, xmlXPathCacheWrapString(
8857
158k
      ctxt->context, fullname));
8858
158k
                }
8859
199k
                break;
8860
199k
            default:
8861
101k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8862
101k
        cur->nodesetval->nodeTab[i]));
8863
101k
                xmlXPathLocalNameFunction(ctxt, 1);
8864
300k
        }
8865
300k
    }
8866
335k
    xmlXPathReleaseObject(ctxt->context, cur);
8867
335k
}
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
7.05M
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8908
7.05M
    xmlXPathObjectPtr cur;
8909
8910
7.05M
    if (ctxt == NULL) return;
8911
7.05M
    if (nargs == 0) {
8912
2.93k
    valuePush(ctxt,
8913
2.93k
  xmlXPathCacheWrapString(ctxt->context,
8914
2.93k
      xmlXPathCastNodeToString(ctxt->context->node)));
8915
2.93k
  return;
8916
2.93k
    }
8917
8918
28.2M
    CHECK_ARITY(1);
8919
28.2M
    cur = valuePop(ctxt);
8920
28.2M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8921
7.05M
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8922
7.05M
}
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
8.84k
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8938
8.84k
    xmlXPathObjectPtr cur;
8939
8940
8.84k
    if (nargs == 0) {
8941
1.37k
        if ((ctxt == NULL) || (ctxt->context == NULL))
8942
0
      return;
8943
1.37k
  if (ctxt->context->node == NULL) {
8944
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8945
1.37k
  } else {
8946
1.37k
      xmlChar *content;
8947
8948
1.37k
      content = xmlXPathCastNodeToString(ctxt->context->node);
8949
1.37k
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8950
1.37k
    xmlUTF8Strlen(content)));
8951
1.37k
      xmlFree(content);
8952
1.37k
  }
8953
1.37k
  return;
8954
1.37k
    }
8955
29.7k
    CHECK_ARITY(1);
8956
29.7k
    CAST_TO_STRING;
8957
29.7k
    CHECK_TYPE(XPATH_STRING);
8958
7.39k
    cur = valuePop(ctxt);
8959
7.39k
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8960
7.39k
  xmlUTF8Strlen(cur->stringval)));
8961
7.39k
    xmlXPathReleaseObject(ctxt->context, cur);
8962
7.39k
}
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
13.4k
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975
13.4k
    xmlXPathObjectPtr cur, newobj;
8976
13.4k
    xmlChar *tmp;
8977
8978
13.4k
    if (ctxt == NULL) return;
8979
13.4k
    if (nargs < 2) {
8980
930
  CHECK_ARITY(2);
8981
930
    }
8982
8983
12.5k
    CAST_TO_STRING;
8984
12.5k
    cur = valuePop(ctxt);
8985
12.5k
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8986
0
  xmlXPathReleaseObject(ctxt->context, cur);
8987
0
  return;
8988
0
    }
8989
12.5k
    nargs--;
8990
8991
75.7k
    while (nargs > 0) {
8992
63.2k
  CAST_TO_STRING;
8993
63.2k
  newobj = valuePop(ctxt);
8994
63.2k
  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
63.2k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
9000
63.2k
  newobj->stringval = cur->stringval;
9001
63.2k
  cur->stringval = tmp;
9002
63.2k
  xmlXPathReleaseObject(ctxt->context, newobj);
9003
63.2k
  nargs--;
9004
63.2k
    }
9005
12.5k
    valuePush(ctxt, cur);
9006
12.5k
}
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
12.7k
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020
12.7k
    xmlXPathObjectPtr hay, needle;
9021
9022
36.5k
    CHECK_ARITY(2);
9023
36.5k
    CAST_TO_STRING;
9024
36.5k
    CHECK_TYPE(XPATH_STRING);
9025
11.9k
    needle = valuePop(ctxt);
9026
11.9k
    CAST_TO_STRING;
9027
11.9k
    hay = valuePop(ctxt);
9028
9029
11.9k
    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
11.9k
    if (xmlStrstr(hay->stringval, needle->stringval))
9035
6.31k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9036
5.60k
    else
9037
5.60k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038
11.9k
    xmlXPathReleaseObject(ctxt->context, hay);
9039
11.9k
    xmlXPathReleaseObject(ctxt->context, needle);
9040
11.9k
}
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
30.2k
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9054
30.2k
    xmlXPathObjectPtr hay, needle;
9055
30.2k
    int n;
9056
9057
86.8k
    CHECK_ARITY(2);
9058
86.8k
    CAST_TO_STRING;
9059
86.8k
    CHECK_TYPE(XPATH_STRING);
9060
28.3k
    needle = valuePop(ctxt);
9061
28.3k
    CAST_TO_STRING;
9062
28.3k
    hay = valuePop(ctxt);
9063
9064
28.3k
    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
28.3k
    n = xmlStrlen(needle->stringval);
9070
28.3k
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9071
26.9k
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9072
1.34k
    else
9073
1.34k
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9074
28.3k
    xmlXPathReleaseObject(ctxt->context, hay);
9075
28.3k
    xmlXPathReleaseObject(ctxt->context, needle);
9076
28.3k
}
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
169k
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9108
169k
    xmlXPathObjectPtr str, start, len;
9109
169k
    double le=0, in;
9110
169k
    int i = 1, j = INT_MAX;
9111
9112
169k
    if (nargs < 2) {
9113
1.81k
  CHECK_ARITY(2);
9114
1.81k
    }
9115
167k
    if (nargs > 3) {
9116
1.67k
  CHECK_ARITY(3);
9117
1.67k
    }
9118
    /*
9119
     * take care of possible last (position) argument
9120
    */
9121
165k
    if (nargs == 3) {
9122
80.0k
  CAST_TO_NUMBER;
9123
80.0k
  CHECK_TYPE(XPATH_NUMBER);
9124
80.0k
  len = valuePop(ctxt);
9125
80.0k
  le = len->floatval;
9126
80.0k
  xmlXPathReleaseObject(ctxt->context, len);
9127
80.0k
    }
9128
9129
165k
    CAST_TO_NUMBER;
9130
165k
    CHECK_TYPE(XPATH_NUMBER);
9131
165k
    start = valuePop(ctxt);
9132
165k
    in = start->floatval;
9133
165k
    xmlXPathReleaseObject(ctxt->context, start);
9134
165k
    CAST_TO_STRING;
9135
165k
    CHECK_TYPE(XPATH_STRING);
9136
165k
    str = valuePop(ctxt);
9137
9138
165k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9139
40.3k
        i = INT_MAX;
9140
125k
    } else if (in >= 1.0) {
9141
114k
        i = (int)in;
9142
114k
        if (in - floor(in) >= 0.5)
9143
14.7k
            i += 1;
9144
114k
    }
9145
9146
165k
    if (nargs == 3) {
9147
80.0k
        double rin, rle, end;
9148
9149
80.0k
        rin = floor(in);
9150
80.0k
        if (in - rin >= 0.5)
9151
7.76k
            rin += 1.0;
9152
9153
80.0k
        rle = floor(le);
9154
80.0k
        if (le - rle >= 0.5)
9155
6.49k
            rle += 1.0;
9156
9157
80.0k
        end = rin + rle;
9158
80.0k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9159
35.5k
            j = 1;
9160
44.4k
        } else if (end < INT_MAX) {
9161
39.2k
            j = (int)end;
9162
39.2k
        }
9163
80.0k
    }
9164
9165
165k
    if (i < j) {
9166
96.9k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9167
96.9k
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9168
96.9k
  xmlFree(ret);
9169
96.9k
    } else {
9170
68.5k
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9171
68.5k
    }
9172
9173
165k
    xmlXPathReleaseObject(ctxt->context, str);
9174
165k
}
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
5.78k
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9191
5.78k
  xmlXPathObjectPtr str;
9192
5.78k
  xmlXPathObjectPtr find;
9193
5.78k
  xmlBufPtr target;
9194
5.78k
  const xmlChar *point;
9195
5.78k
  int offset;
9196
9197
16.8k
  CHECK_ARITY(2);
9198
16.8k
  CAST_TO_STRING;
9199
16.8k
  find = valuePop(ctxt);
9200
16.8k
  CAST_TO_STRING;
9201
16.8k
  str = valuePop(ctxt);
9202
9203
16.8k
  target = xmlBufCreate();
9204
16.8k
  if (target) {
9205
5.55k
    point = xmlStrstr(str->stringval, find->stringval);
9206
5.55k
    if (point) {
9207
2.27k
      offset = point - str->stringval;
9208
2.27k
      xmlBufAdd(target, str->stringval, offset);
9209
2.27k
    }
9210
5.55k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211
5.55k
  xmlBufContent(target)));
9212
5.55k
    xmlBufFree(target);
9213
5.55k
  }
9214
16.8k
  xmlXPathReleaseObject(ctxt->context, str);
9215
16.8k
  xmlXPathReleaseObject(ctxt->context, find);
9216
16.8k
}
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
12.9k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234
12.9k
  xmlXPathObjectPtr str;
9235
12.9k
  xmlXPathObjectPtr find;
9236
12.9k
  xmlBufPtr target;
9237
12.9k
  const xmlChar *point;
9238
12.9k
  int offset;
9239
9240
38.7k
  CHECK_ARITY(2);
9241
38.7k
  CAST_TO_STRING;
9242
38.7k
  find = valuePop(ctxt);
9243
38.7k
  CAST_TO_STRING;
9244
38.7k
  str = valuePop(ctxt);
9245
9246
38.7k
  target = xmlBufCreate();
9247
38.7k
  if (target) {
9248
12.8k
    point = xmlStrstr(str->stringval, find->stringval);
9249
12.8k
    if (point) {
9250
2.84k
      offset = point - str->stringval + xmlStrlen(find->stringval);
9251
2.84k
      xmlBufAdd(target, &str->stringval[offset],
9252
2.84k
       xmlStrlen(str->stringval) - offset);
9253
2.84k
    }
9254
12.8k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9255
12.8k
  xmlBufContent(target)));
9256
12.8k
    xmlBufFree(target);
9257
12.8k
  }
9258
38.7k
  xmlXPathReleaseObject(ctxt->context, str);
9259
38.7k
  xmlXPathReleaseObject(ctxt->context, find);
9260
38.7k
}
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
26.6k
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9278
26.6k
    xmlChar *source, *target;
9279
26.6k
    int blank;
9280
9281
26.6k
    if (ctxt == NULL) return;
9282
26.6k
    if (nargs == 0) {
9283
        /* Use current context node */
9284
7.98k
        valuePush(ctxt,
9285
7.98k
            xmlXPathCacheWrapString(ctxt->context,
9286
7.98k
                xmlXPathCastNodeToString(ctxt->context->node)));
9287
7.98k
        nargs = 1;
9288
7.98k
    }
9289
9290
74.8k
    CHECK_ARITY(1);
9291
74.8k
    CAST_TO_STRING;
9292
74.8k
    CHECK_TYPE(XPATH_STRING);
9293
24.0k
    source = ctxt->value->stringval;
9294
24.0k
    if (source == NULL)
9295
0
        return;
9296
24.0k
    target = source;
9297
9298
    /* Skip leading whitespaces */
9299
24.0k
    while (IS_BLANK_CH(*source))
9300
125k
        source++;
9301
9302
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9303
24.0k
    blank = 0;
9304
1.10M
    while (*source) {
9305
1.08M
        if (IS_BLANK_CH(*source)) {
9306
332k
      blank = 1;
9307
751k
        } else {
9308
751k
            if (blank) {
9309
19.6k
                *target++ = 0x20;
9310
19.6k
                blank = 0;
9311
19.6k
            }
9312
751k
            *target++ = *source;
9313
751k
        }
9314
1.08M
        source++;
9315
1.08M
    }
9316
24.0k
    *target = 0;
9317
24.0k
}
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
36.6k
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9342
36.6k
    xmlXPathObjectPtr str;
9343
36.6k
    xmlXPathObjectPtr from;
9344
36.6k
    xmlXPathObjectPtr to;
9345
36.6k
    xmlBufPtr target;
9346
36.6k
    int offset, max;
9347
36.6k
    xmlChar ch;
9348
36.6k
    const xmlChar *point;
9349
36.6k
    xmlChar *cptr;
9350
9351
107k
    CHECK_ARITY(3);
9352
9353
107k
    CAST_TO_STRING;
9354
107k
    to = valuePop(ctxt);
9355
107k
    CAST_TO_STRING;
9356
107k
    from = valuePop(ctxt);
9357
107k
    CAST_TO_STRING;
9358
107k
    str = valuePop(ctxt);
9359
9360
107k
    target = xmlBufCreate();
9361
107k
    if (target) {
9362
35.3k
  max = xmlUTF8Strlen(to->stringval);
9363
2.16M
  for (cptr = str->stringval; (ch=*cptr); ) {
9364
2.13M
      offset = xmlUTF8Strloc(from->stringval, cptr);
9365
2.13M
      if (offset >= 0) {
9366
489k
    if (offset < max) {
9367
407k
        point = xmlUTF8Strpos(to->stringval, offset);
9368
407k
        if (point)
9369
394k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9370
407k
    }
9371
489k
      } else
9372
1.64M
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9373
9374
      /* Step to next character in input */
9375
2.13M
      cptr++;
9376
2.13M
      if ( ch & 0x80 ) {
9377
    /* if not simple ascii, verify proper format */
9378
22.1k
    if ( (ch & 0xc0) != 0xc0 ) {
9379
1.39k
        xmlGenericError(xmlGenericErrorContext,
9380
1.39k
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381
                    /* not asserting an XPath error is probably better */
9382
1.39k
        break;
9383
1.39k
    }
9384
    /* then skip over remaining bytes for this char */
9385
52.8k
    while ( (ch <<= 1) & 0x80 )
9386
34.9k
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9387
2.88k
      xmlGenericError(xmlGenericErrorContext,
9388
2.88k
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9389
                        /* not asserting an XPath error is probably better */
9390
2.88k
      break;
9391
2.88k
        }
9392
20.7k
    if (ch & 0x80) /* must have had error encountered */
9393
2.88k
        break;
9394
20.7k
      }
9395
2.13M
  }
9396
35.3k
    }
9397
107k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9398
107k
  xmlBufContent(target)));
9399
107k
    xmlBufFree(target);
9400
107k
    xmlXPathReleaseObject(ctxt->context, str);
9401
107k
    xmlXPathReleaseObject(ctxt->context, from);
9402
107k
    xmlXPathReleaseObject(ctxt->context, to);
9403
107k
}
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.16M
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420
1.16M
    xmlXPathObjectPtr cur;
9421
9422
3.48M
    CHECK_ARITY(1);
9423
3.48M
    cur = valuePop(ctxt);
9424
3.48M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9425
1.16M
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9426
1.16M
    valuePush(ctxt, cur);
9427
1.16M
}
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
7.57k
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9441
22.0k
    CHECK_ARITY(1);
9442
22.0k
    CAST_TO_BOOLEAN;
9443
22.0k
    CHECK_TYPE(XPATH_BOOLEAN);
9444
7.23k
    ctxt->value->boolval = ! ctxt->value->boolval;
9445
7.23k
}
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
23.3k
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9457
65.4k
    CHECK_ARITY(0);
9458
65.4k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9459
65.4k
}
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
37.0k
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9471
110k
    CHECK_ARITY(0);
9472
110k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9473
110k
}
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
22.7k
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498
22.7k
    xmlXPathObjectPtr val = NULL;
9499
22.7k
    const xmlChar *theLang = NULL;
9500
22.7k
    const xmlChar *lang;
9501
22.7k
    int ret = 0;
9502
22.7k
    int i;
9503
9504
62.6k
    CHECK_ARITY(1);
9505
62.6k
    CAST_TO_STRING;
9506
62.6k
    CHECK_TYPE(XPATH_STRING);
9507
19.9k
    val = valuePop(ctxt);
9508
19.9k
    lang = val->stringval;
9509
19.9k
    theLang = xmlNodeGetLang(ctxt->context->node);
9510
19.9k
    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
19.9k
not_equal:
9518
19.9k
    if (theLang != NULL)
9519
0
  xmlFree((void *)theLang);
9520
9521
19.9k
    xmlXPathReleaseObject(ctxt->context, val);
9522
19.9k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9523
19.9k
}
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
16.7M
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
16.7M
    xmlXPathObjectPtr cur;
9536
16.7M
    double res;
9537
9538
16.7M
    if (ctxt == NULL) return;
9539
16.7M
    if (nargs == 0) {
9540
9.20k
  if (ctxt->context->node == NULL) {
9541
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9542
9.20k
  } else {
9543
9.20k
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9544
9545
9.20k
      res = xmlXPathStringEvalNumber(content);
9546
9.20k
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9547
9.20k
      xmlFree(content);
9548
9.20k
  }
9549
9.20k
  return;
9550
9.20k
    }
9551
9552
66.8M
    CHECK_ARITY(1);
9553
66.8M
    cur = valuePop(ctxt);
9554
66.8M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9555
66.8M
}
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
24.6k
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9569
24.6k
    xmlXPathObjectPtr cur;
9570
24.6k
    int i;
9571
24.6k
    double res = 0.0;
9572
9573
71.5k
    CHECK_ARITY(1);
9574
71.5k
    if ((ctxt->value == NULL) ||
9575
23.4k
  ((ctxt->value->type != XPATH_NODESET) &&
9576
23.4k
   (ctxt->value->type != XPATH_XSLT_TREE)))
9577
20.3k
  XP_ERROR(XPATH_INVALID_TYPE);
9578
20.3k
    cur = valuePop(ctxt);
9579
9580
20.3k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9581
72.2k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9582
66.0k
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9583
66.0k
  }
9584
6.17k
    }
9585
20.3k
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9586
20.3k
    xmlXPathReleaseObject(ctxt->context, cur);
9587
20.3k
}
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
5.38k
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9601
15.8k
    CHECK_ARITY(1);
9602
15.8k
    CAST_TO_NUMBER;
9603
15.8k
    CHECK_TYPE(XPATH_NUMBER);
9604
9605
5.21k
    ctxt->value->floatval = floor(ctxt->value->floatval);
9606
5.21k
}
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
8.62k
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9620
25.2k
    CHECK_ARITY(1);
9621
25.2k
    CAST_TO_NUMBER;
9622
25.2k
    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
8.33k
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9629
8.33k
#endif
9630
8.33k
}
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
7.43k
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9645
7.43k
    double f;
9646
9647
21.1k
    CHECK_ARITY(1);
9648
21.1k
    CAST_TO_NUMBER;
9649
21.1k
    CHECK_TYPE(XPATH_NUMBER);
9650
9651
6.83k
    f = ctxt->value->floatval;
9652
9653
6.83k
    if ((f >= -0.5) && (f < 0.5)) {
9654
        /* Handles negative zero. */
9655
2.08k
        ctxt->value->floatval *= 0.0;
9656
2.08k
    }
9657
4.75k
    else {
9658
4.75k
        double rounded = floor(f);
9659
4.75k
        if (f - rounded >= 0.5)
9660
1.09k
            rounded += 1.0;
9661
4.75k
        ctxt->value->floatval = rounded;
9662
4.75k
    }
9663
6.83k
}
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
124M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9696
124M
    unsigned char c;
9697
124M
    unsigned int val;
9698
124M
    const xmlChar *cur;
9699
9700
124M
    if (ctxt == NULL)
9701
0
  return(0);
9702
124M
    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
124M
    c = *cur;
9716
124M
    if (c & 0x80) {
9717
7.49M
  if ((cur[1] & 0xc0) != 0x80)
9718
556k
      goto encoding_error;
9719
6.93M
  if ((c & 0xe0) == 0xe0) {
9720
9721
318k
      if ((cur[2] & 0xc0) != 0x80)
9722
39.2k
    goto encoding_error;
9723
279k
      if ((c & 0xf0) == 0xf0) {
9724
148k
    if (((c & 0xf8) != 0xf0) ||
9725
148k
        ((cur[3] & 0xc0) != 0x80))
9726
43.6k
        goto encoding_error;
9727
    /* 4-byte code */
9728
104k
    *len = 4;
9729
104k
    val = (cur[0] & 0x7) << 18;
9730
104k
    val |= (cur[1] & 0x3f) << 12;
9731
104k
    val |= (cur[2] & 0x3f) << 6;
9732
104k
    val |= cur[3] & 0x3f;
9733
130k
      } else {
9734
        /* 3-byte code */
9735
130k
    *len = 3;
9736
130k
    val = (cur[0] & 0xf) << 12;
9737
130k
    val |= (cur[1] & 0x3f) << 6;
9738
130k
    val |= cur[2] & 0x3f;
9739
130k
      }
9740
6.62M
  } else {
9741
    /* 2-byte code */
9742
6.62M
      *len = 2;
9743
6.62M
      val = (cur[0] & 0x1f) << 6;
9744
6.62M
      val |= cur[1] & 0x3f;
9745
6.62M
  }
9746
6.85M
  if (!IS_CHAR(val)) {
9747
53.5k
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9748
0
  }
9749
6.80M
  return(val);
9750
116M
    } else {
9751
  /* 1-byte code */
9752
116M
  *len = 1;
9753
116M
  return(*cur);
9754
116M
    }
9755
639k
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
639k
    *len = 0;
9764
639k
    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
12.3M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9783
12.3M
    const xmlChar *in;
9784
12.3M
    xmlChar *ret;
9785
12.3M
    int count = 0;
9786
9787
12.3M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9788
    /*
9789
     * Accelerator for simple ASCII names
9790
     */
9791
12.3M
    in = ctxt->cur;
9792
12.3M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9793
12.3M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9794
12.3M
  (*in == '_')) {
9795
10.1M
  in++;
9796
72.3M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9797
72.3M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9798
72.3M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9799
72.3M
         (*in == '_') || (*in == '.') ||
9800
72.3M
         (*in == '-'))
9801
62.1M
      in++;
9802
10.1M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9803
10.1M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9804
10.1M
            (*in == '@') || (*in == '*')) {
9805
4.58M
      count = in - ctxt->cur;
9806
4.58M
      if (count == 0)
9807
0
    return(NULL);
9808
4.58M
      ret = xmlStrndup(ctxt->cur, count);
9809
4.58M
      ctxt->cur = in;
9810
4.58M
      return(ret);
9811
4.58M
  }
9812
10.1M
    }
9813
7.79M
    return(xmlXPathParseNameComplex(ctxt, 0));
9814
12.3M
}
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
1.47M
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9836
1.47M
    xmlChar *ret = NULL;
9837
9838
1.47M
    *prefix = NULL;
9839
1.47M
    ret = xmlXPathParseNCName(ctxt);
9840
1.47M
    if (ret && CUR == ':') {
9841
559k
        *prefix = ret;
9842
559k
  NEXT;
9843
559k
  ret = xmlXPathParseNCName(ctxt);
9844
559k
    }
9845
1.47M
    return(ret);
9846
1.47M
}
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
100k
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9864
100k
    const xmlChar *in;
9865
100k
    xmlChar *ret;
9866
100k
    size_t count = 0;
9867
9868
100k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9869
    /*
9870
     * Accelerator for simple ASCII names
9871
     */
9872
100k
    in = ctxt->cur;
9873
100k
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9874
100k
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9875
100k
  (*in == '_') || (*in == ':')) {
9876
39.6k
  in++;
9877
1.13M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9878
1.13M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9879
1.13M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9880
1.13M
         (*in == '_') || (*in == '-') ||
9881
1.13M
         (*in == ':') || (*in == '.'))
9882
1.10M
      in++;
9883
39.6k
  if ((*in > 0) && (*in < 0x80)) {
9884
32.4k
      count = in - ctxt->cur;
9885
32.4k
            if (count > XML_MAX_NAME_LENGTH) {
9886
5
                ctxt->cur = in;
9887
5
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9888
0
            }
9889
32.3k
      ret = xmlStrndup(ctxt->cur, count);
9890
32.3k
      ctxt->cur = in;
9891
32.3k
      return(ret);
9892
32.4k
  }
9893
39.6k
    }
9894
68.4k
    return(xmlXPathParseNameComplex(ctxt, 1));
9895
100k
}
9896
9897
static xmlChar *
9898
7.86M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9899
7.86M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9900
7.86M
    int len = 0, l;
9901
7.86M
    int c;
9902
9903
    /*
9904
     * Handler for more complex cases
9905
     */
9906
7.86M
    c = CUR_CHAR(l);
9907
7.86M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9908
7.86M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9909
7.86M
        (c == '*') || /* accelerators */
9910
7.86M
  (!IS_LETTER(c) && (c != '_') &&
9911
6.47M
         ((!qualified) || (c != ':')))) {
9912
2.07M
  return(NULL);
9913
2.07M
    }
9914
9915
41.9M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9916
41.9M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9917
41.8M
            (c == '.') || (c == '-') ||
9918
41.8M
      (c == '_') || ((qualified) && (c == ':')) ||
9919
41.8M
      (IS_COMBINING(c)) ||
9920
41.8M
      (IS_EXTENDER(c)))) {
9921
36.2M
  COPY_BUF(l,buf,len,c);
9922
36.2M
  NEXTL(l);
9923
36.2M
  c = CUR_CHAR(l);
9924
36.2M
  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
70.2k
      xmlChar *buffer;
9930
70.2k
      int max = len * 2;
9931
9932
70.2k
            if (len > XML_MAX_NAME_LENGTH) {
9933
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9934
0
            }
9935
70.2k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9936
70.2k
      if (buffer == NULL) {
9937
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9938
0
      }
9939
70.2k
      memcpy(buffer, buf, len);
9940
13.1M
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9941
13.1M
       (c == '.') || (c == '-') ||
9942
13.1M
       (c == '_') || ((qualified) && (c == ':')) ||
9943
13.1M
       (IS_COMBINING(c)) ||
9944
13.1M
       (IS_EXTENDER(c))) {
9945
13.0M
    if (len + 10 > max) {
9946
40.3k
                    xmlChar *tmp;
9947
40.3k
                    if (max > XML_MAX_NAME_LENGTH) {
9948
18
                        xmlFree(buffer);
9949
18
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9950
0
                    }
9951
40.3k
        max *= 2;
9952
40.3k
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9953
40.3k
        if (tmp == NULL) {
9954
0
                        xmlFree(buffer);
9955
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9956
0
        }
9957
40.3k
                    buffer = tmp;
9958
40.3k
    }
9959
13.0M
    COPY_BUF(l,buffer,len,c);
9960
13.0M
    NEXTL(l);
9961
13.0M
    c = CUR_CHAR(l);
9962
13.0M
      }
9963
70.2k
      buffer[len] = 0;
9964
70.2k
      return(buffer);
9965
70.2k
  }
9966
36.2M
    }
9967
5.71M
    if (len == 0)
9968
0
  return(NULL);
9969
5.71M
    return(xmlStrndup(buf, len));
9970
5.71M
}
9971
9972
1.54M
#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
33.1M
xmlXPathStringEvalNumber(const xmlChar *str) {
9992
33.1M
    const xmlChar *cur = str;
9993
33.1M
    double ret;
9994
33.1M
    int ok = 0;
9995
33.1M
    int isneg = 0;
9996
33.1M
    int exponent = 0;
9997
33.1M
    int is_exponent_negative = 0;
9998
33.1M
#ifdef __GNUC__
9999
33.1M
    unsigned long tmp = 0;
10000
33.1M
    double temp;
10001
33.1M
#endif
10002
33.1M
    if (cur == NULL) return(0);
10003
66.6M
    while (IS_BLANK_CH(*cur)) cur++;
10004
33.1M
    if (*cur == '-') {
10005
738k
  isneg = 1;
10006
738k
  cur++;
10007
738k
    }
10008
33.1M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
10009
29.1M
        return(xmlXPathNAN);
10010
29.1M
    }
10011
10012
3.97M
#ifdef __GNUC__
10013
    /*
10014
     * tmp/temp is a workaround against a gcc compiler bug
10015
     * http://veillard.com/gcc.bug
10016
     */
10017
3.97M
    ret = 0;
10018
14.2M
    while ((*cur >= '0') && (*cur <= '9')) {
10019
10.2M
  ret = ret * 10;
10020
10.2M
  tmp = (*cur - '0');
10021
10.2M
  ok = 1;
10022
10.2M
  cur++;
10023
10.2M
  temp = (double) tmp;
10024
10.2M
  ret = ret + temp;
10025
10.2M
    }
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
3.97M
    if (*cur == '.') {
10036
1.29M
  int v, frac = 0, max;
10037
1.29M
  double fraction = 0;
10038
10039
1.29M
        cur++;
10040
1.29M
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10041
55.9k
      return(xmlXPathNAN);
10042
55.9k
  }
10043
2.18M
        while (*cur == '0') {
10044
943k
      frac = frac + 1;
10045
943k
      cur++;
10046
943k
        }
10047
1.24M
        max = frac + MAX_FRAC;
10048
2.14M
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10049
904k
      v = (*cur - '0');
10050
904k
      fraction = fraction * 10 + v;
10051
904k
      frac = frac + 1;
10052
904k
      cur++;
10053
904k
  }
10054
1.24M
  fraction /= pow(10.0, frac);
10055
1.24M
  ret = ret + fraction;
10056
1.52M
  while ((*cur >= '0') && (*cur <= '9'))
10057
280k
      cur++;
10058
1.24M
    }
10059
3.91M
    if ((*cur == 'e') || (*cur == 'E')) {
10060
315k
      cur++;
10061
315k
      if (*cur == '-') {
10062
76.2k
  is_exponent_negative = 1;
10063
76.2k
  cur++;
10064
239k
      } else if (*cur == '+') {
10065
16.2k
        cur++;
10066
16.2k
      }
10067
907k
      while ((*cur >= '0') && (*cur <= '9')) {
10068
591k
        if (exponent < 1000000)
10069
498k
    exponent = exponent * 10 + (*cur - '0');
10070
591k
  cur++;
10071
591k
      }
10072
315k
    }
10073
3.91M
    while (IS_BLANK_CH(*cur)) cur++;
10074
3.91M
    if (*cur != 0) return(xmlXPathNAN);
10075
2.88M
    if (isneg) ret = -ret;
10076
2.88M
    if (is_exponent_negative) exponent = -exponent;
10077
2.88M
    ret *= pow(10.0, (double)exponent);
10078
2.88M
    return(ret);
10079
3.91M
}
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
2.12M
{
10095
2.12M
    double ret = 0.0;
10096
2.12M
    int ok = 0;
10097
2.12M
    int exponent = 0;
10098
2.12M
    int is_exponent_negative = 0;
10099
2.12M
    xmlXPathObjectPtr num;
10100
2.12M
#ifdef __GNUC__
10101
2.12M
    unsigned long tmp = 0;
10102
2.12M
    double temp;
10103
2.12M
#endif
10104
10105
2.12M
    CHECK_ERROR;
10106
2.11M
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10107
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10108
0
    }
10109
2.11M
#ifdef __GNUC__
10110
    /*
10111
     * tmp/temp is a workaround against a gcc compiler bug
10112
     * http://veillard.com/gcc.bug
10113
     */
10114
2.11M
    ret = 0;
10115
12.0M
    while ((CUR >= '0') && (CUR <= '9')) {
10116
9.95M
  ret = ret * 10;
10117
9.95M
  tmp = (CUR - '0');
10118
9.95M
        ok = 1;
10119
9.95M
        NEXT;
10120
9.95M
  temp = (double) tmp;
10121
9.95M
  ret = ret + temp;
10122
9.95M
    }
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
2.11M
    if (CUR == '.') {
10132
299k
  int v, frac = 0, max;
10133
299k
  double fraction = 0;
10134
10135
299k
        NEXT;
10136
299k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10137
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10138
0
        }
10139
371k
        while (CUR == '0') {
10140
71.9k
            frac = frac + 1;
10141
71.9k
            NEXT;
10142
71.9k
        }
10143
299k
        max = frac + MAX_FRAC;
10144
699k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10145
399k
      v = (CUR - '0');
10146
399k
      fraction = fraction * 10 + v;
10147
399k
      frac = frac + 1;
10148
399k
            NEXT;
10149
399k
        }
10150
299k
        fraction /= pow(10.0, frac);
10151
299k
        ret = ret + fraction;
10152
940k
        while ((CUR >= '0') && (CUR <= '9'))
10153
640k
            NEXT;
10154
299k
    }
10155
2.11M
    if ((CUR == 'e') || (CUR == 'E')) {
10156
270k
        NEXT;
10157
270k
        if (CUR == '-') {
10158
16.0k
            is_exponent_negative = 1;
10159
16.0k
            NEXT;
10160
254k
        } else if (CUR == '+') {
10161
16.5k
      NEXT;
10162
16.5k
  }
10163
1.06M
        while ((CUR >= '0') && (CUR <= '9')) {
10164
798k
            if (exponent < 1000000)
10165
587k
                exponent = exponent * 10 + (CUR - '0');
10166
798k
            NEXT;
10167
798k
        }
10168
270k
        if (is_exponent_negative)
10169
16.0k
            exponent = -exponent;
10170
270k
        ret *= pow(10.0, (double) exponent);
10171
270k
    }
10172
2.11M
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10173
2.11M
    if (num == NULL) {
10174
0
  ctxt->error = XPATH_MEMORY_ERROR;
10175
2.11M
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10176
2.11M
                              NULL) == -1) {
10177
0
        xmlXPathReleaseObject(ctxt->context, num);
10178
0
    }
10179
2.11M
}
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
25.0k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10194
25.0k
    const xmlChar *q;
10195
25.0k
    xmlChar *ret = NULL;
10196
10197
25.0k
    if (CUR == '"') {
10198
10.8k
        NEXT;
10199
10.8k
  q = CUR_PTR;
10200
1.17M
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10201
1.16M
      NEXT;
10202
10.8k
  if (!IS_CHAR_CH(CUR)) {
10203
5.04k
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10204
5.75k
  } else {
10205
5.75k
      ret = xmlStrndup(q, CUR_PTR - q);
10206
5.75k
      NEXT;
10207
5.75k
        }
10208
14.2k
    } else if (CUR == '\'') {
10209
2.91k
        NEXT;
10210
2.91k
  q = CUR_PTR;
10211
268k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10212
265k
      NEXT;
10213
2.91k
  if (!IS_CHAR_CH(CUR)) {
10214
574
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10215
2.34k
  } else {
10216
2.34k
      ret = xmlStrndup(q, CUR_PTR - q);
10217
2.34k
      NEXT;
10218
2.34k
        }
10219
11.3k
    } else {
10220
11.3k
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10221
0
    }
10222
8.09k
    return(ret);
10223
25.0k
}
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
804k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10238
804k
    const xmlChar *q;
10239
804k
    xmlChar *ret = NULL;
10240
804k
    xmlXPathObjectPtr lit;
10241
10242
804k
    if (CUR == '"') {
10243
54.4k
        NEXT;
10244
54.4k
  q = CUR_PTR;
10245
3.74M
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10246
3.69M
      NEXT;
10247
54.4k
  if (!IS_CHAR_CH(CUR)) {
10248
19.2k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10249
35.2k
  } else {
10250
35.2k
      ret = xmlStrndup(q, CUR_PTR - q);
10251
35.2k
      NEXT;
10252
35.2k
        }
10253
750k
    } else if (CUR == '\'') {
10254
750k
        NEXT;
10255
750k
  q = CUR_PTR;
10256
96.8M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10257
96.0M
      NEXT;
10258
750k
  if (!IS_CHAR_CH(CUR)) {
10259
3.78k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10260
746k
  } else {
10261
746k
      ret = xmlStrndup(q, CUR_PTR - q);
10262
746k
      NEXT;
10263
746k
        }
10264
750k
    } else {
10265
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10266
0
    }
10267
781k
    if (ret == NULL) return;
10268
781k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10269
781k
    if (lit == NULL) {
10270
0
  ctxt->error = XPATH_MEMORY_ERROR;
10271
781k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10272
781k
                              NULL) == -1) {
10273
0
        xmlXPathReleaseObject(ctxt->context, lit);
10274
0
    }
10275
781k
    xmlFree(ret);
10276
781k
}
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
66.3k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10297
66.3k
    xmlChar *name;
10298
66.3k
    xmlChar *prefix;
10299
10300
66.3k
    SKIP_BLANKS;
10301
66.3k
    if (CUR != '$') {
10302
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10303
0
    }
10304
66.3k
    NEXT;
10305
66.3k
    name = xmlXPathParseQName(ctxt, &prefix);
10306
66.3k
    if (name == NULL) {
10307
19.7k
        xmlFree(prefix);
10308
19.7k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10309
0
    }
10310
46.6k
    ctxt->comp->last = -1;
10311
46.6k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10312
0
        xmlFree(prefix);
10313
0
        xmlFree(name);
10314
0
    }
10315
46.6k
    SKIP_BLANKS;
10316
46.6k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10317
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10318
0
    }
10319
46.6k
}
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
1.44M
xmlXPathIsNodeType(const xmlChar *name) {
10336
1.44M
    if (name == NULL)
10337
0
  return(0);
10338
10339
1.44M
    if (xmlStrEqual(name, BAD_CAST "node"))
10340
14.8k
  return(1);
10341
1.43M
    if (xmlStrEqual(name, BAD_CAST "text"))
10342
19.2k
  return(1);
10343
1.41M
    if (xmlStrEqual(name, BAD_CAST "comment"))
10344
5.73k
  return(1);
10345
1.40M
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10346
3.78k
  return(1);
10347
1.40M
    return(0);
10348
1.40M
}
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
1.40M
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10362
1.40M
    xmlChar *name;
10363
1.40M
    xmlChar *prefix;
10364
1.40M
    int nbargs = 0;
10365
1.40M
    int sort = 1;
10366
10367
1.40M
    name = xmlXPathParseQName(ctxt, &prefix);
10368
1.40M
    if (name == NULL) {
10369
6.04k
  xmlFree(prefix);
10370
6.04k
  XP_ERROR(XPATH_EXPR_ERROR);
10371
0
    }
10372
1.39M
    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
1.39M
    if (CUR != '(') {
10383
6.49k
  xmlFree(name);
10384
6.49k
  xmlFree(prefix);
10385
6.49k
  XP_ERROR(XPATH_EXPR_ERROR);
10386
0
    }
10387
1.39M
    NEXT;
10388
1.39M
    SKIP_BLANKS;
10389
10390
    /*
10391
    * Optimization for count(): we don't need the node-set to be sorted.
10392
    */
10393
1.39M
    if ((prefix == NULL) && (name[0] == 'c') &&
10394
1.39M
  xmlStrEqual(name, BAD_CAST "count"))
10395
727
    {
10396
727
  sort = 0;
10397
727
    }
10398
1.39M
    ctxt->comp->last = -1;
10399
1.39M
    if (CUR != ')') {
10400
2.04M
  while (CUR != 0) {
10401
1.98M
      int op1 = ctxt->comp->last;
10402
1.98M
      ctxt->comp->last = -1;
10403
1.98M
      xmlXPathCompileExpr(ctxt, sort);
10404
1.98M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10405
269k
    xmlFree(name);
10406
269k
    xmlFree(prefix);
10407
269k
    return;
10408
269k
      }
10409
1.71M
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10410
1.71M
      nbargs++;
10411
1.71M
      if (CUR == ')') break;
10412
845k
      if (CUR != ',') {
10413
88.0k
    xmlFree(name);
10414
88.0k
    xmlFree(prefix);
10415
88.0k
    XP_ERROR(XPATH_EXPR_ERROR);
10416
0
      }
10417
757k
      NEXT;
10418
757k
      SKIP_BLANKS;
10419
757k
  }
10420
1.28M
    }
10421
1.03M
    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.03M
    NEXT;
10426
1.03M
    SKIP_BLANKS;
10427
1.03M
}
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
4.91M
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10443
4.91M
    SKIP_BLANKS;
10444
4.91M
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10445
4.85M
    else if (CUR == '(') {
10446
514k
  NEXT;
10447
514k
  SKIP_BLANKS;
10448
514k
  xmlXPathCompileExpr(ctxt, 1);
10449
514k
  CHECK_ERROR;
10450
315k
  if (CUR != ')') {
10451
64.4k
      XP_ERROR(XPATH_EXPR_ERROR);
10452
0
  }
10453
251k
  NEXT;
10454
251k
  SKIP_BLANKS;
10455
4.33M
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10456
2.12M
  xmlXPathCompNumber(ctxt);
10457
2.20M
    } else if ((CUR == '\'') || (CUR == '"')) {
10458
804k
  xmlXPathCompLiteral(ctxt);
10459
1.40M
    } else {
10460
1.40M
  xmlXPathCompFunctionCall(ctxt);
10461
1.40M
    }
10462
4.65M
    SKIP_BLANKS;
10463
4.65M
}
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
4.91M
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10482
4.91M
    xmlXPathCompPrimaryExpr(ctxt);
10483
4.91M
    CHECK_ERROR;
10484
4.23M
    SKIP_BLANKS;
10485
10486
5.00M
    while (CUR == '[') {
10487
772k
  xmlXPathCompPredicate(ctxt, 1);
10488
772k
  SKIP_BLANKS;
10489
772k
    }
10490
10491
10492
4.23M
}
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
16.0M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10513
16.0M
    int l;
10514
16.0M
    int c;
10515
16.0M
    const xmlChar *cur;
10516
16.0M
    xmlChar *ret;
10517
10518
16.0M
    cur = ctxt->cur;
10519
10520
16.0M
    c = CUR_CHAR(l);
10521
16.0M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10522
16.0M
  (!IS_LETTER(c) && (c != '_') &&
10523
16.0M
         (c != ':'))) {
10524
10.6M
  return(NULL);
10525
10.6M
    }
10526
10527
56.4M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10528
56.4M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10529
55.0M
            (c == '.') || (c == '-') ||
10530
55.0M
      (c == '_') || (c == ':') ||
10531
55.0M
      (IS_COMBINING(c)) ||
10532
55.0M
      (IS_EXTENDER(c)))) {
10533
51.1M
  NEXTL(l);
10534
51.1M
  c = CUR_CHAR(l);
10535
51.1M
    }
10536
5.39M
    ret = xmlStrndup(cur, ctxt->cur - cur);
10537
5.39M
    ctxt->cur = cur;
10538
5.39M
    return(ret);
10539
16.0M
}
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
26.9M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10561
26.9M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10562
26.9M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10563
10564
26.9M
    SKIP_BLANKS;
10565
26.9M
    if ((CUR == '$') || (CUR == '(') ||
10566
26.9M
  (IS_ASCII_DIGIT(CUR)) ||
10567
26.9M
        (CUR == '\'') || (CUR == '"') ||
10568
26.9M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10569
3.51M
  lc = 0;
10570
23.4M
    } else if (CUR == '*') {
10571
  /* relative or absolute location path */
10572
2.35M
  lc = 1;
10573
21.0M
    } else if (CUR == '/') {
10574
  /* relative or absolute location path */
10575
3.36M
  lc = 1;
10576
17.7M
    } else if (CUR == '@') {
10577
  /* relative abbreviated attribute location path */
10578
250k
  lc = 1;
10579
17.4M
    } else if (CUR == '.') {
10580
  /* relative abbreviated attribute location path */
10581
1.36M
  lc = 1;
10582
16.0M
    } 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
16.0M
  SKIP_BLANKS;
10595
16.0M
  name = xmlXPathScanName(ctxt);
10596
16.0M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10597
#ifdef DEBUG_STEP
10598
      xmlGenericError(xmlGenericErrorContext,
10599
        "PathExpr: Axis\n");
10600
#endif
10601
76.7k
      lc = 1;
10602
76.7k
      xmlFree(name);
10603
16.0M
  } else if (name != NULL) {
10604
5.31M
      int len =xmlStrlen(name);
10605
10606
10607
7.39M
      while (NXT(len) != 0) {
10608
7.14M
    if (NXT(len) == '/') {
10609
        /* element name */
10610
#ifdef DEBUG_STEP
10611
        xmlGenericError(xmlGenericErrorContext,
10612
          "PathExpr: AbbrRelLocation\n");
10613
#endif
10614
1.09M
        lc = 1;
10615
1.09M
        break;
10616
6.04M
    } else if (IS_BLANK_CH(NXT(len))) {
10617
        /* ignore blanks */
10618
2.07M
        ;
10619
3.96M
    } else if (NXT(len) == ':') {
10620
#ifdef DEBUG_STEP
10621
        xmlGenericError(xmlGenericErrorContext,
10622
          "PathExpr: AbbrRelLocation\n");
10623
#endif
10624
2.46k
        lc = 1;
10625
2.46k
        break;
10626
3.96M
    } else if ((NXT(len) == '(')) {
10627
        /* Node Type or Function */
10628
1.44M
        if (xmlXPathIsNodeType(name)) {
10629
#ifdef DEBUG_STEP
10630
            xmlGenericError(xmlGenericErrorContext,
10631
        "PathExpr: Type search\n");
10632
#endif
10633
43.6k
      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
1.40M
        } else {
10640
#ifdef DEBUG_STEP
10641
            xmlGenericError(xmlGenericErrorContext,
10642
        "PathExpr: function call\n");
10643
#endif
10644
1.40M
      lc = 0;
10645
1.40M
        }
10646
1.44M
                    break;
10647
2.51M
    } else if ((NXT(len) == '[')) {
10648
        /* element name */
10649
#ifdef DEBUG_STEP
10650
        xmlGenericError(xmlGenericErrorContext,
10651
          "PathExpr: AbbrRelLocation\n");
10652
#endif
10653
84.5k
        lc = 1;
10654
84.5k
        break;
10655
2.43M
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10656
2.43M
         (NXT(len) == '=')) {
10657
310k
        lc = 1;
10658
310k
        break;
10659
2.12M
    } else {
10660
2.12M
        lc = 1;
10661
2.12M
        break;
10662
2.12M
    }
10663
2.07M
    len++;
10664
2.07M
      }
10665
5.31M
      if (NXT(len) == 0) {
10666
#ifdef DEBUG_STEP
10667
    xmlGenericError(xmlGenericErrorContext,
10668
      "PathExpr: AbbrRelLocation\n");
10669
#endif
10670
    /* element name */
10671
251k
    lc = 1;
10672
251k
      }
10673
5.31M
      xmlFree(name);
10674
10.6M
  } else {
10675
      /* make sure all cases are covered explicitly */
10676
10.6M
      XP_ERROR(XPATH_EXPR_ERROR);
10677
0
  }
10678
16.0M
    }
10679
10680
16.2M
    if (lc) {
10681
11.3M
  if (CUR == '/') {
10682
3.36M
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10683
7.96M
  } else {
10684
7.96M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10685
7.96M
  }
10686
11.3M
  xmlXPathCompLocationPath(ctxt);
10687
11.3M
    } else {
10688
4.91M
  xmlXPathCompFilterExpr(ctxt);
10689
4.91M
  CHECK_ERROR;
10690
4.18M
  if ((CUR == '/') && (NXT(1) == '/')) {
10691
98.4k
      SKIP(2);
10692
98.4k
      SKIP_BLANKS;
10693
10694
98.4k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10695
98.4k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10696
10697
98.4k
      xmlXPathCompRelativeLocationPath(ctxt);
10698
4.08M
  } else if (CUR == '/') {
10699
230k
      xmlXPathCompRelativeLocationPath(ctxt);
10700
230k
  }
10701
4.18M
    }
10702
15.5M
    SKIP_BLANKS;
10703
15.5M
}
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
15.8M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10717
15.8M
    xmlXPathCompPathExpr(ctxt);
10718
15.8M
    CHECK_ERROR;
10719
11.1M
    SKIP_BLANKS;
10720
22.2M
    while (CUR == '|') {
10721
11.0M
  int op1 = ctxt->comp->last;
10722
11.0M
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10723
10724
11.0M
  NEXT;
10725
11.0M
  SKIP_BLANKS;
10726
11.0M
  xmlXPathCompPathExpr(ctxt);
10727
10728
11.0M
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10729
10730
11.0M
  SKIP_BLANKS;
10731
11.0M
    }
10732
11.1M
}
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
15.8M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10746
15.8M
    int minus = 0;
10747
15.8M
    int found = 0;
10748
10749
15.8M
    SKIP_BLANKS;
10750
25.6M
    while (CUR == '-') {
10751
9.75M
        minus = 1 - minus;
10752
9.75M
  found = 1;
10753
9.75M
  NEXT;
10754
9.75M
  SKIP_BLANKS;
10755
9.75M
    }
10756
10757
15.8M
    xmlXPathCompUnionExpr(ctxt);
10758
15.8M
    CHECK_ERROR;
10759
10.8M
    if (found) {
10760
712k
  if (minus)
10761
511k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10762
201k
  else
10763
201k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10764
712k
    }
10765
10.8M
}
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
13.5M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10782
13.5M
    xmlXPathCompUnaryExpr(ctxt);
10783
13.5M
    CHECK_ERROR;
10784
8.64M
    SKIP_BLANKS;
10785
10.8M
    while ((CUR == '*') ||
10786
10.8M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10787
10.8M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10788
2.27M
  int op = -1;
10789
2.27M
  int op1 = ctxt->comp->last;
10790
10791
2.27M
        if (CUR == '*') {
10792
2.25M
      op = 0;
10793
2.25M
      NEXT;
10794
2.25M
  } else if (CUR == 'd') {
10795
14.4k
      op = 1;
10796
14.4k
      SKIP(3);
10797
14.4k
  } else if (CUR == 'm') {
10798
11.5k
      op = 2;
10799
11.5k
      SKIP(3);
10800
11.5k
  }
10801
2.27M
  SKIP_BLANKS;
10802
2.27M
        xmlXPathCompUnaryExpr(ctxt);
10803
2.27M
  CHECK_ERROR;
10804
2.17M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10805
2.17M
  SKIP_BLANKS;
10806
2.17M
    }
10807
8.64M
}
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
12.5M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10822
10823
12.5M
    xmlXPathCompMultiplicativeExpr(ctxt);
10824
12.5M
    CHECK_ERROR;
10825
7.66M
    SKIP_BLANKS;
10826
8.54M
    while ((CUR == '+') || (CUR == '-')) {
10827
1.03M
  int plus;
10828
1.03M
  int op1 = ctxt->comp->last;
10829
10830
1.03M
        if (CUR == '+') plus = 1;
10831
669k
  else plus = 0;
10832
1.03M
  NEXT;
10833
1.03M
  SKIP_BLANKS;
10834
1.03M
        xmlXPathCompMultiplicativeExpr(ctxt);
10835
1.03M
  CHECK_ERROR;
10836
884k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10837
884k
  SKIP_BLANKS;
10838
884k
    }
10839
7.66M
}
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
11.7M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10861
11.7M
    xmlXPathCompAdditiveExpr(ctxt);
10862
11.7M
    CHECK_ERROR;
10863
6.88M
    SKIP_BLANKS;
10864
7.50M
    while ((CUR == '<') || (CUR == '>')) {
10865
830k
  int inf, strict;
10866
830k
  int op1 = ctxt->comp->last;
10867
10868
830k
        if (CUR == '<') inf = 1;
10869
492k
  else inf = 0;
10870
830k
  if (NXT(1) == '=') strict = 0;
10871
607k
  else strict = 1;
10872
830k
  NEXT;
10873
830k
  if (!strict) NEXT;
10874
830k
  SKIP_BLANKS;
10875
830k
        xmlXPathCompAdditiveExpr(ctxt);
10876
830k
  CHECK_ERROR;
10877
617k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10878
617k
  SKIP_BLANKS;
10879
617k
    }
10880
6.88M
}
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
10.4M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10900
10.4M
    xmlXPathCompRelationalExpr(ctxt);
10901
10.4M
    CHECK_ERROR;
10902
5.65M
    SKIP_BLANKS;
10903
6.67M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10904
1.31M
  int eq;
10905
1.31M
  int op1 = ctxt->comp->last;
10906
10907
1.31M
        if (CUR == '=') eq = 1;
10908
369k
  else eq = 0;
10909
1.31M
  NEXT;
10910
1.31M
  if (!eq) NEXT;
10911
1.31M
  SKIP_BLANKS;
10912
1.31M
        xmlXPathCompRelationalExpr(ctxt);
10913
1.31M
  CHECK_ERROR;
10914
1.01M
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10915
1.01M
  SKIP_BLANKS;
10916
1.01M
    }
10917
5.65M
}
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
10.2M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10931
10.2M
    xmlXPathCompEqualityExpr(ctxt);
10932
10.2M
    CHECK_ERROR;
10933
5.27M
    SKIP_BLANKS;
10934
5.36M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10935
119k
  int op1 = ctxt->comp->last;
10936
119k
        SKIP(3);
10937
119k
  SKIP_BLANKS;
10938
119k
        xmlXPathCompEqualityExpr(ctxt);
10939
119k
  CHECK_ERROR;
10940
88.9k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10941
88.9k
  SKIP_BLANKS;
10942
88.9k
    }
10943
5.27M
}
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
12.7M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10957
12.7M
    xmlXPathContextPtr xpctxt = ctxt->context;
10958
10959
12.7M
    if (xpctxt != NULL) {
10960
12.7M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10961
10.1M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10962
        /*
10963
         * Parsing a single '(' pushes about 10 functions on the call stack
10964
         * before recursing!
10965
         */
10966
10.1M
        xpctxt->depth += 10;
10967
10.1M
    }
10968
10969
10.1M
    xmlXPathCompAndExpr(ctxt);
10970
10.1M
    CHECK_ERROR;
10971
5.14M
    SKIP_BLANKS;
10972
5.24M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10973
124k
  int op1 = ctxt->comp->last;
10974
124k
        SKIP(2);
10975
124k
  SKIP_BLANKS;
10976
124k
        xmlXPathCompAndExpr(ctxt);
10977
124k
  CHECK_ERROR;
10978
94.0k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10979
94.0k
  SKIP_BLANKS;
10980
94.0k
    }
10981
5.11M
    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
2.67M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10989
2.67M
    }
10990
10991
5.11M
    if (xpctxt != NULL)
10992
5.11M
        xpctxt->depth -= 10;
10993
5.11M
}
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
4.21M
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11007
4.21M
    int op1 = ctxt->comp->last;
11008
11009
4.21M
    SKIP_BLANKS;
11010
4.21M
    if (CUR != '[') {
11011
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11012
0
    }
11013
4.21M
    NEXT;
11014
4.21M
    SKIP_BLANKS;
11015
11016
4.21M
    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
4.21M
    if (! filter)
11027
3.44M
  xmlXPathCompileExpr(ctxt, 0);
11028
772k
    else
11029
772k
  xmlXPathCompileExpr(ctxt, 1);
11030
4.21M
    CHECK_ERROR;
11031
11032
1.26M
    if (CUR != ']') {
11033
93.8k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11034
0
    }
11035
11036
1.17M
    if (filter)
11037
199k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11038
974k
    else
11039
974k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11040
11041
1.17M
    NEXT;
11042
1.17M
    SKIP_BLANKS;
11043
1.17M
}
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
12.5M
         xmlChar *name) {
11070
12.5M
    int blanks;
11071
11072
12.5M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11073
0
  STRANGE;
11074
0
  return(NULL);
11075
0
    }
11076
12.5M
    *type = (xmlXPathTypeVal) 0;
11077
12.5M
    *test = (xmlXPathTestVal) 0;
11078
12.5M
    *prefix = NULL;
11079
12.5M
    SKIP_BLANKS;
11080
11081
12.5M
    if ((name == NULL) && (CUR == '*')) {
11082
  /*
11083
   * All elements
11084
   */
11085
4.63M
  NEXT;
11086
4.63M
  *test = NODE_TEST_ALL;
11087
4.63M
  return(NULL);
11088
4.63M
    }
11089
11090
7.94M
    if (name == NULL)
11091
680k
  name = xmlXPathParseNCName(ctxt);
11092
7.94M
    if (name == NULL) {
11093
384k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11094
0
    }
11095
11096
7.56M
    blanks = IS_BLANK_CH(CUR);
11097
7.56M
    SKIP_BLANKS;
11098
7.56M
    if (CUR == '(') {
11099
251k
  NEXT;
11100
  /*
11101
   * NodeType or PI search
11102
   */
11103
251k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11104
19.1k
      *type = NODE_TYPE_COMMENT;
11105
232k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11106
62.9k
      *type = NODE_TYPE_NODE;
11107
169k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11108
32.9k
      *type = NODE_TYPE_PI;
11109
136k
  else if (xmlStrEqual(name, BAD_CAST "text"))
11110
116k
      *type = NODE_TYPE_TEXT;
11111
20.5k
  else {
11112
20.5k
      if (name != NULL)
11113
20.5k
    xmlFree(name);
11114
20.5k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11115
0
  }
11116
11117
231k
  *test = NODE_TEST_TYPE;
11118
11119
231k
  SKIP_BLANKS;
11120
231k
  if (*type == NODE_TYPE_PI) {
11121
      /*
11122
       * Specific case: search a PI by name.
11123
       */
11124
32.9k
      if (name != NULL)
11125
32.9k
    xmlFree(name);
11126
32.9k
      name = NULL;
11127
32.9k
      if (CUR != ')') {
11128
25.0k
    name = xmlXPathParseLiteral(ctxt);
11129
25.0k
                if (name == NULL) {
11130
16.9k
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11131
0
                }
11132
8.09k
    *test = NODE_TEST_PI;
11133
8.09k
    SKIP_BLANKS;
11134
8.09k
      }
11135
32.9k
  }
11136
214k
  if (CUR != ')') {
11137
24.2k
      if (name != NULL)
11138
24.2k
    xmlFree(name);
11139
24.2k
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11140
0
  }
11141
189k
  NEXT;
11142
189k
  return(name);
11143
214k
    }
11144
7.31M
    *test = NODE_TEST_NAME;
11145
7.31M
    if ((!blanks) && (CUR == ':')) {
11146
434k
  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
434k
  *prefix = name;
11164
434k
#endif
11165
11166
434k
  if (CUR == '*') {
11167
      /*
11168
       * All elements
11169
       */
11170
55.4k
      NEXT;
11171
55.4k
      *test = NODE_TEST_ALL;
11172
55.4k
      return(NULL);
11173
55.4k
  }
11174
11175
379k
  name = xmlXPathParseNCName(ctxt);
11176
379k
  if (name == NULL) {
11177
98.8k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11178
0
  }
11179
379k
    }
11180
7.15M
    return(name);
11181
7.31M
}
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
7.78M
xmlXPathIsAxisName(const xmlChar *name) {
11205
7.78M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11206
7.78M
    switch (name[0]) {
11207
619k
  case 'a':
11208
619k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11209
50.3k
    ret = AXIS_ANCESTOR;
11210
619k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11211
16.8k
    ret = AXIS_ANCESTOR_OR_SELF;
11212
619k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11213
9.27k
    ret = AXIS_ATTRIBUTE;
11214
619k
      break;
11215
506k
  case 'c':
11216
506k
      if (xmlStrEqual(name, BAD_CAST "child"))
11217
23.3k
    ret = AXIS_CHILD;
11218
506k
      break;
11219
626k
  case 'd':
11220
626k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11221
8.35k
    ret = AXIS_DESCENDANT;
11222
626k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11223
12.3k
    ret = AXIS_DESCENDANT_OR_SELF;
11224
626k
      break;
11225
219k
  case 'f':
11226
219k
      if (xmlStrEqual(name, BAD_CAST "following"))
11227
22.0k
    ret = AXIS_FOLLOWING;
11228
219k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11229
14.2k
    ret = AXIS_FOLLOWING_SIBLING;
11230
219k
      break;
11231
458k
  case 'n':
11232
458k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11233
85.6k
    ret = AXIS_NAMESPACE;
11234
458k
      break;
11235
251k
  case 'p':
11236
251k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11237
15.3k
    ret = AXIS_PARENT;
11238
251k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11239
23.3k
    ret = AXIS_PRECEDING;
11240
251k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11241
17.0k
    ret = AXIS_PRECEDING_SIBLING;
11242
251k
      break;
11243
221k
  case 's':
11244
221k
      if (xmlStrEqual(name, BAD_CAST "self"))
11245
20.9k
    ret = AXIS_SELF;
11246
221k
      break;
11247
7.78M
    }
11248
7.78M
    return(ret);
11249
7.78M
}
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
16.0M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11285
#ifdef LIBXML_XPTR_LOCS_ENABLED
11286
    int rangeto = 0;
11287
    int op2 = -1;
11288
#endif
11289
11290
16.0M
    SKIP_BLANKS;
11291
16.0M
    if ((CUR == '.') && (NXT(1) == '.')) {
11292
107k
  SKIP(2);
11293
107k
  SKIP_BLANKS;
11294
107k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11295
107k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11296
15.9M
    } else if (CUR == '.') {
11297
2.39M
  NEXT;
11298
2.39M
  SKIP_BLANKS;
11299
13.5M
    } else {
11300
13.5M
  xmlChar *name = NULL;
11301
13.5M
  xmlChar *prefix = NULL;
11302
13.5M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11303
13.5M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11304
13.5M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11305
13.5M
  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
13.5M
  if (CUR == '*') {
11338
4.27M
      axis = AXIS_CHILD;
11339
9.28M
  } else {
11340
9.28M
      if (name == NULL)
11341
9.28M
    name = xmlXPathParseNCName(ctxt);
11342
9.28M
      if (name != NULL) {
11343
7.78M
    axis = xmlXPathIsAxisName(name);
11344
7.78M
    if (axis != 0) {
11345
319k
        SKIP_BLANKS;
11346
319k
        if ((CUR == ':') && (NXT(1) == ':')) {
11347
227k
      SKIP(2);
11348
227k
      xmlFree(name);
11349
227k
      name = NULL;
11350
227k
        } else {
11351
      /* an element name can conflict with an axis one :-\ */
11352
92.0k
      axis = AXIS_CHILD;
11353
92.0k
        }
11354
7.46M
    } else {
11355
7.46M
        axis = AXIS_CHILD;
11356
7.46M
    }
11357
7.78M
      } else if (CUR == '@') {
11358
526k
    NEXT;
11359
526k
    axis = AXIS_ATTRIBUTE;
11360
978k
      } else {
11361
978k
    axis = AXIS_CHILD;
11362
978k
      }
11363
9.28M
  }
11364
11365
13.5M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11366
970k
            xmlFree(name);
11367
970k
            return;
11368
970k
        }
11369
11370
12.5M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11371
12.5M
  if (test == 0)
11372
404k
      return;
11373
11374
12.1M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11375
12.1M
      (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
12.1M
  op1 = ctxt->comp->last;
11399
12.1M
  ctxt->comp->last = -1;
11400
11401
12.1M
  SKIP_BLANKS;
11402
15.6M
  while (CUR == '[') {
11403
3.44M
      xmlXPathCompPredicate(ctxt, 0);
11404
3.44M
  }
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
12.1M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11412
12.1M
                           test, type, (void *)prefix, (void *)name) == -1) {
11413
0
            xmlFree(prefix);
11414
0
            xmlFree(name);
11415
0
        }
11416
12.1M
    }
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
16.0M
}
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
11.1M
(xmlXPathParserContextPtr ctxt) {
11443
11.1M
    SKIP_BLANKS;
11444
11.1M
    if ((CUR == '/') && (NXT(1) == '/')) {
11445
74.3k
  SKIP(2);
11446
74.3k
  SKIP_BLANKS;
11447
74.3k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11448
74.3k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11449
11.0M
    } else if (CUR == '/') {
11450
376k
      NEXT;
11451
376k
  SKIP_BLANKS;
11452
376k
    }
11453
11.1M
    xmlXPathCompStep(ctxt);
11454
11.1M
    CHECK_ERROR;
11455
10.3M
    SKIP_BLANKS;
11456
15.2M
    while (CUR == '/') {
11457
4.89M
  if ((CUR == '/') && (NXT(1) == '/')) {
11458
1.91M
      SKIP(2);
11459
1.91M
      SKIP_BLANKS;
11460
1.91M
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11461
1.91M
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11462
1.91M
      xmlXPathCompStep(ctxt);
11463
2.98M
  } else if (CUR == '/') {
11464
2.98M
      NEXT;
11465
2.98M
      SKIP_BLANKS;
11466
2.98M
      xmlXPathCompStep(ctxt);
11467
2.98M
  }
11468
4.89M
  SKIP_BLANKS;
11469
4.89M
    }
11470
10.3M
}
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
11.3M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11495
11.3M
    SKIP_BLANKS;
11496
11.3M
    if (CUR != '/') {
11497
7.96M
        xmlXPathCompRelativeLocationPath(ctxt);
11498
7.96M
    } else {
11499
6.48M
  while (CUR == '/') {
11500
3.49M
      if ((CUR == '/') && (NXT(1) == '/')) {
11501
1.52M
    SKIP(2);
11502
1.52M
    SKIP_BLANKS;
11503
1.52M
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11504
1.52M
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11505
1.52M
    xmlXPathCompRelativeLocationPath(ctxt);
11506
1.97M
      } else if (CUR == '/') {
11507
1.97M
    NEXT;
11508
1.97M
    SKIP_BLANKS;
11509
1.97M
    if ((CUR != 0 ) &&
11510
1.97M
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11511
1.94M
         (CUR == '@') || (CUR == '*')))
11512
1.34M
        xmlXPathCompRelativeLocationPath(ctxt);
11513
1.97M
      }
11514
3.49M
      CHECK_ERROR;
11515
3.49M
  }
11516
3.36M
    }
11517
11.3M
}
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
4.87M
{
11635
4.87M
    xmlXPathContextPtr xpctxt;
11636
4.87M
    xmlNodePtr oldnode;
11637
4.87M
    xmlDocPtr olddoc;
11638
4.87M
    xmlXPathStepOpPtr filterOp;
11639
4.87M
    int oldcs, oldpp;
11640
4.87M
    int i, j, pos;
11641
11642
4.87M
    if ((set == NULL) || (set->nodeNr == 0))
11643
628k
        return;
11644
11645
    /*
11646
    * Check if the node set contains a sufficient number of nodes for
11647
    * the requested range.
11648
    */
11649
4.24M
    if (set->nodeNr < minPos) {
11650
58.5k
        xmlXPathNodeSetClear(set, hasNsNodes);
11651
58.5k
        return;
11652
58.5k
    }
11653
11654
4.18M
    xpctxt = ctxt->context;
11655
4.18M
    oldnode = xpctxt->node;
11656
4.18M
    olddoc = xpctxt->doc;
11657
4.18M
    oldcs = xpctxt->contextSize;
11658
4.18M
    oldpp = xpctxt->proximityPosition;
11659
4.18M
    filterOp = &ctxt->comp->steps[filterOpIndex];
11660
11661
4.18M
    xpctxt->contextSize = set->nodeNr;
11662
11663
15.6M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11664
12.4M
        xmlNodePtr node = set->nodeTab[i];
11665
12.4M
        int res;
11666
11667
12.4M
        xpctxt->node = node;
11668
12.4M
        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
12.4M
        if ((node->type != XML_NAMESPACE_DECL) &&
11677
12.4M
            (node->doc != NULL))
11678
12.1M
            xpctxt->doc = node->doc;
11679
11680
12.4M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11681
11682
12.4M
        if (ctxt->error != XPATH_EXPRESSION_OK)
11683
55.3k
            break;
11684
12.4M
        if (res < 0) {
11685
            /* Shouldn't happen */
11686
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11687
0
            break;
11688
0
        }
11689
11690
12.4M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11691
3.38M
            if (i != j) {
11692
520k
                set->nodeTab[j] = node;
11693
520k
                set->nodeTab[i] = NULL;
11694
520k
            }
11695
11696
3.38M
            j += 1;
11697
9.05M
        } else {
11698
            /* Remove the entry from the initial node set. */
11699
9.05M
            set->nodeTab[i] = NULL;
11700
9.05M
            if (node->type == XML_NAMESPACE_DECL)
11701
255k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11702
9.05M
        }
11703
11704
12.4M
        if (res != 0) {
11705
3.53M
            if (pos == maxPos) {
11706
983k
                i += 1;
11707
983k
                break;
11708
983k
            }
11709
11710
2.54M
            pos += 1;
11711
2.54M
        }
11712
12.4M
    }
11713
11714
    /* Free remaining nodes. */
11715
4.18M
    if (hasNsNodes) {
11716
488k
        for (; i < set->nodeNr; i++) {
11717
149k
            xmlNodePtr node = set->nodeTab[i];
11718
149k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11719
42.3k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11720
149k
        }
11721
338k
    }
11722
11723
4.18M
    set->nodeNr = j;
11724
11725
    /* If too many elements were removed, shrink table to preserve memory. */
11726
4.18M
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11727
4.18M
        (set->nodeNr < set->nodeMax / 2)) {
11728
103k
        xmlNodePtr *tmp;
11729
103k
        int nodeMax = set->nodeNr;
11730
11731
103k
        if (nodeMax < XML_NODESET_DEFAULT)
11732
102k
            nodeMax = XML_NODESET_DEFAULT;
11733
103k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11734
103k
                nodeMax * sizeof(xmlNodePtr));
11735
103k
        if (tmp == NULL) {
11736
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11737
103k
        } else {
11738
103k
            set->nodeTab = tmp;
11739
103k
            set->nodeMax = nodeMax;
11740
103k
        }
11741
103k
    }
11742
11743
4.18M
    xpctxt->node = oldnode;
11744
4.18M
    xpctxt->doc = olddoc;
11745
4.18M
    xpctxt->contextSize = oldcs;
11746
4.18M
    xpctxt->proximityPosition = oldpp;
11747
4.18M
}
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
4.24M
{
11888
4.24M
    if (op->ch1 != -1) {
11889
450k
  xmlXPathCompExprPtr comp = ctxt->comp;
11890
  /*
11891
  * Process inner predicates first.
11892
  */
11893
450k
  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
450k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11899
450k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11900
450k
        ctxt->context->depth += 1;
11901
450k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11902
450k
                                    1, set->nodeNr, hasNsNodes);
11903
450k
        ctxt->context->depth -= 1;
11904
450k
  CHECK_ERROR;
11905
450k
    }
11906
11907
4.24M
    if (op->ch2 != -1)
11908
4.24M
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11909
4.24M
}
11910
11911
static int
11912
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11913
          xmlXPathStepOpPtr op,
11914
          int *maxPos)
11915
2.36M
{
11916
11917
2.36M
    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
2.36M
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11933
0
  return(0);
11934
11935
2.36M
    if (op->ch2 != -1) {
11936
2.36M
  exprOp = &ctxt->comp->steps[op->ch2];
11937
2.36M
    } else
11938
0
  return(0);
11939
11940
2.36M
    if ((exprOp != NULL) &&
11941
2.36M
  (exprOp->op == XPATH_OP_VALUE) &&
11942
2.36M
  (exprOp->value4 != NULL) &&
11943
2.36M
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11944
796k
    {
11945
796k
        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
796k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11959
786k
      *maxPos = (int) floatval;
11960
786k
            if (floatval == (double) *maxPos)
11961
714k
                return(1);
11962
786k
        }
11963
796k
    }
11964
1.65M
    return(0);
11965
2.36M
}
11966
11967
static int
11968
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11969
                           xmlXPathStepOpPtr op,
11970
         xmlNodePtr * first, xmlNodePtr * last,
11971
         int toBool)
11972
50.7M
{
11973
11974
50.7M
#define XP_TEST_HIT \
11975
149M
    if (hasAxisRange != 0) { \
11976
1.08M
  if (++pos == maxPos) { \
11977
554k
      if (addNode(seq, cur) < 0) \
11978
554k
          ctxt->error = XPATH_MEMORY_ERROR; \
11979
554k
      goto axis_range_end; } \
11980
148M
    } else { \
11981
148M
  if (addNode(seq, cur) < 0) \
11982
148M
      ctxt->error = XPATH_MEMORY_ERROR; \
11983
148M
  if (breakOnFirstHit) goto first_hit; }
11984
11985
50.7M
#define XP_TEST_HIT_NS \
11986
50.7M
    if (hasAxisRange != 0) { \
11987
169k
  if (++pos == maxPos) { \
11988
90.5k
      hasNsNodes = 1; \
11989
90.5k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11990
90.5k
          ctxt->error = XPATH_MEMORY_ERROR; \
11991
90.5k
  goto axis_range_end; } \
11992
1.19M
    } else { \
11993
1.19M
  hasNsNodes = 1; \
11994
1.19M
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11995
1.19M
      ctxt->error = XPATH_MEMORY_ERROR; \
11996
1.19M
  if (breakOnFirstHit) goto first_hit; }
11997
11998
50.7M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999
50.7M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000
50.7M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001
50.7M
    const xmlChar *prefix = op->value4;
12002
50.7M
    const xmlChar *name = op->value5;
12003
50.7M
    const xmlChar *URI = NULL;
12004
12005
#ifdef DEBUG_STEP
12006
    int nbMatches = 0, prevMatches = 0;
12007
#endif
12008
50.7M
    int total = 0, hasNsNodes = 0;
12009
    /* The popped object holding the context nodes */
12010
50.7M
    xmlXPathObjectPtr obj;
12011
    /* The set of context nodes for the node tests */
12012
50.7M
    xmlNodeSetPtr contextSeq;
12013
50.7M
    int contextIdx;
12014
50.7M
    xmlNodePtr contextNode;
12015
    /* The final resulting node set wrt to all context nodes */
12016
50.7M
    xmlNodeSetPtr outSeq;
12017
    /*
12018
    * The temporary resulting node set wrt 1 context node.
12019
    * Used to feed predicate evaluation.
12020
    */
12021
50.7M
    xmlNodeSetPtr seq;
12022
50.7M
    xmlNodePtr cur;
12023
    /* First predicate operator */
12024
50.7M
    xmlXPathStepOpPtr predOp;
12025
50.7M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12026
50.7M
    int hasPredicateRange, hasAxisRange, pos;
12027
50.7M
    int breakOnFirstHit;
12028
12029
50.7M
    xmlXPathTraversalFunction next = NULL;
12030
50.7M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12031
50.7M
    xmlXPathNodeSetMergeFunction mergeAndClear;
12032
50.7M
    xmlNodePtr oldContextNode;
12033
50.7M
    xmlXPathContextPtr xpctxt = ctxt->context;
12034
12035
12036
50.7M
    CHECK_TYPE0(XPATH_NODESET);
12037
50.6M
    obj = valuePop(ctxt);
12038
    /*
12039
    * Setup namespaces.
12040
    */
12041
50.6M
    if (prefix != NULL) {
12042
941k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12043
941k
        if (URI == NULL) {
12044
120k
      xmlXPathReleaseObject(xpctxt, obj);
12045
120k
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12046
0
  }
12047
941k
    }
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
50.4M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12062
50.4M
    switch (axis) {
12063
355k
        case AXIS_ANCESTOR:
12064
355k
            first = NULL;
12065
355k
            next = xmlXPathNextAncestor;
12066
355k
            break;
12067
49.0k
        case AXIS_ANCESTOR_OR_SELF:
12068
49.0k
            first = NULL;
12069
49.0k
            next = xmlXPathNextAncestorOrSelf;
12070
49.0k
            break;
12071
3.17M
        case AXIS_ATTRIBUTE:
12072
3.17M
            first = NULL;
12073
3.17M
      last = NULL;
12074
3.17M
            next = xmlXPathNextAttribute;
12075
3.17M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12076
3.17M
            break;
12077
36.8M
        case AXIS_CHILD:
12078
36.8M
      last = NULL;
12079
36.8M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12080
36.8M
    (type == NODE_TYPE_NODE))
12081
36.2M
      {
12082
    /*
12083
    * Optimization if an element node type is 'element'.
12084
    */
12085
36.2M
    next = xmlXPathNextChildElement;
12086
36.2M
      } else
12087
547k
    next = xmlXPathNextChild;
12088
36.8M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12089
36.8M
            break;
12090
5.59M
        case AXIS_DESCENDANT:
12091
5.59M
      last = NULL;
12092
5.59M
            next = xmlXPathNextDescendant;
12093
5.59M
            break;
12094
3.45M
        case AXIS_DESCENDANT_OR_SELF:
12095
3.45M
      last = NULL;
12096
3.45M
            next = xmlXPathNextDescendantOrSelf;
12097
3.45M
            break;
12098
60.0k
        case AXIS_FOLLOWING:
12099
60.0k
      last = NULL;
12100
60.0k
            next = xmlXPathNextFollowing;
12101
60.0k
            break;
12102
27.0k
        case AXIS_FOLLOWING_SIBLING:
12103
27.0k
      last = NULL;
12104
27.0k
            next = xmlXPathNextFollowingSibling;
12105
27.0k
            break;
12106
260k
        case AXIS_NAMESPACE:
12107
260k
            first = NULL;
12108
260k
      last = NULL;
12109
260k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12110
260k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12111
260k
            break;
12112
522k
        case AXIS_PARENT:
12113
522k
            first = NULL;
12114
522k
            next = xmlXPathNextParent;
12115
522k
            break;
12116
57.5k
        case AXIS_PRECEDING:
12117
57.5k
            first = NULL;
12118
57.5k
            next = xmlXPathNextPrecedingInternal;
12119
57.5k
            break;
12120
80.3k
        case AXIS_PRECEDING_SIBLING:
12121
80.3k
            first = NULL;
12122
80.3k
            next = xmlXPathNextPrecedingSibling;
12123
80.3k
            break;
12124
29.0k
        case AXIS_SELF:
12125
29.0k
            first = NULL;
12126
29.0k
      last = NULL;
12127
29.0k
            next = xmlXPathNextSelf;
12128
29.0k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12129
29.0k
            break;
12130
50.4M
    }
12131
12132
#ifdef DEBUG_STEP
12133
    xmlXPathDebugDumpStepAxis(op,
12134
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12135
#endif
12136
12137
50.4M
    if (next == NULL) {
12138
0
  xmlXPathReleaseObject(xpctxt, obj);
12139
0
        return(0);
12140
0
    }
12141
50.4M
    contextSeq = obj->nodesetval;
12142
50.4M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12143
9.25M
  xmlXPathReleaseObject(xpctxt, obj);
12144
9.25M
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12145
9.25M
        return(0);
12146
9.25M
    }
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
41.2M
    maxPos = 0;
12166
41.2M
    predOp = NULL;
12167
41.2M
    hasPredicateRange = 0;
12168
41.2M
    hasAxisRange = 0;
12169
41.2M
    if (op->ch2 != -1) {
12170
  /*
12171
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12172
  */
12173
2.36M
  predOp = &ctxt->comp->steps[op->ch2];
12174
2.36M
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12175
714k
      if (predOp->ch1 != -1) {
12176
    /*
12177
    * Use the next inner predicate operator.
12178
    */
12179
272k
    predOp = &ctxt->comp->steps[predOp->ch1];
12180
272k
    hasPredicateRange = 1;
12181
441k
      } else {
12182
    /*
12183
    * There's no other predicate than the [n] predicate.
12184
    */
12185
441k
    predOp = NULL;
12186
441k
    hasAxisRange = 1;
12187
441k
      }
12188
714k
  }
12189
2.36M
    }
12190
41.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
41.2M
    oldContextNode = xpctxt->node;
12205
41.2M
    addNode = xmlXPathNodeSetAddUnique;
12206
41.2M
    outSeq = NULL;
12207
41.2M
    seq = NULL;
12208
41.2M
    contextNode = NULL;
12209
41.2M
    contextIdx = 0;
12210
12211
12212
125M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12213
125M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12214
85.6M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12215
12216
85.6M
  if (seq == NULL) {
12217
42.6M
      seq = xmlXPathNodeSetCreate(NULL);
12218
42.6M
      if (seq == NULL) {
12219
                /* TODO: Propagate memory error. */
12220
0
    total = 0;
12221
0
    goto error;
12222
0
      }
12223
42.6M
  }
12224
  /*
12225
  * Traverse the axis and test the nodes.
12226
  */
12227
85.6M
  pos = 0;
12228
85.6M
  cur = NULL;
12229
85.6M
  hasNsNodes = 0;
12230
365M
        do {
12231
365M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12232
3
                goto error;
12233
12234
365M
            cur = next(ctxt, cur);
12235
365M
            if (cur == NULL)
12236
83.7M
                break;
12237
12238
      /*
12239
      * QUESTION TODO: What does the "first" and "last" stuff do?
12240
      */
12241
282M
            if ((first != NULL) && (*first != NULL)) {
12242
392k
    if (*first == cur)
12243
21.0k
        break;
12244
370k
    if (((total % 256) == 0) &&
12245
370k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12246
370k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12247
#else
12248
        (xmlXPathCmpNodes(*first, cur) >= 0))
12249
#endif
12250
65.9k
    {
12251
65.9k
        break;
12252
65.9k
    }
12253
370k
      }
12254
282M
      if ((last != NULL) && (*last != NULL)) {
12255
286k
    if (*last == cur)
12256
49.3k
        break;
12257
237k
    if (((total % 256) == 0) &&
12258
237k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12259
237k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12260
#else
12261
        (xmlXPathCmpNodes(cur, *last) >= 0))
12262
#endif
12263
97.9k
    {
12264
97.9k
        break;
12265
97.9k
    }
12266
237k
      }
12267
12268
281M
            total++;
12269
12270
#ifdef DEBUG_STEP
12271
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12272
#endif
12273
12274
281M
      switch (test) {
12275
0
                case NODE_TEST_NONE:
12276
0
        total = 0;
12277
0
                    STRANGE
12278
0
        goto error;
12279
98.2M
                case NODE_TEST_TYPE:
12280
98.2M
        if (type == NODE_TYPE_NODE) {
12281
90.8M
      switch (cur->type) {
12282
1.96M
          case XML_DOCUMENT_NODE:
12283
1.96M
          case XML_HTML_DOCUMENT_NODE:
12284
31.8M
          case XML_ELEMENT_NODE:
12285
31.9M
          case XML_ATTRIBUTE_NODE:
12286
35.7M
          case XML_PI_NODE:
12287
39.8M
          case XML_COMMENT_NODE:
12288
42.1M
          case XML_CDATA_SECTION_NODE:
12289
90.6M
          case XML_TEXT_NODE:
12290
90.6M
        XP_TEST_HIT
12291
90.5M
        break;
12292
90.5M
          case XML_NAMESPACE_DECL: {
12293
174k
        if (axis == AXIS_NAMESPACE) {
12294
53.4k
            XP_TEST_HIT_NS
12295
121k
        } else {
12296
121k
                              hasNsNodes = 1;
12297
121k
            XP_TEST_HIT
12298
121k
        }
12299
166k
        break;
12300
174k
                            }
12301
166k
          default:
12302
0
        break;
12303
90.8M
      }
12304
90.8M
        } else if (cur->type == (xmlElementType) type) {
12305
3.56M
      if (cur->type == XML_NAMESPACE_DECL)
12306
0
          XP_TEST_HIT_NS
12307
3.56M
      else
12308
3.56M
          XP_TEST_HIT
12309
3.84M
        } else if ((type == NODE_TYPE_TEXT) &&
12310
3.84M
       (cur->type == XML_CDATA_SECTION_NODE))
12311
160k
        {
12312
160k
      XP_TEST_HIT
12313
160k
        }
12314
97.9M
        break;
12315
97.9M
                case NODE_TEST_PI:
12316
171k
                    if ((cur->type == XML_PI_NODE) &&
12317
171k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12318
248
        {
12319
248
      XP_TEST_HIT
12320
248
                    }
12321
171k
                    break;
12322
102M
                case NODE_TEST_ALL:
12323
102M
                    if (axis == AXIS_ATTRIBUTE) {
12324
2.64M
                        if (cur->type == XML_ATTRIBUTE_NODE)
12325
2.64M
      {
12326
2.64M
                            if (prefix == NULL)
12327
2.63M
          {
12328
2.63M
        XP_TEST_HIT
12329
2.63M
                            } else if ((cur->ns != NULL) &&
12330
9.08k
        (xmlStrEqual(URI, cur->ns->href)))
12331
0
          {
12332
0
        XP_TEST_HIT
12333
0
                            }
12334
2.64M
                        }
12335
99.8M
                    } else if (axis == AXIS_NAMESPACE) {
12336
1.14M
                        if (cur->type == XML_NAMESPACE_DECL)
12337
1.14M
      {
12338
1.14M
          XP_TEST_HIT_NS
12339
1.14M
                        }
12340
98.6M
                    } else {
12341
98.6M
                        if (cur->type == XML_ELEMENT_NODE) {
12342
50.9M
                            if (prefix == NULL)
12343
50.0M
          {
12344
50.0M
        XP_TEST_HIT
12345
12346
50.0M
                            } else if ((cur->ns != NULL) &&
12347
873k
        (xmlStrEqual(URI, cur->ns->href)))
12348
253k
          {
12349
253k
        XP_TEST_HIT
12350
253k
                            }
12351
50.9M
                        }
12352
98.6M
                    }
12353
101M
                    break;
12354
101M
                case NODE_TEST_NS:{
12355
0
                        TODO;
12356
0
                        break;
12357
102M
                    }
12358
81.0M
                case NODE_TEST_NAME:
12359
81.0M
                    if (axis == AXIS_ATTRIBUTE) {
12360
903k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12361
0
          break;
12362
80.1M
        } else if (axis == AXIS_NAMESPACE) {
12363
1.10M
                        if (cur->type != XML_NAMESPACE_DECL)
12364
0
          break;
12365
79.0M
        } else {
12366
79.0M
            if (cur->type != XML_ELEMENT_NODE)
12367
42.4M
          break;
12368
79.0M
        }
12369
38.5M
                    switch (cur->type) {
12370
36.5M
                        case XML_ELEMENT_NODE:
12371
36.5M
                            if (xmlStrEqual(name, cur->name)) {
12372
2.32M
                                if (prefix == NULL) {
12373
1.90M
                                    if (cur->ns == NULL)
12374
1.22M
            {
12375
1.22M
          XP_TEST_HIT
12376
1.22M
                                    }
12377
1.90M
                                } else {
12378
423k
                                    if ((cur->ns != NULL) &&
12379
423k
                                        (xmlStrEqual(URI, cur->ns->href)))
12380
193k
            {
12381
193k
          XP_TEST_HIT
12382
193k
                                    }
12383
423k
                                }
12384
2.32M
                            }
12385
36.4M
                            break;
12386
36.4M
                        case XML_ATTRIBUTE_NODE:{
12387
903k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12388
12389
903k
                                if (xmlStrEqual(name, attr->name)) {
12390
273k
                                    if (prefix == NULL) {
12391
264k
                                        if ((attr->ns == NULL) ||
12392
264k
                                            (attr->ns->prefix == NULL))
12393
264k
          {
12394
264k
              XP_TEST_HIT
12395
264k
                                        }
12396
264k
                                    } else {
12397
8.94k
                                        if ((attr->ns != NULL) &&
12398
8.94k
                                            (xmlStrEqual(URI,
12399
0
                attr->ns->href)))
12400
0
          {
12401
0
              XP_TEST_HIT
12402
0
                                        }
12403
8.94k
                                    }
12404
273k
                                }
12405
848k
                                break;
12406
903k
                            }
12407
1.10M
                        case XML_NAMESPACE_DECL:
12408
1.10M
                            if (cur->type == XML_NAMESPACE_DECL) {
12409
1.10M
                                xmlNsPtr ns = (xmlNsPtr) cur;
12410
12411
1.10M
                                if ((ns->prefix != NULL) && (name != NULL)
12412
1.10M
                                    && (xmlStrEqual(ns->prefix, name)))
12413
164k
        {
12414
164k
            XP_TEST_HIT_NS
12415
164k
                                }
12416
1.10M
                            }
12417
1.09M
                            break;
12418
1.09M
                        default:
12419
0
                            break;
12420
38.5M
                    }
12421
38.3M
                    break;
12422
281M
      } /* switch(test) */
12423
281M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12424
12425
84.0M
  goto apply_predicates;
12426
12427
84.0M
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
644k
  if (outSeq == NULL) {
12435
202k
      outSeq = seq;
12436
202k
      seq = NULL;
12437
202k
  } else
12438
            /* TODO: Check memory error. */
12439
442k
      outSeq = mergeAndClear(outSeq, seq);
12440
  /*
12441
  * Break if only a true/false result was requested.
12442
  */
12443
644k
  if (toBool)
12444
18.4k
      break;
12445
626k
  continue;
12446
12447
958k
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
958k
  if (outSeq == NULL) {
12453
958k
      outSeq = seq;
12454
958k
      seq = NULL;
12455
958k
  } else
12456
            /* TODO: Check memory error. */
12457
0
      outSeq = mergeAndClear(outSeq, seq);
12458
958k
  break;
12459
12460
#ifdef DEBUG_STEP
12461
  if (seq != NULL)
12462
      nbMatches += seq->nodeNr;
12463
#endif
12464
12465
84.0M
apply_predicates: /* --------------------------------------------------- */
12466
84.0M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12467
0
      goto error;
12468
12469
        /*
12470
  * Apply predicates.
12471
  */
12472
84.0M
        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
3.79M
      if (hasPredicateRange != 0)
12502
812k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12503
812k
              hasNsNodes);
12504
2.98M
      else
12505
2.98M
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12506
2.98M
              hasNsNodes);
12507
12508
3.79M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12509
46.7k
    total = 0;
12510
46.7k
    goto error;
12511
46.7k
      }
12512
3.79M
        }
12513
12514
83.9M
        if (seq->nodeNr > 0) {
12515
      /*
12516
      * Add to result set.
12517
      */
12518
18.7M
      if (outSeq == NULL) {
12519
11.9M
    outSeq = seq;
12520
11.9M
    seq = NULL;
12521
11.9M
      } else {
12522
                /* TODO: Check memory error. */
12523
6.73M
    outSeq = mergeAndClear(outSeq, seq);
12524
6.73M
      }
12525
12526
18.7M
            if (toBool)
12527
26.3k
                break;
12528
18.7M
  }
12529
83.9M
    }
12530
12531
41.2M
error:
12532
41.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
41.2M
    xmlXPathReleaseObject(xpctxt, obj);
12544
12545
    /*
12546
    * Ensure we return at least an empty set.
12547
    */
12548
41.2M
    if (outSeq == NULL) {
12549
28.0M
  if ((seq != NULL) && (seq->nodeNr == 0))
12550
28.0M
      outSeq = seq;
12551
193
  else
12552
            /* TODO: Check memory error. */
12553
193
      outSeq = xmlXPathNodeSetCreate(NULL);
12554
28.0M
    }
12555
41.2M
    if ((seq != NULL) && (seq != outSeq)) {
12556
1.40M
   xmlXPathFreeNodeSet(seq);
12557
1.40M
    }
12558
    /*
12559
    * Hand over the result. Better to push the set also in
12560
    * case of errors.
12561
    */
12562
41.2M
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12563
    /*
12564
    * Reset the context node.
12565
    */
12566
41.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
41.2M
    if (xpctxt->tmpNsList != NULL) {
12572
31.8k
        xmlFree(xpctxt->tmpNsList);
12573
31.8k
        xpctxt->tmpNsList = NULL;
12574
31.8k
    }
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
41.2M
    return(total);
12583
41.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
1.22M
{
12604
1.22M
    int total = 0, cur;
12605
1.22M
    xmlXPathCompExprPtr comp;
12606
1.22M
    xmlXPathObjectPtr arg1, arg2;
12607
12608
1.22M
    CHECK_ERROR0;
12609
1.22M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12610
0
        return(0);
12611
1.22M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12612
1.22M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12613
1.22M
    ctxt->context->depth += 1;
12614
1.22M
    comp = ctxt->comp;
12615
1.22M
    switch (op->op) {
12616
0
        case XPATH_OP_END:
12617
0
            break;
12618
390k
        case XPATH_OP_UNION:
12619
390k
            total =
12620
390k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12621
390k
                                        first);
12622
390k
      CHECK_ERROR0;
12623
304k
            if ((ctxt->value != NULL)
12624
304k
                && (ctxt->value->type == XPATH_NODESET)
12625
304k
                && (ctxt->value->nodesetval != NULL)
12626
304k
                && (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
139k
    if (ctxt->value->nodesetval->nodeNr > 1)
12638
35.6k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12639
139k
                *first = ctxt->value->nodesetval->nodeTab[0];
12640
139k
            }
12641
304k
            cur =
12642
304k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12643
304k
                                        first);
12644
304k
      CHECK_ERROR0;
12645
12646
296k
            arg2 = valuePop(ctxt);
12647
296k
            arg1 = valuePop(ctxt);
12648
296k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12649
296k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12650
7.01k
          xmlXPathReleaseObject(ctxt->context, arg1);
12651
7.01k
          xmlXPathReleaseObject(ctxt->context, arg2);
12652
7.01k
                XP_ERROR0(XPATH_INVALID_TYPE);
12653
0
            }
12654
289k
            if ((ctxt->context->opLimit != 0) &&
12655
289k
                (((arg1->nodesetval != NULL) &&
12656
289k
                  (xmlXPathCheckOpLimit(ctxt,
12657
244k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12658
289k
                 ((arg2->nodesetval != NULL) &&
12659
289k
                  (xmlXPathCheckOpLimit(ctxt,
12660
238k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12661
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12662
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12663
0
                break;
12664
0
            }
12665
12666
            /* TODO: Check memory error. */
12667
289k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12668
289k
                                                    arg2->nodesetval);
12669
289k
            valuePush(ctxt, arg1);
12670
289k
      xmlXPathReleaseObject(ctxt->context, arg2);
12671
            /* optimizer */
12672
289k
      if (total > cur)
12673
65.4k
    xmlXPathCompSwap(op);
12674
289k
            total += cur;
12675
289k
            break;
12676
38.3k
        case XPATH_OP_ROOT:
12677
38.3k
            xmlXPathRoot(ctxt);
12678
38.3k
            break;
12679
40.8k
        case XPATH_OP_NODE:
12680
40.8k
            if (op->ch1 != -1)
12681
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12682
40.8k
      CHECK_ERROR0;
12683
40.8k
            if (op->ch2 != -1)
12684
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12685
40.8k
      CHECK_ERROR0;
12686
40.8k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12687
40.8k
    ctxt->context->node));
12688
40.8k
            break;
12689
360k
        case XPATH_OP_COLLECT:{
12690
360k
                if (op->ch1 == -1)
12691
0
                    break;
12692
12693
360k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12694
360k
    CHECK_ERROR0;
12695
12696
355k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12697
355k
                break;
12698
360k
            }
12699
8.50k
        case XPATH_OP_VALUE:
12700
8.50k
            valuePush(ctxt,
12701
8.50k
                      xmlXPathCacheObjectCopy(ctxt->context,
12702
8.50k
      (xmlXPathObjectPtr) op->value4));
12703
8.50k
            break;
12704
167k
        case XPATH_OP_SORT:
12705
167k
            if (op->ch1 != -1)
12706
167k
                total +=
12707
167k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12708
167k
                                            first);
12709
167k
      CHECK_ERROR0;
12710
144k
            if ((ctxt->value != NULL)
12711
144k
                && (ctxt->value->type == XPATH_NODESET)
12712
144k
                && (ctxt->value->nodesetval != NULL)
12713
144k
    && (ctxt->value->nodesetval->nodeNr > 1))
12714
26.6k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12715
144k
            break;
12716
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12717
192k
  case XPATH_OP_FILTER:
12718
192k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12719
192k
            break;
12720
0
#endif
12721
22.2k
        default:
12722
22.2k
            total += xmlXPathCompOpEval(ctxt, op);
12723
22.2k
            break;
12724
1.22M
    }
12725
12726
1.09M
    ctxt->context->depth -= 1;
12727
1.09M
    return(total);
12728
1.22M
}
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
961k
{
12745
961k
    int total = 0, cur;
12746
961k
    xmlXPathCompExprPtr comp;
12747
961k
    xmlXPathObjectPtr arg1, arg2;
12748
12749
961k
    CHECK_ERROR0;
12750
961k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12751
0
        return(0);
12752
961k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12753
961k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12754
961k
    ctxt->context->depth += 1;
12755
961k
    comp = ctxt->comp;
12756
961k
    switch (op->op) {
12757
0
        case XPATH_OP_END:
12758
0
            break;
12759
384k
        case XPATH_OP_UNION:
12760
384k
            total =
12761
384k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12762
384k
      CHECK_ERROR0;
12763
330k
            if ((ctxt->value != NULL)
12764
330k
                && (ctxt->value->type == XPATH_NODESET)
12765
330k
                && (ctxt->value->nodesetval != NULL)
12766
330k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12767
                /*
12768
                 * limit tree traversing to first node in the result
12769
                 */
12770
146k
    if (ctxt->value->nodesetval->nodeNr > 1)
12771
53.9k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12772
146k
                *last =
12773
146k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12774
146k
                                                     nodesetval->nodeNr -
12775
146k
                                                     1];
12776
146k
            }
12777
330k
            cur =
12778
330k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12779
330k
      CHECK_ERROR0;
12780
324k
            if ((ctxt->value != NULL)
12781
324k
                && (ctxt->value->type == XPATH_NODESET)
12782
324k
                && (ctxt->value->nodesetval != NULL)
12783
324k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12784
193k
            }
12785
12786
324k
            arg2 = valuePop(ctxt);
12787
324k
            arg1 = valuePop(ctxt);
12788
324k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12789
324k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12790
4.37k
          xmlXPathReleaseObject(ctxt->context, arg1);
12791
4.37k
          xmlXPathReleaseObject(ctxt->context, arg2);
12792
4.37k
                XP_ERROR0(XPATH_INVALID_TYPE);
12793
0
            }
12794
319k
            if ((ctxt->context->opLimit != 0) &&
12795
319k
                (((arg1->nodesetval != NULL) &&
12796
319k
                  (xmlXPathCheckOpLimit(ctxt,
12797
258k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12798
319k
                 ((arg2->nodesetval != NULL) &&
12799
319k
                  (xmlXPathCheckOpLimit(ctxt,
12800
284k
                                        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
319k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12808
319k
                                                    arg2->nodesetval);
12809
319k
            valuePush(ctxt, arg1);
12810
319k
      xmlXPathReleaseObject(ctxt->context, arg2);
12811
            /* optimizer */
12812
319k
      if (total > cur)
12813
70.7k
    xmlXPathCompSwap(op);
12814
319k
            total += cur;
12815
319k
            break;
12816
35.2k
        case XPATH_OP_ROOT:
12817
35.2k
            xmlXPathRoot(ctxt);
12818
35.2k
            break;
12819
38.4k
        case XPATH_OP_NODE:
12820
38.4k
            if (op->ch1 != -1)
12821
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12822
38.4k
      CHECK_ERROR0;
12823
38.4k
            if (op->ch2 != -1)
12824
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12825
38.4k
      CHECK_ERROR0;
12826
38.4k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12827
38.4k
    ctxt->context->node));
12828
38.4k
            break;
12829
356k
        case XPATH_OP_COLLECT:{
12830
356k
                if (op->ch1 == -1)
12831
0
                    break;
12832
12833
356k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12834
356k
    CHECK_ERROR0;
12835
12836
352k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12837
352k
                break;
12838
356k
            }
12839
5.25k
        case XPATH_OP_VALUE:
12840
5.25k
            valuePush(ctxt,
12841
5.25k
                      xmlXPathCacheObjectCopy(ctxt->context,
12842
5.25k
      (xmlXPathObjectPtr) op->value4));
12843
5.25k
            break;
12844
123k
        case XPATH_OP_SORT:
12845
123k
            if (op->ch1 != -1)
12846
123k
                total +=
12847
123k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12848
123k
                                           last);
12849
123k
      CHECK_ERROR0;
12850
107k
            if ((ctxt->value != NULL)
12851
107k
                && (ctxt->value->type == XPATH_NODESET)
12852
107k
                && (ctxt->value->nodesetval != NULL)
12853
107k
    && (ctxt->value->nodesetval->nodeNr > 1))
12854
25.7k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12855
107k
            break;
12856
18.2k
        default:
12857
18.2k
            total += xmlXPathCompOpEval(ctxt, op);
12858
18.2k
            break;
12859
961k
    }
12860
12861
876k
    ctxt->context->depth -= 1;
12862
876k
    return (total);
12863
961k
}
12864
12865
#ifdef XP_OPTIMIZED_FILTER_FIRST
12866
static int
12867
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12868
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12869
192k
{
12870
192k
    int total = 0;
12871
192k
    xmlXPathCompExprPtr comp;
12872
192k
    xmlNodeSetPtr set;
12873
12874
192k
    CHECK_ERROR0;
12875
192k
    comp = ctxt->comp;
12876
    /*
12877
    * Optimization for ()[last()] selection i.e. the last elem
12878
    */
12879
192k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12880
192k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12881
192k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12882
136k
  int f = comp->steps[op->ch2].ch1;
12883
12884
136k
  if ((f != -1) &&
12885
136k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12886
136k
      (comp->steps[f].value5 == NULL) &&
12887
136k
      (comp->steps[f].value == 0) &&
12888
136k
      (comp->steps[f].value4 != NULL) &&
12889
136k
      (xmlStrEqual
12890
67.4k
      (comp->steps[f].value4, BAD_CAST "last"))) {
12891
51.4k
      xmlNodePtr last = NULL;
12892
12893
51.4k
      total +=
12894
51.4k
    xmlXPathCompOpEvalLast(ctxt,
12895
51.4k
        &comp->steps[op->ch1],
12896
51.4k
        &last);
12897
51.4k
      CHECK_ERROR0;
12898
      /*
12899
      * The nodeset should be in document order,
12900
      * Keep only the last value
12901
      */
12902
46.5k
      if ((ctxt->value != NULL) &&
12903
46.5k
    (ctxt->value->type == XPATH_NODESET) &&
12904
46.5k
    (ctxt->value->nodesetval != NULL) &&
12905
46.5k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12906
46.5k
    (ctxt->value->nodesetval->nodeNr > 1)) {
12907
8.90k
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12908
8.90k
    *first = *(ctxt->value->nodesetval->nodeTab);
12909
8.90k
      }
12910
46.5k
      return (total);
12911
51.4k
  }
12912
136k
    }
12913
12914
141k
    if (op->ch1 != -1)
12915
141k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12916
141k
    CHECK_ERROR0;
12917
124k
    if (op->ch2 == -1)
12918
0
  return (total);
12919
124k
    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
124k
    CHECK_TYPE0(XPATH_NODESET);
12940
112k
    set = ctxt->value->nodesetval;
12941
112k
    if (set != NULL) {
12942
88.9k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12943
88.9k
        if (set->nodeNr > 0)
12944
17.6k
            *first = set->nodeTab[0];
12945
88.9k
    }
12946
12947
112k
    return (total);
12948
124k
}
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
209M
{
12962
209M
    int total = 0;
12963
209M
    int equal, ret;
12964
209M
    xmlXPathCompExprPtr comp;
12965
209M
    xmlXPathObjectPtr arg1, arg2;
12966
12967
209M
    CHECK_ERROR0;
12968
209M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12969
26
        return(0);
12970
209M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12971
209M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12972
209M
    ctxt->context->depth += 1;
12973
209M
    comp = ctxt->comp;
12974
209M
    switch (op->op) {
12975
0
        case XPATH_OP_END:
12976
0
            break;
12977
179k
        case XPATH_OP_AND:
12978
179k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12979
179k
      CHECK_ERROR0;
12980
159k
            xmlXPathBooleanFunction(ctxt, 1);
12981
159k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12982
105k
                break;
12983
54.5k
            arg2 = valuePop(ctxt);
12984
54.5k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12985
54.5k
      if (ctxt->error) {
12986
7.21k
    xmlXPathFreeObject(arg2);
12987
7.21k
    break;
12988
7.21k
      }
12989
47.3k
            xmlXPathBooleanFunction(ctxt, 1);
12990
47.3k
            if (ctxt->value != NULL)
12991
47.3k
                ctxt->value->boolval &= arg2->boolval;
12992
47.3k
      xmlXPathReleaseObject(ctxt->context, arg2);
12993
47.3k
            break;
12994
237k
        case XPATH_OP_OR:
12995
237k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12996
237k
      CHECK_ERROR0;
12997
201k
            xmlXPathBooleanFunction(ctxt, 1);
12998
201k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12999
75.8k
                break;
13000
125k
            arg2 = valuePop(ctxt);
13001
125k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13002
125k
      if (ctxt->error) {
13003
18.2k
    xmlXPathFreeObject(arg2);
13004
18.2k
    break;
13005
18.2k
      }
13006
107k
            xmlXPathBooleanFunction(ctxt, 1);
13007
107k
            if (ctxt->value != NULL)
13008
107k
                ctxt->value->boolval |= arg2->boolval;
13009
107k
      xmlXPathReleaseObject(ctxt->context, arg2);
13010
107k
            break;
13011
9.25M
        case XPATH_OP_EQUAL:
13012
9.25M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13013
9.25M
      CHECK_ERROR0;
13014
9.01M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13015
9.01M
      CHECK_ERROR0;
13016
8.77M
      if (op->value)
13017
6.74M
    equal = xmlXPathEqualValues(ctxt);
13018
2.02M
      else
13019
2.02M
    equal = xmlXPathNotEqualValues(ctxt);
13020
8.77M
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13021
8.77M
            break;
13022
4.70M
        case XPATH_OP_CMP:
13023
4.70M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024
4.70M
      CHECK_ERROR0;
13025
4.53M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13026
4.53M
      CHECK_ERROR0;
13027
4.44M
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13028
4.44M
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13029
4.44M
            break;
13030
14.2M
        case XPATH_OP_PLUS:
13031
14.2M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13032
14.2M
      CHECK_ERROR0;
13033
13.9M
            if (op->ch2 != -1) {
13034
7.74M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13035
7.74M
      }
13036
13.9M
      CHECK_ERROR0;
13037
13.9M
            if (op->value == 0)
13038
6.47M
                xmlXPathSubValues(ctxt);
13039
7.44M
            else if (op->value == 1)
13040
1.20M
                xmlXPathAddValues(ctxt);
13041
6.23M
            else if (op->value == 2)
13042
3.86M
                xmlXPathValueFlipSign(ctxt);
13043
2.36M
            else if (op->value == 3) {
13044
2.36M
                CAST_TO_NUMBER;
13045
2.36M
                CHECK_TYPE0(XPATH_NUMBER);
13046
2.36M
            }
13047
13.9M
            break;
13048
16.6M
        case XPATH_OP_MULT:
13049
16.6M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13050
16.6M
      CHECK_ERROR0;
13051
14.1M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13052
14.1M
      CHECK_ERROR0;
13053
14.1M
            if (op->value == 0)
13054
13.9M
                xmlXPathMultValues(ctxt);
13055
170k
            else if (op->value == 1)
13056
69.8k
                xmlXPathDivValues(ctxt);
13057
100k
            else if (op->value == 2)
13058
100k
                xmlXPathModValues(ctxt);
13059
14.1M
            break;
13060
10.0M
        case XPATH_OP_UNION:
13061
10.0M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13062
10.0M
      CHECK_ERROR0;
13063
9.40M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13064
9.40M
      CHECK_ERROR0;
13065
13066
9.19M
            arg2 = valuePop(ctxt);
13067
9.19M
            arg1 = valuePop(ctxt);
13068
9.19M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13069
9.19M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13070
75.2k
          xmlXPathReleaseObject(ctxt->context, arg1);
13071
75.2k
          xmlXPathReleaseObject(ctxt->context, arg2);
13072
75.2k
                XP_ERROR0(XPATH_INVALID_TYPE);
13073
0
            }
13074
9.12M
            if ((ctxt->context->opLimit != 0) &&
13075
9.12M
                (((arg1->nodesetval != NULL) &&
13076
9.12M
                  (xmlXPathCheckOpLimit(ctxt,
13077
7.65M
                                        arg1->nodesetval->nodeNr) < 0)) ||
13078
9.12M
                 ((arg2->nodesetval != NULL) &&
13079
9.12M
                  (xmlXPathCheckOpLimit(ctxt,
13080
7.28M
                                        arg2->nodesetval->nodeNr) < 0)))) {
13081
7
          xmlXPathReleaseObject(ctxt->context, arg1);
13082
7
          xmlXPathReleaseObject(ctxt->context, arg2);
13083
7
                break;
13084
7
            }
13085
13086
9.12M
      if ((arg1->nodesetval == NULL) ||
13087
9.12M
    ((arg2->nodesetval != NULL) &&
13088
7.65M
     (arg2->nodesetval->nodeNr != 0)))
13089
4.19M
      {
13090
                /* TODO: Check memory error. */
13091
4.19M
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13092
4.19M
              arg2->nodesetval);
13093
4.19M
      }
13094
13095
9.12M
            valuePush(ctxt, arg1);
13096
9.12M
      xmlXPathReleaseObject(ctxt->context, arg2);
13097
9.12M
            break;
13098
10.9M
        case XPATH_OP_ROOT:
13099
10.9M
            xmlXPathRoot(ctxt);
13100
10.9M
            break;
13101
32.4M
        case XPATH_OP_NODE:
13102
32.4M
            if (op->ch1 != -1)
13103
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13104
32.4M
      CHECK_ERROR0;
13105
32.4M
            if (op->ch2 != -1)
13106
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13107
32.4M
      CHECK_ERROR0;
13108
32.4M
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13109
32.4M
    ctxt->context->node));
13110
32.4M
            break;
13111
47.3M
        case XPATH_OP_COLLECT:{
13112
47.3M
                if (op->ch1 == -1)
13113
0
                    break;
13114
13115
47.3M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13116
47.3M
    CHECK_ERROR0;
13117
13118
47.0M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13119
47.0M
                break;
13120
47.3M
            }
13121
20.8M
        case XPATH_OP_VALUE:
13122
20.8M
            valuePush(ctxt,
13123
20.8M
                      xmlXPathCacheObjectCopy(ctxt->context,
13124
20.8M
      (xmlXPathObjectPtr) op->value4));
13125
20.8M
            break;
13126
54.8k
        case XPATH_OP_VARIABLE:{
13127
54.8k
    xmlXPathObjectPtr val;
13128
13129
54.8k
                if (op->ch1 != -1)
13130
0
                    total +=
13131
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13132
54.8k
                if (op->value5 == NULL) {
13133
42.7k
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13134
42.7k
        if (val == NULL)
13135
42.7k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13136
0
                    valuePush(ctxt, val);
13137
12.1k
    } else {
13138
12.1k
                    const xmlChar *URI;
13139
13140
12.1k
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13141
12.1k
                    if (URI == NULL) {
13142
6.80k
                        xmlGenericError(xmlGenericErrorContext,
13143
6.80k
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13144
6.80k
                                    (char *) op->value4, (char *)op->value5);
13145
6.80k
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13146
6.80k
                        break;
13147
6.80k
                    }
13148
5.31k
        val = xmlXPathVariableLookupNS(ctxt->context,
13149
5.31k
                                                       op->value4, URI);
13150
5.31k
        if (val == NULL)
13151
5.31k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13152
0
                    valuePush(ctxt, val);
13153
0
                }
13154
0
                break;
13155
54.8k
            }
13156
13.7M
        case XPATH_OP_FUNCTION:{
13157
13.7M
                xmlXPathFunction func;
13158
13.7M
                const xmlChar *oldFunc, *oldFuncURI;
13159
13.7M
    int i;
13160
13.7M
                int frame;
13161
13162
13.7M
                frame = xmlXPathSetFrame(ctxt);
13163
13.7M
                if (op->ch1 != -1) {
13164
11.7M
                    total +=
13165
11.7M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13166
11.7M
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13167
144k
                        xmlXPathPopFrame(ctxt, frame);
13168
144k
                        break;
13169
144k
                    }
13170
11.7M
                }
13171
13.6M
    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
31.3M
    for (i = 0; i < op->value; i++) {
13179
17.7M
        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
17.7M
                }
13187
13.6M
                if (op->cache != NULL)
13188
12.5M
                    func = op->cache;
13189
1.03M
                else {
13190
1.03M
                    const xmlChar *URI = NULL;
13191
13192
1.03M
                    if (op->value5 == NULL)
13193
580k
                        func =
13194
580k
                            xmlXPathFunctionLookup(ctxt->context,
13195
580k
                                                   op->value4);
13196
453k
                    else {
13197
453k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13198
453k
                        if (URI == NULL) {
13199
54.8k
                            xmlGenericError(xmlGenericErrorContext,
13200
54.8k
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13201
54.8k
                                    (char *)op->value4, (char *)op->value5);
13202
54.8k
                            xmlXPathPopFrame(ctxt, frame);
13203
54.8k
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13204
54.8k
                            break;
13205
54.8k
                        }
13206
398k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13207
398k
                                                        op->value4, URI);
13208
398k
                    }
13209
979k
                    if (func == NULL) {
13210
229k
                        xmlGenericError(xmlGenericErrorContext,
13211
229k
                                "xmlXPathCompOpEval: function %s not found\n",
13212
229k
                                        (char *)op->value4);
13213
229k
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13214
0
                    }
13215
749k
                    op->cache = func;
13216
749k
                    op->cacheURI = (void *) URI;
13217
749k
                }
13218
13.3M
                oldFunc = ctxt->context->function;
13219
13.3M
                oldFuncURI = ctxt->context->functionURI;
13220
13.3M
                ctxt->context->function = op->value4;
13221
13.3M
                ctxt->context->functionURI = op->cacheURI;
13222
13.3M
                func(ctxt, op->value);
13223
13.3M
                ctxt->context->function = oldFunc;
13224
13.3M
                ctxt->context->functionURI = oldFuncURI;
13225
13.3M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13226
13.3M
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13227
13.3M
                    XP_ERROR0(XPATH_STACK_ERROR);
13228
13.3M
                xmlXPathPopFrame(ctxt, frame);
13229
13.3M
                break;
13230
13.3M
            }
13231
17.9M
        case XPATH_OP_ARG:
13232
17.9M
            if (op->ch1 != -1) {
13233
6.19M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13234
6.19M
          CHECK_ERROR0;
13235
6.19M
            }
13236
17.9M
            if (op->ch2 != -1) {
13237
17.9M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238
17.9M
          CHECK_ERROR0;
13239
17.9M
      }
13240
17.7M
            break;
13241
17.7M
        case XPATH_OP_PREDICATE:
13242
1.07M
        case XPATH_OP_FILTER:{
13243
1.07M
                xmlNodeSetPtr set;
13244
13245
                /*
13246
                 * Optimization for ()[1] selection i.e. the first elem
13247
                 */
13248
1.07M
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13249
1.07M
#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
1.07M
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13260
1.07M
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13261
#else
13262
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13263
#endif
13264
1.07M
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13265
439k
                    xmlXPathObjectPtr val;
13266
13267
439k
                    val = comp->steps[op->ch2].value4;
13268
439k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13269
439k
                        (val->floatval == 1.0)) {
13270
359k
                        xmlNodePtr first = NULL;
13271
13272
359k
                        total +=
13273
359k
                            xmlXPathCompOpEvalFirst(ctxt,
13274
359k
                                                    &comp->steps[op->ch1],
13275
359k
                                                    &first);
13276
359k
      CHECK_ERROR0;
13277
                        /*
13278
                         * The nodeset should be in document order,
13279
                         * Keep only the first value
13280
                         */
13281
300k
                        if ((ctxt->value != NULL) &&
13282
300k
                            (ctxt->value->type == XPATH_NODESET) &&
13283
300k
                            (ctxt->value->nodesetval != NULL) &&
13284
300k
                            (ctxt->value->nodesetval->nodeNr > 1))
13285
26.6k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13286
26.6k
                                                        1, 1);
13287
300k
                        break;
13288
359k
                    }
13289
439k
                }
13290
                /*
13291
                 * Optimization for ()[last()] selection i.e. the last elem
13292
                 */
13293
715k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13294
715k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13295
715k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13296
476k
                    int f = comp->steps[op->ch2].ch1;
13297
13298
476k
                    if ((f != -1) &&
13299
476k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13300
476k
                        (comp->steps[f].value5 == NULL) &&
13301
476k
                        (comp->steps[f].value == 0) &&
13302
476k
                        (comp->steps[f].value4 != NULL) &&
13303
476k
                        (xmlStrEqual
13304
82.3k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13305
71.8k
                        xmlNodePtr last = NULL;
13306
13307
71.8k
                        total +=
13308
71.8k
                            xmlXPathCompOpEvalLast(ctxt,
13309
71.8k
                                                   &comp->steps[op->ch1],
13310
71.8k
                                                   &last);
13311
71.8k
      CHECK_ERROR0;
13312
                        /*
13313
                         * The nodeset should be in document order,
13314
                         * Keep only the last value
13315
                         */
13316
60.7k
                        if ((ctxt->value != NULL) &&
13317
60.7k
                            (ctxt->value->type == XPATH_NODESET) &&
13318
60.7k
                            (ctxt->value->nodesetval != NULL) &&
13319
60.7k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13320
60.7k
                            (ctxt->value->nodesetval->nodeNr > 1))
13321
16.8k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13322
60.7k
                        break;
13323
71.8k
                    }
13324
476k
                }
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
644k
                if (op->ch1 != -1)
13337
644k
                    total +=
13338
644k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13339
644k
    CHECK_ERROR0;
13340
591k
                if (op->ch2 == -1)
13341
0
                    break;
13342
591k
                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
591k
                CHECK_TYPE0(XPATH_NODESET);
13358
570k
                set = ctxt->value->nodesetval;
13359
570k
                if (set != NULL)
13360
540k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13361
540k
                                          1, set->nodeNr, 1);
13362
570k
                break;
13363
591k
            }
13364
9.58M
        case XPATH_OP_SORT:
13365
9.58M
            if (op->ch1 != -1)
13366
9.58M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13367
9.58M
      CHECK_ERROR0;
13368
8.57M
            if ((ctxt->value != NULL) &&
13369
8.57M
                (ctxt->value->type == XPATH_NODESET) &&
13370
8.57M
                (ctxt->value->nodesetval != NULL) &&
13371
8.57M
    (ctxt->value->nodesetval->nodeNr > 1))
13372
1.84M
      {
13373
1.84M
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13374
1.84M
      }
13375
8.57M
            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
209M
    }
13541
13542
202M
    ctxt->context->depth -= 1;
13543
202M
    return (total);
13544
209M
}
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
12.4M
{
13559
12.4M
    xmlXPathObjectPtr resObj = NULL;
13560
13561
13.7M
start:
13562
13.7M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13563
0
        return(0);
13564
    /* comp = ctxt->comp; */
13565
13.7M
    switch (op->op) {
13566
0
        case XPATH_OP_END:
13567
0
            return (0);
13568
485k
  case XPATH_OP_VALUE:
13569
485k
      resObj = (xmlXPathObjectPtr) op->value4;
13570
485k
      if (isPredicate)
13571
485k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13572
0
      return(xmlXPathCastToBoolean(resObj));
13573
1.29M
  case XPATH_OP_SORT:
13574
      /*
13575
      * We don't need sorting for boolean results. Skip this one.
13576
      */
13577
1.29M
            if (op->ch1 != -1) {
13578
1.29M
    op = &ctxt->comp->steps[op->ch1];
13579
1.29M
    goto start;
13580
1.29M
      }
13581
0
      return(0);
13582
2.98M
  case XPATH_OP_COLLECT:
13583
2.98M
      if (op->ch1 == -1)
13584
0
    return(0);
13585
13586
2.98M
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13587
2.98M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13588
4.58k
    return(-1);
13589
13590
2.97M
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13591
2.97M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13592
7.55k
    return(-1);
13593
13594
2.96M
      resObj = valuePop(ctxt);
13595
2.96M
      if (resObj == NULL)
13596
0
    return(-1);
13597
2.96M
      break;
13598
9.02M
  default:
13599
      /*
13600
      * Fallback to call xmlXPathCompOpEval().
13601
      */
13602
9.02M
      xmlXPathCompOpEval(ctxt, op);
13603
9.02M
      if (ctxt->error != XPATH_EXPRESSION_OK)
13604
43.2k
    return(-1);
13605
13606
8.98M
      resObj = valuePop(ctxt);
13607
8.98M
      if (resObj == NULL)
13608
0
    return(-1);
13609
8.98M
      break;
13610
13.7M
    }
13611
13612
11.9M
    if (resObj) {
13613
11.9M
  int res;
13614
13615
11.9M
  if (resObj->type == XPATH_BOOLEAN) {
13616
4.61M
      res = resObj->boolval;
13617
7.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
7.33M
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13627
7.33M
  } else {
13628
0
      res = xmlXPathCastToBoolean(resObj);
13629
0
  }
13630
11.9M
  xmlXPathReleaseObject(ctxt->context, resObj);
13631
11.9M
  return(res);
13632
11.9M
    }
13633
13634
0
    return(0);
13635
11.9M
}
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
2.66M
{
13648
2.66M
    int max_depth, min_depth;
13649
2.66M
    int from_root;
13650
2.66M
    int ret, depth;
13651
2.66M
    int eval_all_nodes;
13652
2.66M
    xmlNodePtr cur = NULL, limit = NULL;
13653
2.66M
    xmlStreamCtxtPtr patstream = NULL;
13654
13655
2.66M
    if ((ctxt == NULL) || (comp == NULL))
13656
0
        return(-1);
13657
2.66M
    max_depth = xmlPatternMaxDepth(comp);
13658
2.66M
    if (max_depth == -1)
13659
0
        return(-1);
13660
2.66M
    if (max_depth == -2)
13661
329k
        max_depth = 10000;
13662
2.66M
    min_depth = xmlPatternMinDepth(comp);
13663
2.66M
    if (min_depth == -1)
13664
0
        return(-1);
13665
2.66M
    from_root = xmlPatternFromRoot(comp);
13666
2.66M
    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
2.66M
    if (! toBool) {
13673
2.66M
  if (resultSeq == NULL)
13674
0
      return(-1);
13675
2.66M
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13676
2.66M
  if (*resultSeq == NULL)
13677
0
      return(-1);
13678
2.66M
    }
13679
13680
    /*
13681
     * handle the special cases of "/" amd "." being matched
13682
     */
13683
2.66M
    if (min_depth == 0) {
13684
144k
  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
144k
  } else {
13692
      /* Select "self::node()" */
13693
144k
      if (toBool)
13694
0
    return(1);
13695
            /* TODO: Check memory error. */
13696
144k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13697
144k
  }
13698
144k
    }
13699
2.66M
    if (max_depth == 0) {
13700
56.7k
  return(0);
13701
56.7k
    }
13702
13703
2.61M
    if (from_root) {
13704
212k
        cur = (xmlNodePtr)ctxt->doc;
13705
2.39M
    } else if (ctxt->node != NULL) {
13706
2.39M
        switch (ctxt->node->type) {
13707
792k
            case XML_ELEMENT_NODE:
13708
1.93M
            case XML_DOCUMENT_NODE:
13709
1.93M
            case XML_DOCUMENT_FRAG_NODE:
13710
1.93M
            case XML_HTML_DOCUMENT_NODE:
13711
1.93M
          cur = ctxt->node;
13712
1.93M
    break;
13713
345
            case XML_ATTRIBUTE_NODE:
13714
376k
            case XML_TEXT_NODE:
13715
393k
            case XML_CDATA_SECTION_NODE:
13716
393k
            case XML_ENTITY_REF_NODE:
13717
393k
            case XML_ENTITY_NODE:
13718
426k
            case XML_PI_NODE:
13719
459k
            case XML_COMMENT_NODE:
13720
459k
            case XML_NOTATION_NODE:
13721
459k
            case XML_DTD_NODE:
13722
459k
            case XML_DOCUMENT_TYPE_NODE:
13723
459k
            case XML_ELEMENT_DECL:
13724
459k
            case XML_ATTRIBUTE_DECL:
13725
459k
            case XML_ENTITY_DECL:
13726
465k
            case XML_NAMESPACE_DECL:
13727
465k
            case XML_XINCLUDE_START:
13728
465k
            case XML_XINCLUDE_END:
13729
465k
    break;
13730
2.39M
  }
13731
2.39M
  limit = cur;
13732
2.39M
    }
13733
2.61M
    if (cur == NULL) {
13734
466k
        return(0);
13735
466k
    }
13736
13737
2.14M
    patstream = xmlPatternGetStreamCtxt(comp);
13738
2.14M
    if (patstream == NULL) {
13739
  /*
13740
  * QUESTION TODO: Is this an error?
13741
  */
13742
0
  return(0);
13743
0
    }
13744
13745
2.14M
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13746
13747
2.14M
    if (from_root) {
13748
211k
  ret = xmlStreamPush(patstream, NULL, NULL);
13749
211k
  if (ret < 0) {
13750
211k
  } else if (ret == 1) {
13751
8.90k
      if (toBool)
13752
0
    goto return_1;
13753
            /* TODO: Check memory error. */
13754
8.90k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13755
8.90k
  }
13756
211k
    }
13757
2.14M
    depth = 0;
13758
2.14M
    goto scan_children;
13759
7.12M
next_node:
13760
12.2M
    do {
13761
12.2M
        if (ctxt->opLimit != 0) {
13762
12.2M
            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
12.2M
            ctxt->opCount++;
13769
12.2M
        }
13770
13771
12.2M
  switch (cur->type) {
13772
4.22M
      case XML_ELEMENT_NODE:
13773
9.88M
      case XML_TEXT_NODE:
13774
10.1M
      case XML_CDATA_SECTION_NODE:
13775
10.6M
      case XML_COMMENT_NODE:
13776
12.2M
      case XML_PI_NODE:
13777
12.2M
    if (cur->type == XML_ELEMENT_NODE) {
13778
4.22M
        ret = xmlStreamPush(patstream, cur->name,
13779
4.22M
        (cur->ns ? cur->ns->href : NULL));
13780
8.03M
    } else if (eval_all_nodes)
13781
849k
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13782
7.18M
    else
13783
7.18M
        break;
13784
13785
5.07M
    if (ret < 0) {
13786
        /* NOP. */
13787
5.07M
    } else if (ret == 1) {
13788
650k
        if (toBool)
13789
0
      goto return_1;
13790
650k
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13791
650k
            < 0) {
13792
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13793
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13794
0
        }
13795
650k
    }
13796
5.07M
    if ((cur->children == NULL) || (depth >= max_depth)) {
13797
3.38M
        ret = xmlStreamPop(patstream);
13798
3.38M
        while (cur->next != NULL) {
13799
1.92M
      cur = cur->next;
13800
1.92M
      if ((cur->type != XML_ENTITY_DECL) &&
13801
1.92M
          (cur->type != XML_DTD_NODE))
13802
1.92M
          goto next_node;
13803
1.92M
        }
13804
3.38M
    }
13805
3.15M
      default:
13806
3.15M
    break;
13807
12.2M
  }
13808
13809
12.4M
scan_children:
13810
12.4M
  if (cur->type == XML_NAMESPACE_DECL) break;
13811
12.4M
  if ((cur->children != NULL) && (depth < max_depth)) {
13812
      /*
13813
       * Do not descend on entities declarations
13814
       */
13815
3.64M
      if (cur->children->type != XML_ENTITY_DECL) {
13816
3.64M
    cur = cur->children;
13817
3.64M
    depth++;
13818
    /*
13819
     * Skip DTDs
13820
     */
13821
3.64M
    if (cur->type != XML_DTD_NODE)
13822
3.64M
        continue;
13823
3.64M
      }
13824
3.64M
  }
13825
13826
8.84M
  if (cur == limit)
13827
190k
      break;
13828
13829
8.65M
  while (cur->next != NULL) {
13830
5.20M
      cur = cur->next;
13831
5.20M
      if ((cur->type != XML_ENTITY_DECL) &&
13832
5.20M
    (cur->type != XML_DTD_NODE))
13833
5.20M
    goto next_node;
13834
5.20M
  }
13835
13836
3.64M
  do {
13837
3.64M
      cur = cur->parent;
13838
3.64M
      depth--;
13839
3.64M
      if ((cur == NULL) || (cur == limit) ||
13840
3.64M
                (cur->type == XML_DOCUMENT_NODE))
13841
1.95M
          goto done;
13842
1.68M
      if (cur->type == XML_ELEMENT_NODE) {
13843
1.68M
    ret = xmlStreamPop(patstream);
13844
1.68M
      } 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
1.68M
      if (cur->next != NULL) {
13853
1.49M
    cur = cur->next;
13854
1.49M
    break;
13855
1.49M
      }
13856
1.68M
  } while (cur != NULL);
13857
13858
5.13M
    } while ((cur != NULL) && (depth >= 0));
13859
13860
2.14M
done:
13861
13862
2.14M
    if (patstream)
13863
2.14M
  xmlFreeStreamCtxt(patstream);
13864
2.14M
    return(0);
13865
13866
0
return_1:
13867
0
    if (patstream)
13868
0
  xmlFreeStreamCtxt(patstream);
13869
0
    return(1);
13870
7.12M
}
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.24M
{
13883
5.24M
    xmlXPathCompExprPtr comp;
13884
5.24M
    int oldDepth;
13885
13886
5.24M
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13887
0
  return(-1);
13888
13889
5.24M
    if (ctxt->valueTab == NULL) {
13890
  /* Allocate the value stack */
13891
20.8k
  ctxt->valueTab = (xmlXPathObjectPtr *)
13892
20.8k
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13893
20.8k
  if (ctxt->valueTab == NULL) {
13894
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13895
0
      return(-1);
13896
0
  }
13897
20.8k
  ctxt->valueNr = 0;
13898
20.8k
  ctxt->valueMax = 10;
13899
20.8k
  ctxt->value = NULL;
13900
20.8k
        ctxt->valueFrame = 0;
13901
20.8k
    }
13902
5.24M
#ifdef XPATH_STREAMING
13903
5.24M
    if (ctxt->comp->stream) {
13904
2.66M
  int res;
13905
13906
2.66M
  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
2.66M
  } else {
13915
2.66M
      xmlXPathObjectPtr resObj = NULL;
13916
13917
      /*
13918
      * Evaluation to a sequence.
13919
      */
13920
2.66M
      res = xmlXPathRunStreamEval(ctxt->context,
13921
2.66M
    ctxt->comp->stream, &resObj, 0);
13922
13923
2.66M
      if ((res != -1) && (resObj != NULL)) {
13924
2.66M
    valuePush(ctxt, resObj);
13925
2.66M
    return(0);
13926
2.66M
      }
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
2.66M
    }
13935
2.58M
#endif
13936
2.58M
    comp = ctxt->comp;
13937
2.58M
    if (comp->last < 0) {
13938
0
  xmlGenericError(xmlGenericErrorContext,
13939
0
      "xmlXPathRunEval: last is less than zero\n");
13940
0
  return(-1);
13941
0
    }
13942
2.58M
    oldDepth = ctxt->context->depth;
13943
2.58M
    if (toBool)
13944
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13945
0
      &comp->steps[comp->last], 0));
13946
2.58M
    else
13947
2.58M
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13948
2.58M
    ctxt->context->depth = oldDepth;
13949
13950
2.58M
    return(0);
13951
2.58M
}
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
7.82M
                                xmlXPathObjectPtr res) {
14016
7.82M
    if ((ctxt == NULL) || (res == NULL)) return(0);
14017
7.82M
    switch (res->type) {
14018
0
        case XPATH_BOOLEAN:
14019
0
      return(res->boolval);
14020
3.41M
        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
3.41M
      return(res->floatval == ctxt->context->proximityPosition);
14026
0
#endif
14027
3.91M
        case XPATH_NODESET:
14028
3.91M
        case XPATH_XSLT_TREE:
14029
3.91M
      if (res->nodesetval == NULL)
14030
138k
    return(0);
14031
3.77M
      return(res->nodesetval->nodeNr != 0);
14032
493k
        case XPATH_STRING:
14033
493k
      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
817
        default:
14043
817
      STRANGE
14044
7.82M
    }
14045
817
    return(0);
14046
7.82M
}
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.31M
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.31M
    xmlPatternPtr stream;
14065
7.31M
    xmlXPathCompExprPtr comp;
14066
7.31M
    xmlDictPtr dict = NULL;
14067
7.31M
    const xmlChar **namespaces = NULL;
14068
7.31M
    xmlNsPtr ns;
14069
7.31M
    int i, j;
14070
14071
7.31M
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14072
7.31M
        (!xmlStrchr(str, '@'))) {
14073
5.71M
  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
5.71M
  tmp = xmlStrchr(str, ':');
14085
5.71M
  if ((tmp != NULL) &&
14086
5.71M
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14087
395k
      return(NULL);
14088
14089
5.31M
  if (ctxt != NULL) {
14090
5.31M
      dict = ctxt->dict;
14091
5.31M
      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
5.31M
  }
14106
14107
5.31M
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14108
5.31M
  if (namespaces != NULL) {
14109
0
      xmlFree((xmlChar **)namespaces);
14110
0
  }
14111
5.31M
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14112
1.29M
      comp = xmlXPathNewCompExpr();
14113
1.29M
      if (comp == NULL) {
14114
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14115
0
    return(NULL);
14116
0
      }
14117
1.29M
      comp->stream = stream;
14118
1.29M
      comp->dict = dict;
14119
1.29M
      if (comp->dict)
14120
0
    xmlDictReference(comp->dict);
14121
1.29M
      return(comp);
14122
1.29M
  }
14123
4.02M
  xmlFreePattern(stream);
14124
4.02M
    }
14125
5.62M
    return(NULL);
14126
7.31M
}
14127
#endif /* XPATH_STREAMING */
14128
14129
static void
14130
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14131
                           xmlXPathStepOpPtr op)
14132
20.9M
{
14133
20.9M
    xmlXPathCompExprPtr comp = pctxt->comp;
14134
20.9M
    xmlXPathContextPtr ctxt;
14135
14136
    /*
14137
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14138
    * internal representation.
14139
    */
14140
14141
20.9M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14142
20.9M
        (op->ch1 != -1) &&
14143
20.9M
        (op->ch2 == -1 /* no predicate */))
14144
5.19M
    {
14145
5.19M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14146
14147
5.19M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14148
5.19M
            ((xmlXPathAxisVal) prevop->value ==
14149
1.74M
                AXIS_DESCENDANT_OR_SELF) &&
14150
5.19M
            (prevop->ch2 == -1) &&
14151
5.19M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14152
5.19M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14153
772k
        {
14154
            /*
14155
            * This is a "descendant-or-self::node()" without predicates.
14156
            * Try to eliminate it.
14157
            */
14158
14159
772k
            switch ((xmlXPathAxisVal) op->value) {
14160
672k
                case AXIS_CHILD:
14161
672k
                case AXIS_DESCENDANT:
14162
                    /*
14163
                    * Convert "descendant-or-self::node()/child::" or
14164
                    * "descendant-or-self::node()/descendant::" to
14165
                    * "descendant::"
14166
                    */
14167
672k
                    op->ch1   = prevop->ch1;
14168
672k
                    op->value = AXIS_DESCENDANT;
14169
672k
                    break;
14170
36
                case AXIS_SELF:
14171
22.2k
                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
22.2k
                    op->ch1   = prevop->ch1;
14178
22.2k
                    op->value = AXIS_DESCENDANT_OR_SELF;
14179
22.2k
                    break;
14180
78.1k
                default:
14181
78.1k
                    break;
14182
772k
            }
14183
772k
  }
14184
5.19M
    }
14185
14186
    /* OP_VALUE has invalid ch1. */
14187
20.9M
    if (op->op == XPATH_OP_VALUE)
14188
1.64M
        return;
14189
14190
    /* Recurse */
14191
19.2M
    ctxt = pctxt->context;
14192
19.2M
    if (ctxt != NULL) {
14193
19.2M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14194
2.58k
            return;
14195
19.2M
        ctxt->depth += 1;
14196
19.2M
    }
14197
19.2M
    if (op->ch1 != -1)
14198
13.4M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14199
19.2M
    if (op->ch2 != -1)
14200
6.77M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14201
19.2M
    if (ctxt != NULL)
14202
19.2M
        ctxt->depth -= 1;
14203
19.2M
}
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.26M
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14217
7.26M
    xmlXPathParserContextPtr pctxt;
14218
7.26M
    xmlXPathCompExprPtr comp;
14219
7.26M
    int oldDepth = 0;
14220
14221
7.26M
#ifdef XPATH_STREAMING
14222
7.26M
    comp = xmlXPathTryStreamCompile(ctxt, str);
14223
7.26M
    if (comp != NULL)
14224
1.28M
        return(comp);
14225
5.97M
#endif
14226
14227
5.97M
    xmlInitParser();
14228
14229
5.97M
    pctxt = xmlXPathNewParserContext(str, ctxt);
14230
5.97M
    if (pctxt == NULL)
14231
0
        return NULL;
14232
5.97M
    if (ctxt != NULL)
14233
5.97M
        oldDepth = ctxt->depth;
14234
5.97M
    xmlXPathCompileExpr(pctxt, 1);
14235
5.97M
    if (ctxt != NULL)
14236
5.97M
        ctxt->depth = oldDepth;
14237
14238
5.97M
    if( pctxt->error != XPATH_EXPRESSION_OK )
14239
4.18M
    {
14240
4.18M
        xmlXPathFreeParserContext(pctxt);
14241
4.18M
        return(NULL);
14242
4.18M
    }
14243
14244
1.79M
    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
954k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14252
954k
  comp = NULL;
14253
954k
    } else {
14254
835k
  comp = pctxt->comp;
14255
835k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14256
653k
            if (ctxt != NULL)
14257
653k
                oldDepth = ctxt->depth;
14258
653k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14259
653k
            if (ctxt != NULL)
14260
653k
                ctxt->depth = oldDepth;
14261
653k
  }
14262
835k
  pctxt->comp = NULL;
14263
835k
    }
14264
1.79M
    xmlXPathFreeParserContext(pctxt);
14265
14266
1.79M
    if (comp != NULL) {
14267
835k
  comp->expr = xmlStrdup(str);
14268
#ifdef DEBUG_EVAL_COUNTS
14269
  comp->string = xmlStrdup(str);
14270
  comp->nb = 0;
14271
#endif
14272
835k
    }
14273
1.79M
    return(comp);
14274
5.97M
}
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.22M
{
14309
5.22M
    xmlXPathParserContextPtr pctxt;
14310
5.22M
    xmlXPathObjectPtr resObj;
14311
#ifndef LIBXML_THREAD_ENABLED
14312
    static int reentance = 0;
14313
#endif
14314
5.22M
    int res;
14315
14316
5.22M
    CHECK_CTXT_NEG(ctxt)
14317
14318
5.22M
    if (comp == NULL)
14319
0
  return(-1);
14320
5.22M
    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.22M
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14336
5.22M
    res = xmlXPathRunEval(pctxt, toBool);
14337
14338
5.22M
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14339
845k
        resObj = NULL;
14340
4.38M
    } else {
14341
4.38M
        resObj = valuePop(pctxt);
14342
4.38M
        if (resObj == NULL) {
14343
0
            if (!toBool)
14344
0
                xmlGenericError(xmlGenericErrorContext,
14345
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14346
4.38M
        } 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.38M
    }
14352
14353
5.22M
    if (resObjPtr)
14354
5.22M
        *resObjPtr = resObj;
14355
3
    else
14356
3
        xmlXPathReleaseObject(ctxt, resObj);
14357
14358
5.22M
    pctxt->comp = NULL;
14359
5.22M
    xmlXPathFreeParserContext(pctxt);
14360
#ifndef LIBXML_THREAD_ENABLED
14361
    reentance--;
14362
#endif
14363
14364
5.22M
    return(res);
14365
5.22M
}
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.22M
{
14380
5.22M
    xmlXPathObjectPtr res = NULL;
14381
14382
5.22M
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14383
5.22M
    return(res);
14384
5.22M
}
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
50.9k
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14413
50.9k
#ifdef XPATH_STREAMING
14414
50.9k
    xmlXPathCompExprPtr comp;
14415
50.9k
#endif
14416
50.9k
    int oldDepth = 0;
14417
14418
50.9k
    if (ctxt == NULL) return;
14419
14420
50.9k
#ifdef XPATH_STREAMING
14421
50.9k
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14422
50.9k
    if (comp != NULL) {
14423
9.79k
        if (ctxt->comp != NULL)
14424
9.79k
      xmlXPathFreeCompExpr(ctxt->comp);
14425
9.79k
        ctxt->comp = comp;
14426
9.79k
    } else
14427
41.1k
#endif
14428
41.1k
    {
14429
41.1k
        if (ctxt->context != NULL)
14430
41.1k
            oldDepth = ctxt->context->depth;
14431
41.1k
  xmlXPathCompileExpr(ctxt, 1);
14432
41.1k
        if (ctxt->context != NULL)
14433
41.1k
            ctxt->context->depth = oldDepth;
14434
41.1k
        CHECK_ERROR;
14435
14436
        /* Check for trailing characters. */
14437
25.4k
        if (*ctxt->cur != 0)
14438
12.7k
            XP_ERROR(XPATH_EXPR_ERROR);
14439
14440
12.7k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14441
9.12k
            if (ctxt->context != NULL)
14442
9.12k
                oldDepth = ctxt->context->depth;
14443
9.12k
      xmlXPathOptimizeExpression(ctxt,
14444
9.12k
    &ctxt->comp->steps[ctxt->comp->last]);
14445
9.12k
            if (ctxt->context != NULL)
14446
9.12k
                ctxt->context->depth = oldDepth;
14447
9.12k
        }
14448
12.7k
    }
14449
14450
22.5k
    xmlXPathRunEval(ctxt, 0);
14451
22.5k
}
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
48.5k
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14465
48.5k
    xmlXPathParserContextPtr ctxt;
14466
48.5k
    xmlXPathObjectPtr res;
14467
14468
48.5k
    CHECK_CTXT(ctx)
14469
14470
48.5k
    xmlInitParser();
14471
14472
48.5k
    ctxt = xmlXPathNewParserContext(str, ctx);
14473
48.5k
    if (ctxt == NULL)
14474
0
        return NULL;
14475
48.5k
    xmlXPathEvalExpr(ctxt);
14476
14477
48.5k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14478
29.8k
  res = NULL;
14479
29.8k
    } else {
14480
18.6k
  res = valuePop(ctxt);
14481
18.6k
        if (res == NULL) {
14482
0
            xmlGenericError(xmlGenericErrorContext,
14483
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14484
18.6k
        } 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
18.6k
    }
14490
14491
48.5k
    xmlXPathFreeParserContext(ctxt);
14492
48.5k
    return(res);
14493
48.5k
}
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
99.3k
{
14676
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14677
99.3k
                         xmlXPathBooleanFunction);
14678
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14679
99.3k
                         xmlXPathCeilingFunction);
14680
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14681
99.3k
                         xmlXPathCountFunction);
14682
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14683
99.3k
                         xmlXPathConcatFunction);
14684
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14685
99.3k
                         xmlXPathContainsFunction);
14686
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14687
99.3k
                         xmlXPathIdFunction);
14688
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14689
99.3k
                         xmlXPathFalseFunction);
14690
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14691
99.3k
                         xmlXPathFloorFunction);
14692
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14693
99.3k
                         xmlXPathLastFunction);
14694
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14695
99.3k
                         xmlXPathLangFunction);
14696
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14697
99.3k
                         xmlXPathLocalNameFunction);
14698
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14699
99.3k
                         xmlXPathNotFunction);
14700
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14701
99.3k
                         xmlXPathNameFunction);
14702
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14703
99.3k
                         xmlXPathNamespaceURIFunction);
14704
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14705
99.3k
                         xmlXPathNormalizeFunction);
14706
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14707
99.3k
                         xmlXPathNumberFunction);
14708
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14709
99.3k
                         xmlXPathPositionFunction);
14710
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14711
99.3k
                         xmlXPathRoundFunction);
14712
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14713
99.3k
                         xmlXPathStringFunction);
14714
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14715
99.3k
                         xmlXPathStringLengthFunction);
14716
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14717
99.3k
                         xmlXPathStartsWithFunction);
14718
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14719
99.3k
                         xmlXPathSubstringFunction);
14720
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14721
99.3k
                         xmlXPathSubstringBeforeFunction);
14722
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14723
99.3k
                         xmlXPathSubstringAfterFunction);
14724
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14725
99.3k
                         xmlXPathSumFunction);
14726
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14727
99.3k
                         xmlXPathTrueFunction);
14728
99.3k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14729
99.3k
                         xmlXPathTranslateFunction);
14730
14731
99.3k
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14732
99.3k
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14733
99.3k
                         xmlXPathEscapeUriFunction);
14734
99.3k
}
14735
14736
#endif /* LIBXML_XPATH_ENABLED */