Coverage Report

Created: 2025-08-26 06:42

/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
14
 */
15
16
/* To avoid EBCDIC trouble when parsing on zOS */
17
#if defined(__MVS__)
18
#pragma convert("ISO8859-1")
19
#endif
20
21
#define IN_LIBXML
22
#include "libxml.h"
23
24
#include <limits.h>
25
#include <string.h>
26
#include <stddef.h>
27
#include <math.h>
28
#include <float.h>
29
#include <ctype.h>
30
31
#include <libxml/xmlmemory.h>
32
#include <libxml/tree.h>
33
#include <libxml/xpath.h>
34
#include <libxml/xpathInternals.h>
35
#include <libxml/parserInternals.h>
36
#include <libxml/hash.h>
37
#ifdef LIBXML_DEBUG_ENABLED
38
#include <libxml/debugXML.h>
39
#endif
40
#include <libxml/xmlerror.h>
41
#include <libxml/threads.h>
42
#ifdef LIBXML_PATTERN_ENABLED
43
#include <libxml/pattern.h>
44
#endif
45
46
#include "private/buf.h"
47
#include "private/error.h"
48
#include "private/memory.h"
49
#include "private/parser.h"
50
#include "private/xpath.h"
51
52
/* Disabled for now */
53
#if 0
54
#ifdef LIBXML_PATTERN_ENABLED
55
#define XPATH_STREAMING
56
#endif
57
#endif
58
59
/**
60
 * Use the Timsort algorithm provided in timsort.h to sort
61
 * nodeset as this is a great improvement over the old Shell sort
62
 * used in #xmlXPathNodeSetSort
63
 */
64
#define WITH_TIM_SORT
65
66
/*
67
* If defined, this will use xmlXPathCmpNodesExt() instead of
68
* xmlXPathCmpNodes(). The new function is optimized comparison of
69
* non-element nodes; actually it will speed up comparison only if
70
* xmlXPathOrderDocElems() was called in order to index the elements of
71
* a tree in document order; Libxslt does such an indexing, thus it will
72
* benefit from this optimization.
73
*/
74
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
75
76
/*
77
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
78
* in a way, that it stop evaluation at the first node.
79
*/
80
#define XP_OPTIMIZED_FILTER_FIRST
81
82
/*
83
 * when compiling an XPath expression we arbitrary limit the maximum
84
 * number of step operation in the compiled expression. 1000000 is
85
 * an insanely large value which should never be reached under normal
86
 * circumstances
87
 */
88
301k
#define XPATH_MAX_STEPS 1000000
89
90
/*
91
 * when evaluating an XPath expression we arbitrary limit the maximum
92
 * number of object allowed to be pushed on the stack. 1000000 is
93
 * an insanely large value which should never be reached under normal
94
 * circumstances
95
 */
96
8.62k
#define XPATH_MAX_STACK_DEPTH 1000000
97
98
/*
99
 * when evaluating an XPath expression nodesets are created and we
100
 * arbitrary limit the maximum length of those node set. 10000000 is
101
 * an insanely large value which should never be reached under normal
102
 * circumstances, one would first need to construct an in memory tree
103
 * with more than 10 millions nodes.
104
 */
105
5.24M
#define XPATH_MAX_NODESET_LENGTH 10000000
106
107
/*
108
 * Maximum amount of nested functions calls when parsing or evaluating
109
 * expressions
110
 */
111
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
112
19.6M
#define XPATH_MAX_RECURSION_DEPTH 500
113
#elif defined(_WIN32)
114
/* Windows typically limits stack size to 1MB. */
115
#define XPATH_MAX_RECURSION_DEPTH 1000
116
#else
117
#define XPATH_MAX_RECURSION_DEPTH 5000
118
#endif
119
120
/*
121
 * TODO:
122
 * There are a few spots where some tests are done which depend upon ascii
123
 * data.  These should be enhanced for full UTF8 support (see particularly
124
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
125
 */
126
127
#if defined(LIBXML_XPATH_ENABLED)
128
129
static void
130
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs);
131
132
static const struct {
133
    const char *name;
134
    xmlXPathFunction func;
135
} xmlXPathStandardFunctions[] = {
136
    { "boolean", xmlXPathBooleanFunction },
137
    { "ceiling", xmlXPathCeilingFunction },
138
    { "count", xmlXPathCountFunction },
139
    { "concat", xmlXPathConcatFunction },
140
    { "contains", xmlXPathContainsFunction },
141
    { "id", xmlXPathIdFunction },
142
    { "false", xmlXPathFalseFunction },
143
    { "floor", xmlXPathFloorFunction },
144
    { "last", xmlXPathLastFunction },
145
    { "lang", xmlXPathLangFunction },
146
    { "local-name", xmlXPathLocalNameFunction },
147
    { "not", xmlXPathNotFunction },
148
    { "name", xmlXPathNameFunction },
149
    { "namespace-uri", xmlXPathNamespaceURIFunction },
150
    { "normalize-space", xmlXPathNormalizeFunction },
151
    { "number", xmlXPathNumberFunction },
152
    { "position", xmlXPathPositionFunction },
153
    { "round", xmlXPathRoundFunction },
154
    { "string", xmlXPathStringFunction },
155
    { "string-length", xmlXPathStringLengthFunction },
156
    { "starts-with", xmlXPathStartsWithFunction },
157
    { "substring", xmlXPathSubstringFunction },
158
    { "substring-before", xmlXPathSubstringBeforeFunction },
159
    { "substring-after", xmlXPathSubstringAfterFunction },
160
    { "sum", xmlXPathSumFunction },
161
    { "true", xmlXPathTrueFunction },
162
    { "translate", xmlXPathTranslateFunction }
163
};
164
165
#define NUM_STANDARD_FUNCTIONS \
166
296k
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
1.07M
#define SF_HASH_SIZE 64
169
170
static unsigned char xmlXPathSFHash[SF_HASH_SIZE];
171
172
double xmlXPathNAN = 0.0;
173
double xmlXPathPINF = 0.0;
174
double xmlXPathNINF = 0.0;
175
176
/**
177
 * @deprecated Alias for #xmlInitParser.
178
 */
179
void
180
0
xmlXPathInit(void) {
181
0
    xmlInitParser();
182
0
}
183
184
ATTRIBUTE_NO_SANITIZE_INTEGER
185
static unsigned
186
303k
xmlXPathSFComputeHash(const xmlChar *name) {
187
303k
    unsigned hashValue = 5381;
188
303k
    const xmlChar *ptr;
189
190
2.58M
    for (ptr = name; *ptr; ptr++)
191
2.27M
        hashValue = hashValue * 33 + *ptr;
192
193
303k
    return(hashValue);
194
303k
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
10.5k
xmlInitXPathInternal(void) {
202
10.5k
    size_t i;
203
204
10.5k
#if defined(NAN) && defined(INFINITY)
205
10.5k
    xmlXPathNAN = NAN;
206
10.5k
    xmlXPathPINF = INFINITY;
207
10.5k
    xmlXPathNINF = -INFINITY;
208
#else
209
    /* MSVC doesn't allow division by zero in constant expressions. */
210
    double zero = 0.0;
211
    xmlXPathNAN = 0.0 / zero;
212
    xmlXPathPINF = 1.0 / zero;
213
    xmlXPathNINF = -xmlXPathPINF;
214
#endif
215
216
    /*
217
     * Initialize hash table for standard functions
218
     */
219
220
687k
    for (i = 0; i < SF_HASH_SIZE; i++)
221
677k
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
296k
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
285k
        const char *name = xmlXPathStandardFunctions[i].name;
225
285k
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
359k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
74.0k
            bucketIndex += 1;
229
74.0k
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
74.0k
        }
232
233
285k
        xmlXPathSFHash[bucketIndex] = i;
234
285k
    }
235
10.5k
}
236
237
/************************************************************************
238
 *                  *
239
 *      Floating point stuff        *
240
 *                  *
241
 ************************************************************************/
242
243
/**
244
 * Checks whether a double is a NaN.
245
 *
246
 * @param val  a double value
247
 * @returns 1 if the value is a NaN, 0 otherwise
248
 */
249
int
250
2.03M
xmlXPathIsNaN(double val) {
251
2.03M
#ifdef isnan
252
2.03M
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
2.03M
}
257
258
/**
259
 * Checks whether a double is an infinity.
260
 *
261
 * @param val  a double value
262
 * @returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
263
 */
264
int
265
434k
xmlXPathIsInf(double val) {
266
434k
#ifdef isinf
267
434k
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
268
#else
269
    if (val >= xmlXPathPINF)
270
        return 1;
271
    if (val <= -xmlXPathPINF)
272
        return -1;
273
    return 0;
274
#endif
275
434k
}
276
277
/*
278
 * TODO: when compatibility allows remove all "fake node libxslt" strings
279
 *       the test should just be name[0] = ' '
280
 */
281
282
static const xmlNs xmlXPathXMLNamespaceStruct = {
283
    NULL,
284
    XML_NAMESPACE_DECL,
285
    XML_XML_NAMESPACE,
286
    BAD_CAST "xml",
287
    NULL,
288
    NULL
289
};
290
static const xmlNs *const xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
291
292
static void
293
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
294
295
38.4M
#define XML_NODE_SORT_VALUE(n) XML_PTR_TO_INT((n)->content)
296
297
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
298
299
/**
300
 * Compare two nodes w.r.t document order.
301
 * This one is optimized for handling of non-element nodes.
302
 *
303
 * @param node1  the first node
304
 * @param node2  the second node
305
 * @returns -2 in case of error 1 if first point < second point, 0 if
306
 *         it's the same node, -1 otherwise
307
 */
308
static int
309
32.8M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
32.8M
    int depth1, depth2;
311
32.8M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
32.8M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
32.8M
    xmlNodePtr cur, root;
314
32.8M
    XML_INTPTR_T l1, l2;
315
316
32.8M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
32.8M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
32.8M
    switch (node1->type) {
326
21.8M
  case XML_ELEMENT_NODE:
327
21.8M
      if (node2->type == XML_ELEMENT_NODE) {
328
13.0M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
13.0M
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
13.0M
        (node1->doc == node2->doc))
331
0
    {
332
0
        l1 = -XML_NODE_SORT_VALUE(node1);
333
0
        l2 = -XML_NODE_SORT_VALUE(node2);
334
0
        if (l1 < l2)
335
0
      return(1);
336
0
        if (l1 > l2)
337
0
      return(-1);
338
0
    } else
339
13.0M
        goto turtle_comparison;
340
13.0M
      }
341
8.81M
      break;
342
8.81M
  case XML_ATTRIBUTE_NODE:
343
36.2k
      precedence1 = 1; /* element is owner */
344
36.2k
      miscNode1 = node1;
345
36.2k
      node1 = node1->parent;
346
36.2k
      misc = 1;
347
36.2k
      break;
348
9.15M
  case XML_TEXT_NODE:
349
9.77M
  case XML_CDATA_SECTION_NODE:
350
9.78M
  case XML_COMMENT_NODE:
351
9.93M
  case XML_PI_NODE: {
352
9.93M
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
9.93M
      if (node1->prev != NULL) {
357
17.7M
    do {
358
17.7M
        node1 = node1->prev;
359
17.7M
        if (node1->type == XML_ELEMENT_NODE) {
360
8.19M
      precedence1 = 3; /* element in prev-sibl axis */
361
8.19M
      break;
362
8.19M
        }
363
9.58M
        if (node1->prev == NULL) {
364
29.9k
      precedence1 = 2; /* element is parent */
365
      /*
366
      * URGENT TODO: Are there any cases, where the
367
      * parent of such a node is not an element node?
368
      */
369
29.9k
      node1 = node1->parent;
370
29.9k
      break;
371
29.9k
        }
372
9.58M
    } while (1);
373
8.22M
      } else {
374
1.70M
    precedence1 = 2; /* element is parent */
375
1.70M
    node1 = node1->parent;
376
1.70M
      }
377
9.93M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
9.93M
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
9.92M
    node1 = miscNode1;
383
9.92M
    precedence1 = 0;
384
9.92M
      } else
385
3.21k
    misc = 1;
386
9.93M
  }
387
0
      break;
388
796k
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
796k
      return(1);
393
208k
  default:
394
208k
      break;
395
32.8M
    }
396
18.9M
    switch (node2->type) {
397
7.13M
  case XML_ELEMENT_NODE:
398
7.13M
      break;
399
55.9k
  case XML_ATTRIBUTE_NODE:
400
55.9k
      precedence2 = 1; /* element is owner */
401
55.9k
      miscNode2 = node2;
402
55.9k
      node2 = node2->parent;
403
55.9k
      misc = 1;
404
55.9k
      break;
405
10.2M
  case XML_TEXT_NODE:
406
11.0M
  case XML_CDATA_SECTION_NODE:
407
11.0M
  case XML_COMMENT_NODE:
408
11.1M
  case XML_PI_NODE: {
409
11.1M
      miscNode2 = node2;
410
11.1M
      if (node2->prev != NULL) {
411
18.5M
    do {
412
18.5M
        node2 = node2->prev;
413
18.5M
        if (node2->type == XML_ELEMENT_NODE) {
414
8.94M
      precedence2 = 3; /* element in prev-sibl axis */
415
8.94M
      break;
416
8.94M
        }
417
9.61M
        if (node2->prev == NULL) {
418
37.9k
      precedence2 = 2; /* element is parent */
419
37.9k
      node2 = node2->parent;
420
37.9k
      break;
421
37.9k
        }
422
9.61M
    } while (1);
423
8.98M
      } else {
424
2.19M
    precedence2 = 2; /* element is parent */
425
2.19M
    node2 = node2->parent;
426
2.19M
      }
427
11.1M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
11.1M
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
11.1M
      {
430
11.1M
    node2 = miscNode2;
431
11.1M
    precedence2 = 0;
432
11.1M
      } else
433
70.9k
    misc = 1;
434
11.1M
  }
435
0
      break;
436
16.2k
  case XML_NAMESPACE_DECL:
437
16.2k
      return(1);
438
602k
  default:
439
602k
      break;
440
18.9M
    }
441
18.9M
    if (misc) {
442
144k
  if (node1 == node2) {
443
76.6k
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
3.34k
    cur = miscNode2->prev;
449
4.73k
    while (cur != NULL) {
450
2.82k
        if (cur == miscNode1)
451
1.43k
      return(1);
452
1.38k
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
1.38k
        cur = cur->prev;
455
1.38k
    }
456
1.90k
    return (-1);
457
73.3k
      } else {
458
    /*
459
    * Evaluate based on higher precedence wrt to the element.
460
    * TODO: This assumes attributes are sorted before content.
461
    *   Is this 100% correct?
462
    */
463
73.3k
    if (precedence1 < precedence2)
464
70.9k
        return(1);
465
2.33k
    else
466
2.33k
        return(-1);
467
73.3k
      }
468
76.6k
  }
469
  /*
470
  * Special case: One of the helper-elements is contained by the other.
471
  * <foo>
472
  *   <node2>
473
  *     <node1>Text-1(precedence1 == 2)</node1>
474
  *   </node2>
475
  *   Text-6(precedence2 == 3)
476
  * </foo>
477
  */
478
67.7k
  if ((precedence2 == 3) && (precedence1 > 1)) {
479
0
      cur = node1->parent;
480
0
      while (cur) {
481
0
    if (cur == node2)
482
0
        return(1);
483
0
    cur = cur->parent;
484
0
      }
485
0
  }
486
67.7k
  if ((precedence1 == 3) && (precedence2 > 1)) {
487
0
      cur = node2->parent;
488
0
      while (cur) {
489
0
    if (cur == node1)
490
0
        return(-1);
491
0
    cur = cur->parent;
492
0
      }
493
0
  }
494
67.7k
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
18.8M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
18.8M
  (node2->type == XML_ELEMENT_NODE) &&
501
18.8M
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
18.8M
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
18.8M
  (node1->doc == node2->doc)) {
504
505
0
  l1 = -XML_NODE_SORT_VALUE(node1);
506
0
  l2 = -XML_NODE_SORT_VALUE(node2);
507
0
  if (l1 < l2)
508
0
      return(1);
509
0
  if (l1 > l2)
510
0
      return(-1);
511
0
    }
512
513
31.9M
turtle_comparison:
514
515
31.9M
    if (node1 == node2->prev)
516
10.2M
  return(1);
517
21.7M
    if (node1 == node2->next)
518
1.13M
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
188M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
172M
  if (cur->parent == node1)
524
4.24M
      return(1);
525
167M
  depth2++;
526
167M
    }
527
16.3M
    root = cur;
528
172M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
160M
  if (cur->parent == node2)
530
3.95M
      return(-1);
531
156M
  depth1++;
532
156M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
12.4M
    if (root != cur) {
537
704
  return(-2);
538
704
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
46.2M
    while (depth1 > depth2) {
543
33.8M
  depth1--;
544
33.8M
  node1 = node1->parent;
545
33.8M
    }
546
32.0M
    while (depth2 > depth1) {
547
19.6M
  depth2--;
548
19.6M
  node2 = node2->parent;
549
19.6M
    }
550
15.6M
    while (node1->parent != node2->parent) {
551
3.25M
  node1 = node1->parent;
552
3.25M
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
3.25M
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
3.25M
    }
557
    /*
558
     * Find who's first.
559
     */
560
12.4M
    if (node1 == node2->prev)
561
750k
  return(1);
562
11.6M
    if (node1 == node2->next)
563
5.04M
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
6.62M
    if ((node1->type == XML_ELEMENT_NODE) &&
568
6.62M
  (node2->type == XML_ELEMENT_NODE) &&
569
6.62M
  (0 > XML_NODE_SORT_VALUE(node1)) &&
570
6.62M
  (0 > XML_NODE_SORT_VALUE(node2)) &&
571
6.62M
  (node1->doc == node2->doc)) {
572
573
0
  l1 = -XML_NODE_SORT_VALUE(node1);
574
0
  l2 = -XML_NODE_SORT_VALUE(node2);
575
0
  if (l1 < l2)
576
0
      return(1);
577
0
  if (l1 > l2)
578
0
      return(-1);
579
0
    }
580
581
628M
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
624M
  if (cur == node2)
583
2.69M
      return(1);
584
3.93M
    return(-1); /* assume there is no sibling list corruption */
585
6.62M
}
586
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
587
588
/*
589
 * Wrapper for the Timsort algorithm from timsort.h
590
 */
591
#ifdef WITH_TIM_SORT
592
#define SORT_NAME libxml_domnode
593
6.61M
#define SORT_TYPE xmlNodePtr
594
/**
595
 * Comparison function for the Timsort implementation
596
 *
597
 * @param x  a node
598
 * @param y  another node
599
 * @returns -2 in case of error -1 if first point < second point, 0 if
600
 *         it's the same node, +1 otherwise
601
 */
602
static
603
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
604
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
605
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
606
32.8M
    {
607
32.8M
        int res = xmlXPathCmpNodesExt(x, y);
608
32.8M
        return res == -2 ? res : -res;
609
32.8M
    }
610
#else
611
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
612
    {
613
        int res = xmlXPathCmpNodes(x, y);
614
        return res == -2 ? res : -res;
615
    }
616
#endif
617
32.8M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
618
#include "timsort.h"
619
#endif /* WITH_TIM_SORT */
620
621
/************************************************************************
622
 *                  *
623
 *      Error handling routines       *
624
 *                  *
625
 ************************************************************************/
626
627
/**
628
 * Macro to raise an XPath error and return NULL.
629
 *
630
 * @param X  the error code
631
 */
632
#define XP_ERRORNULL(X)             \
633
3.15k
    { xmlXPathErr(ctxt, X); return(NULL); }
634
635
/*
636
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
637
 */
638
static const char* const xmlXPathErrorMessages[] = {
639
    "Ok",
640
    "Number encoding",
641
    "Unfinished literal",
642
    "Start of literal",
643
    "Expected $ for variable reference",
644
    "Undefined variable",
645
    "Invalid predicate",
646
    "Invalid expression",
647
    "Missing closing curly brace",
648
    "Unregistered function",
649
    "Invalid operand",
650
    "Invalid type",
651
    "Invalid number of arguments",
652
    "Invalid context size",
653
    "Invalid context position",
654
    "Memory allocation error",
655
    "Syntax error",
656
    "Resource error",
657
    "Sub resource error",
658
    "Undefined namespace prefix",
659
    "Encoding error",
660
    "Char out of XML range",
661
    "Invalid or incomplete context",
662
    "Stack usage error",
663
    "Forbidden variable",
664
    "Operation limit exceeded",
665
    "Recursion limit exceeded",
666
    "?? Unknown error ??" /* Must be last in the list! */
667
};
668
14.4M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
14.4M
       sizeof(xmlXPathErrorMessages[0])) - 1)
670
/**
671
 * Handle a memory allocation failure.
672
 *
673
 * @param ctxt  an XPath context
674
 */
675
void
676
xmlXPathErrMemory(xmlXPathContext *ctxt)
677
83.5k
{
678
83.5k
    if (ctxt == NULL)
679
0
        return;
680
83.5k
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
83.5k
                        &ctxt->lastError);
682
83.5k
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
82.1k
{
692
82.1k
    if (ctxt == NULL)
693
0
        return;
694
82.1k
    ctxt->error = XPATH_MEMORY_ERROR;
695
82.1k
    xmlXPathErrMemory(ctxt->context);
696
82.1k
}
697
698
/**
699
 * Handle an XPath error
700
 *
701
 * @param ctxt  a XPath parser context
702
 * @param code  the error code
703
 * @param fmt  format string for error message
704
 * @param ...  extra args
705
 */
706
static void
707
14.4M
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
14.4M
    va_list ap;
709
14.4M
    xmlStructuredErrorFunc schannel = NULL;
710
14.4M
    xmlGenericErrorFunc channel = NULL;
711
14.4M
    void *data = NULL;
712
14.4M
    xmlNodePtr node = NULL;
713
14.4M
    int res;
714
715
14.4M
    if (ctxt == NULL)
716
0
        return;
717
14.4M
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
14.4M
    if (ctxt->error != 0)
721
14.4M
        return;
722
723
33.4k
    ctxt->error = code;
724
725
33.4k
    if (ctxt->context != NULL) {
726
33.4k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
33.4k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
33.4k
        xmlResetError(err);
734
735
33.4k
        err->domain = XML_FROM_XPATH;
736
33.4k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
33.4k
        err->level = XML_ERR_ERROR;
738
33.4k
        if (ctxt->base != NULL) {
739
32.2k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
32.2k
            if (err->str1 == NULL) {
741
114
                xmlXPathPErrMemory(ctxt);
742
114
                return;
743
114
            }
744
32.2k
        }
745
33.3k
        err->int1 = ctxt->cur - ctxt->base;
746
33.3k
        err->node = ctxt->context->debugNode;
747
748
33.3k
        schannel = ctxt->context->error;
749
33.3k
        data = ctxt->context->userData;
750
33.3k
        node = ctxt->context->debugNode;
751
33.3k
    }
752
753
33.3k
    if (schannel == NULL) {
754
28.7k
        channel = xmlGenericError;
755
28.7k
        data = xmlGenericErrorContext;
756
28.7k
    }
757
758
33.3k
    va_start(ap, fmt);
759
33.3k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
33.3k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
33.3k
                         XML_ERR_ERROR, NULL, 0,
762
33.3k
                         (const char *) ctxt->base, NULL, NULL,
763
33.3k
                         ctxt->cur - ctxt->base, 0,
764
33.3k
                         fmt, ap);
765
33.3k
    va_end(ap);
766
33.3k
    if (res < 0)
767
264
        xmlXPathPErrMemory(ctxt);
768
33.3k
}
769
770
/**
771
 * Handle an XPath error
772
 *
773
 * @param ctxt  a XPath parser context
774
 * @param code  the error code
775
 */
776
void
777
14.4M
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
14.4M
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
14.4M
}
780
781
/**
782
 * Formats an error message.
783
 *
784
 * @param ctxt  the XPath Parser context
785
 * @param file  the file name
786
 * @param line  the line number
787
 * @param no  the error number
788
 */
789
void
790
xmlXPatherror(xmlXPathParserContext *ctxt, const char *file ATTRIBUTE_UNUSED,
791
397
              int line ATTRIBUTE_UNUSED, int no) {
792
397
    xmlXPathErr(ctxt, no);
793
397
}
794
795
/**
796
 * Adds opCount to the running total of operations and returns -1 if the
797
 * operation limit is exceeded. Returns 0 otherwise.
798
 *
799
 * @param ctxt  the XPath Parser context
800
 * @param opCount  the number of operations to be added
801
 */
802
static int
803
78.2M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
78.2M
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
78.2M
    if ((opCount > xpctxt->opLimit) ||
807
78.2M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
560
        xpctxt->opCount = xpctxt->opLimit;
809
560
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
560
        return(-1);
811
560
    }
812
813
78.2M
    xpctxt->opCount += opCount;
814
78.2M
    return(0);
815
78.2M
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
80.9M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
819
820
/************************************************************************
821
 *                  *
822
 *      Parser Types          *
823
 *                  *
824
 ************************************************************************/
825
826
/*
827
 * Types are private:
828
 */
829
830
typedef enum {
831
    XPATH_OP_END=0,
832
    XPATH_OP_AND,
833
    XPATH_OP_OR,
834
    XPATH_OP_EQUAL,
835
    XPATH_OP_CMP,
836
    XPATH_OP_PLUS,
837
    XPATH_OP_MULT,
838
    XPATH_OP_UNION,
839
    XPATH_OP_ROOT,
840
    XPATH_OP_NODE,
841
    XPATH_OP_COLLECT,
842
    XPATH_OP_VALUE, /* 11 */
843
    XPATH_OP_VARIABLE,
844
    XPATH_OP_FUNCTION,
845
    XPATH_OP_ARG,
846
    XPATH_OP_PREDICATE,
847
    XPATH_OP_FILTER, /* 16 */
848
    XPATH_OP_SORT /* 17 */
849
} xmlXPathOp;
850
851
typedef enum {
852
    AXIS_ANCESTOR = 1,
853
    AXIS_ANCESTOR_OR_SELF,
854
    AXIS_ATTRIBUTE,
855
    AXIS_CHILD,
856
    AXIS_DESCENDANT,
857
    AXIS_DESCENDANT_OR_SELF,
858
    AXIS_FOLLOWING,
859
    AXIS_FOLLOWING_SIBLING,
860
    AXIS_NAMESPACE,
861
    AXIS_PARENT,
862
    AXIS_PRECEDING,
863
    AXIS_PRECEDING_SIBLING,
864
    AXIS_SELF
865
} xmlXPathAxisVal;
866
867
typedef enum {
868
    NODE_TEST_NONE = 0,
869
    NODE_TEST_TYPE = 1,
870
    NODE_TEST_PI = 2,
871
    NODE_TEST_ALL = 3,
872
    NODE_TEST_NS = 4,
873
    NODE_TEST_NAME = 5
874
} xmlXPathTestVal;
875
876
typedef enum {
877
    NODE_TYPE_NODE = 0,
878
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
879
    NODE_TYPE_TEXT = XML_TEXT_NODE,
880
    NODE_TYPE_PI = XML_PI_NODE
881
} xmlXPathTypeVal;
882
883
typedef struct _xmlXPathStepOp xmlXPathStepOp;
884
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
885
struct _xmlXPathStepOp {
886
    xmlXPathOp op;    /* The identifier of the operation */
887
    int ch1;      /* First child */
888
    int ch2;      /* Second child */
889
    int value;
890
    int value2;
891
    int value3;
892
    void *value4;
893
    void *value5;
894
    xmlXPathFunction cache;
895
    void *cacheURI;
896
};
897
898
struct _xmlXPathCompExpr {
899
    int nbStep;     /* Number of steps in this expression */
900
    int maxStep;    /* Maximum number of steps allocated */
901
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
902
    int last;     /* index of last step in expression */
903
    xmlChar *expr;    /* the expression being computed */
904
    xmlDictPtr dict;    /* the dictionary to use if any */
905
#ifdef XPATH_STREAMING
906
    xmlPatternPtr stream;
907
#endif
908
};
909
910
/************************************************************************
911
 *                  *
912
 *      Forward declarations        *
913
 *                  *
914
 ************************************************************************/
915
916
static void
917
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
918
static int
919
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
920
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
921
static int
922
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
923
          xmlXPathStepOpPtr op,
924
          int isPredicate);
925
static void
926
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
927
928
/************************************************************************
929
 *                  *
930
 *      Parser Type functions       *
931
 *                  *
932
 ************************************************************************/
933
934
/**
935
 * Create a new Xpath component
936
 *
937
 * @returns the newly allocated xmlXPathCompExpr or NULL in case of error
938
 */
939
static xmlXPathCompExprPtr
940
59.2k
xmlXPathNewCompExpr(void) {
941
59.2k
    xmlXPathCompExprPtr cur;
942
943
59.2k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
59.2k
    if (cur == NULL)
945
229
  return(NULL);
946
58.9k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
58.9k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
58.9k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
58.9k
    cur->nbStep = 0;
953
58.9k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
58.9k
                                     sizeof(xmlXPathStepOp));
955
58.9k
    if (cur->steps == NULL) {
956
103
  xmlFree(cur);
957
103
  return(NULL);
958
103
    }
959
58.8k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
58.8k
    cur->last = -1;
961
58.8k
    return(cur);
962
58.9k
}
963
964
/**
965
 * Free up the memory allocated by `comp`
966
 *
967
 * @param comp  an XPATH comp
968
 */
969
void
970
xmlXPathFreeCompExpr(xmlXPathCompExpr *comp)
971
60.9k
{
972
60.9k
    xmlXPathStepOpPtr op;
973
60.9k
    int i;
974
975
60.9k
    if (comp == NULL)
976
2.07k
        return;
977
58.8k
    if (comp->dict == NULL) {
978
56.2M
  for (i = 0; i < comp->nbStep; i++) {
979
56.2M
      op = &comp->steps[i];
980
56.2M
      if (op->value4 != NULL) {
981
247k
    if (op->op == XPATH_OP_VALUE)
982
185k
        xmlXPathFreeObject(op->value4);
983
62.0k
    else
984
62.0k
        xmlFree(op->value4);
985
247k
      }
986
56.2M
      if (op->value5 != NULL)
987
2.20M
    xmlFree(op->value5);
988
56.2M
  }
989
58.8k
    } else {
990
0
  for (i = 0; i < comp->nbStep; i++) {
991
0
      op = &comp->steps[i];
992
0
      if (op->value4 != NULL) {
993
0
    if (op->op == XPATH_OP_VALUE)
994
0
        xmlXPathFreeObject(op->value4);
995
0
      }
996
0
  }
997
0
        xmlDictFree(comp->dict);
998
0
    }
999
58.8k
    if (comp->steps != NULL) {
1000
58.8k
        xmlFree(comp->steps);
1001
58.8k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
58.8k
    if (comp->expr != NULL) {
1008
6.51k
        xmlFree(comp->expr);
1009
6.51k
    }
1010
1011
58.8k
    xmlFree(comp);
1012
58.8k
}
1013
1014
/**
1015
 * Add a step to an XPath Compiled Expression
1016
 *
1017
 * @param ctxt  XPath parser context
1018
 * @param ch1  first child index
1019
 * @param ch2  second child index
1020
 * @param op  an op
1021
 * @param value  the first int value
1022
 * @param value2  the second int value
1023
 * @param value3  the third int value
1024
 * @param value4  the first string value
1025
 * @param value5  the second string value
1026
 * @returns -1 in case of failure, the index otherwise
1027
 */
1028
static int
1029
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1030
   xmlXPathOp op, int value,
1031
56.3M
   int value2, int value3, void *value4, void *value5) {
1032
56.3M
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
56.3M
    if (comp->nbStep >= comp->maxStep) {
1034
301k
  xmlXPathStepOp *real;
1035
301k
        int newSize;
1036
1037
301k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
301k
                                  10, XPATH_MAX_STEPS);
1039
301k
        if (newSize < 0) {
1040
76.4k
      xmlXPathPErrMemory(ctxt);
1041
76.4k
      return(-1);
1042
76.4k
        }
1043
224k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
224k
  if (real == NULL) {
1045
132
      xmlXPathPErrMemory(ctxt);
1046
132
      return(-1);
1047
132
  }
1048
224k
  comp->steps = real;
1049
224k
  comp->maxStep = newSize;
1050
224k
    }
1051
56.2M
    comp->last = comp->nbStep;
1052
56.2M
    comp->steps[comp->nbStep].ch1 = ch1;
1053
56.2M
    comp->steps[comp->nbStep].ch2 = ch2;
1054
56.2M
    comp->steps[comp->nbStep].op = op;
1055
56.2M
    comp->steps[comp->nbStep].value = value;
1056
56.2M
    comp->steps[comp->nbStep].value2 = value2;
1057
56.2M
    comp->steps[comp->nbStep].value3 = value3;
1058
56.2M
    if ((comp->dict != NULL) &&
1059
56.2M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1060
0
   (op == XPATH_OP_COLLECT))) {
1061
0
        if (value4 != NULL) {
1062
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1063
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1064
0
      xmlFree(value4);
1065
0
  } else
1066
0
      comp->steps[comp->nbStep].value4 = NULL;
1067
0
        if (value5 != NULL) {
1068
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1069
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1070
0
      xmlFree(value5);
1071
0
  } else
1072
0
      comp->steps[comp->nbStep].value5 = NULL;
1073
56.2M
    } else {
1074
56.2M
  comp->steps[comp->nbStep].value4 = value4;
1075
56.2M
  comp->steps[comp->nbStep].value5 = value5;
1076
56.2M
    }
1077
56.2M
    comp->steps[comp->nbStep].cache = NULL;
1078
56.2M
    return(comp->nbStep++);
1079
56.3M
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
8.61M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
8.61M
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
405k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
405k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
22.7M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
22.7M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
1.71M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
1.71M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
22.7M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
22.7M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
22.7M
      (val), (val2), 0 ,NULL ,NULL)
1097
1098
/************************************************************************
1099
 *                  *
1100
 *    XPath object cache structures       *
1101
 *                  *
1102
 ************************************************************************/
1103
1104
/* #define XP_DEFAULT_CACHE_ON */
1105
1106
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1107
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1108
struct _xmlXPathContextCache {
1109
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1110
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1111
    int numNodeset;
1112
    int maxNodeset;
1113
    int numMisc;
1114
    int maxMisc;
1115
};
1116
1117
/************************************************************************
1118
 *                  *
1119
 *    Debugging related functions       *
1120
 *                  *
1121
 ************************************************************************/
1122
1123
#ifdef LIBXML_DEBUG_ENABLED
1124
static void
1125
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1126
    int i;
1127
    char shift[100];
1128
1129
    for (i = 0;((i < depth) && (i < 25));i++)
1130
        shift[2 * i] = shift[2 * i + 1] = ' ';
1131
    shift[2 * i] = shift[2 * i + 1] = 0;
1132
    if (cur == NULL) {
1133
  fprintf(output, "%s", shift);
1134
  fprintf(output, "Node is NULL !\n");
1135
  return;
1136
1137
    }
1138
1139
    if ((cur->type == XML_DOCUMENT_NODE) ||
1140
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1141
  fprintf(output, "%s", shift);
1142
  fprintf(output, " /\n");
1143
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1144
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1145
    else
1146
  xmlDebugDumpOneNode(output, cur, depth);
1147
}
1148
static void
1149
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1150
    xmlNodePtr tmp;
1151
    int i;
1152
    char shift[100];
1153
1154
    for (i = 0;((i < depth) && (i < 25));i++)
1155
        shift[2 * i] = shift[2 * i + 1] = ' ';
1156
    shift[2 * i] = shift[2 * i + 1] = 0;
1157
    if (cur == NULL) {
1158
  fprintf(output, "%s", shift);
1159
  fprintf(output, "Node is NULL !\n");
1160
  return;
1161
1162
    }
1163
1164
    while (cur != NULL) {
1165
  tmp = cur;
1166
  cur = cur->next;
1167
  xmlDebugDumpOneNode(output, tmp, depth);
1168
    }
1169
}
1170
1171
static void
1172
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1173
    int i;
1174
    char shift[100];
1175
1176
    for (i = 0;((i < depth) && (i < 25));i++)
1177
        shift[2 * i] = shift[2 * i + 1] = ' ';
1178
    shift[2 * i] = shift[2 * i + 1] = 0;
1179
1180
    if (cur == NULL) {
1181
  fprintf(output, "%s", shift);
1182
  fprintf(output, "NodeSet is NULL !\n");
1183
  return;
1184
1185
    }
1186
1187
    if (cur != NULL) {
1188
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1189
  for (i = 0;i < cur->nodeNr;i++) {
1190
      fprintf(output, "%s", shift);
1191
      fprintf(output, "%d", i + 1);
1192
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1193
  }
1194
    }
1195
}
1196
1197
static void
1198
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1199
    int i;
1200
    char shift[100];
1201
1202
    for (i = 0;((i < depth) && (i < 25));i++)
1203
        shift[2 * i] = shift[2 * i + 1] = ' ';
1204
    shift[2 * i] = shift[2 * i + 1] = 0;
1205
1206
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1207
  fprintf(output, "%s", shift);
1208
  fprintf(output, "Value Tree is NULL !\n");
1209
  return;
1210
1211
    }
1212
1213
    fprintf(output, "%s", shift);
1214
    fprintf(output, "%d", i + 1);
1215
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1216
}
1217
1218
/**
1219
 * Dump the content of the object for debugging purposes
1220
 *
1221
 * @param output  the FILE * to dump the output
1222
 * @param cur  the object to inspect
1223
 * @param depth  indentation level
1224
 */
1225
void
1226
xmlXPathDebugDumpObject(FILE *output, xmlXPathObject *cur, int depth) {
1227
    int i;
1228
    char shift[100];
1229
1230
    if (output == NULL) return;
1231
1232
    for (i = 0;((i < depth) && (i < 25));i++)
1233
        shift[2 * i] = shift[2 * i + 1] = ' ';
1234
    shift[2 * i] = shift[2 * i + 1] = 0;
1235
1236
1237
    fprintf(output, "%s", shift);
1238
1239
    if (cur == NULL) {
1240
        fprintf(output, "Object is empty (NULL)\n");
1241
  return;
1242
    }
1243
    switch(cur->type) {
1244
        case XPATH_UNDEFINED:
1245
      fprintf(output, "Object is uninitialized\n");
1246
      break;
1247
        case XPATH_NODESET:
1248
      fprintf(output, "Object is a Node Set :\n");
1249
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250
      break;
1251
  case XPATH_XSLT_TREE:
1252
      fprintf(output, "Object is an XSLT value tree :\n");
1253
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254
      break;
1255
        case XPATH_BOOLEAN:
1256
      fprintf(output, "Object is a Boolean : ");
1257
      if (cur->boolval) fprintf(output, "true\n");
1258
      else fprintf(output, "false\n");
1259
      break;
1260
        case XPATH_NUMBER:
1261
      switch (xmlXPathIsInf(cur->floatval)) {
1262
      case 1:
1263
    fprintf(output, "Object is a number : Infinity\n");
1264
    break;
1265
      case -1:
1266
    fprintf(output, "Object is a number : -Infinity\n");
1267
    break;
1268
      default:
1269
    if (xmlXPathIsNaN(cur->floatval)) {
1270
        fprintf(output, "Object is a number : NaN\n");
1271
    } else if (cur->floatval == 0) {
1272
                    /* Omit sign for negative zero. */
1273
        fprintf(output, "Object is a number : 0\n");
1274
    } else {
1275
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276
    }
1277
      }
1278
      break;
1279
        case XPATH_STRING:
1280
      fprintf(output, "Object is a string : ");
1281
      xmlDebugDumpString(output, cur->stringval);
1282
      fprintf(output, "\n");
1283
      break;
1284
  case XPATH_USERS:
1285
      fprintf(output, "Object is user defined\n");
1286
      break;
1287
    }
1288
}
1289
1290
static void
1291
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1292
                       xmlXPathStepOpPtr op, int depth) {
1293
    int i;
1294
    char shift[100];
1295
1296
    for (i = 0;((i < depth) && (i < 25));i++)
1297
        shift[2 * i] = shift[2 * i + 1] = ' ';
1298
    shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300
    fprintf(output, "%s", shift);
1301
    if (op == NULL) {
1302
  fprintf(output, "Step is NULL\n");
1303
  return;
1304
    }
1305
    switch (op->op) {
1306
        case XPATH_OP_END:
1307
      fprintf(output, "END"); break;
1308
        case XPATH_OP_AND:
1309
      fprintf(output, "AND"); break;
1310
        case XPATH_OP_OR:
1311
      fprintf(output, "OR"); break;
1312
        case XPATH_OP_EQUAL:
1313
       if (op->value)
1314
     fprintf(output, "EQUAL =");
1315
       else
1316
     fprintf(output, "EQUAL !=");
1317
       break;
1318
        case XPATH_OP_CMP:
1319
       if (op->value)
1320
     fprintf(output, "CMP <");
1321
       else
1322
     fprintf(output, "CMP >");
1323
       if (!op->value2)
1324
     fprintf(output, "=");
1325
       break;
1326
        case XPATH_OP_PLUS:
1327
       if (op->value == 0)
1328
     fprintf(output, "PLUS -");
1329
       else if (op->value == 1)
1330
     fprintf(output, "PLUS +");
1331
       else if (op->value == 2)
1332
     fprintf(output, "PLUS unary -");
1333
       else if (op->value == 3)
1334
     fprintf(output, "PLUS unary - -");
1335
       break;
1336
        case XPATH_OP_MULT:
1337
       if (op->value == 0)
1338
     fprintf(output, "MULT *");
1339
       else if (op->value == 1)
1340
     fprintf(output, "MULT div");
1341
       else
1342
     fprintf(output, "MULT mod");
1343
       break;
1344
        case XPATH_OP_UNION:
1345
       fprintf(output, "UNION"); break;
1346
        case XPATH_OP_ROOT:
1347
       fprintf(output, "ROOT"); break;
1348
        case XPATH_OP_NODE:
1349
       fprintf(output, "NODE"); break;
1350
        case XPATH_OP_SORT:
1351
       fprintf(output, "SORT"); break;
1352
        case XPATH_OP_COLLECT: {
1353
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1354
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1355
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1356
      const xmlChar *prefix = op->value4;
1357
      const xmlChar *name = op->value5;
1358
1359
      fprintf(output, "COLLECT ");
1360
      switch (axis) {
1361
    case AXIS_ANCESTOR:
1362
        fprintf(output, " 'ancestors' "); break;
1363
    case AXIS_ANCESTOR_OR_SELF:
1364
        fprintf(output, " 'ancestors-or-self' "); break;
1365
    case AXIS_ATTRIBUTE:
1366
        fprintf(output, " 'attributes' "); break;
1367
    case AXIS_CHILD:
1368
        fprintf(output, " 'child' "); break;
1369
    case AXIS_DESCENDANT:
1370
        fprintf(output, " 'descendant' "); break;
1371
    case AXIS_DESCENDANT_OR_SELF:
1372
        fprintf(output, " 'descendant-or-self' "); break;
1373
    case AXIS_FOLLOWING:
1374
        fprintf(output, " 'following' "); break;
1375
    case AXIS_FOLLOWING_SIBLING:
1376
        fprintf(output, " 'following-siblings' "); break;
1377
    case AXIS_NAMESPACE:
1378
        fprintf(output, " 'namespace' "); break;
1379
    case AXIS_PARENT:
1380
        fprintf(output, " 'parent' "); break;
1381
    case AXIS_PRECEDING:
1382
        fprintf(output, " 'preceding' "); break;
1383
    case AXIS_PRECEDING_SIBLING:
1384
        fprintf(output, " 'preceding-sibling' "); break;
1385
    case AXIS_SELF:
1386
        fprintf(output, " 'self' "); break;
1387
      }
1388
      switch (test) {
1389
                case NODE_TEST_NONE:
1390
        fprintf(output, "'none' "); break;
1391
                case NODE_TEST_TYPE:
1392
        fprintf(output, "'type' "); break;
1393
                case NODE_TEST_PI:
1394
        fprintf(output, "'PI' "); break;
1395
                case NODE_TEST_ALL:
1396
        fprintf(output, "'all' "); break;
1397
                case NODE_TEST_NS:
1398
        fprintf(output, "'namespace' "); break;
1399
                case NODE_TEST_NAME:
1400
        fprintf(output, "'name' "); break;
1401
      }
1402
      switch (type) {
1403
                case NODE_TYPE_NODE:
1404
        fprintf(output, "'node' "); break;
1405
                case NODE_TYPE_COMMENT:
1406
        fprintf(output, "'comment' "); break;
1407
                case NODE_TYPE_TEXT:
1408
        fprintf(output, "'text' "); break;
1409
                case NODE_TYPE_PI:
1410
        fprintf(output, "'PI' "); break;
1411
      }
1412
      if (prefix != NULL)
1413
    fprintf(output, "%s:", prefix);
1414
      if (name != NULL)
1415
    fprintf(output, "%s", (const char *) name);
1416
      break;
1417
1418
        }
1419
  case XPATH_OP_VALUE: {
1420
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1421
1422
      fprintf(output, "ELEM ");
1423
      xmlXPathDebugDumpObject(output, object, 0);
1424
      goto finish;
1425
  }
1426
  case XPATH_OP_VARIABLE: {
1427
      const xmlChar *prefix = op->value5;
1428
      const xmlChar *name = op->value4;
1429
1430
      if (prefix != NULL)
1431
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1432
      else
1433
    fprintf(output, "VARIABLE %s", name);
1434
      break;
1435
  }
1436
  case XPATH_OP_FUNCTION: {
1437
      int nbargs = op->value;
1438
      const xmlChar *prefix = op->value5;
1439
      const xmlChar *name = op->value4;
1440
1441
      if (prefix != NULL)
1442
    fprintf(output, "FUNCTION %s:%s(%d args)",
1443
      prefix, name, nbargs);
1444
      else
1445
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1446
      break;
1447
  }
1448
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1449
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1450
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1451
  default:
1452
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1453
    }
1454
    fprintf(output, "\n");
1455
finish:
1456
    /* OP_VALUE has invalid ch1. */
1457
    if (op->op == XPATH_OP_VALUE)
1458
        return;
1459
1460
    if (op->ch1 >= 0)
1461
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1462
    if (op->ch2 >= 0)
1463
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1464
}
1465
1466
/**
1467
 * Dumps the tree of the compiled XPath expression.
1468
 *
1469
 * @param output  the FILE * for the output
1470
 * @param comp  the precompiled XPath expression
1471
 * @param depth  the indentation level.
1472
 */
1473
void
1474
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExpr *comp,
1475
                    int depth) {
1476
    int i;
1477
    char shift[100];
1478
1479
    if ((output == NULL) || (comp == NULL)) return;
1480
1481
    for (i = 0;((i < depth) && (i < 25));i++)
1482
        shift[2 * i] = shift[2 * i + 1] = ' ';
1483
    shift[2 * i] = shift[2 * i + 1] = 0;
1484
1485
    fprintf(output, "%s", shift);
1486
1487
#ifdef XPATH_STREAMING
1488
    if (comp->stream) {
1489
        fprintf(output, "Streaming Expression\n");
1490
    } else
1491
#endif
1492
    {
1493
        fprintf(output, "Compiled Expression : %d elements\n",
1494
                comp->nbStep);
1495
        i = comp->last;
1496
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1497
    }
1498
}
1499
1500
#endif /* LIBXML_DEBUG_ENABLED */
1501
1502
/************************************************************************
1503
 *                  *
1504
 *      XPath object caching        *
1505
 *                  *
1506
 ************************************************************************/
1507
1508
/**
1509
 * Create a new object cache
1510
 *
1511
 * @returns the xmlXPathCache just allocated.
1512
 */
1513
static xmlXPathContextCachePtr
1514
xmlXPathNewCache(void)
1515
24.8k
{
1516
24.8k
    xmlXPathContextCachePtr ret;
1517
1518
24.8k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
24.8k
    if (ret == NULL)
1520
565
  return(NULL);
1521
24.2k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
24.2k
    ret->maxNodeset = 100;
1523
24.2k
    ret->maxMisc = 100;
1524
24.2k
    return(ret);
1525
24.8k
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
12.6k
{
1530
45.1k
    while (list != NULL) {
1531
32.5k
        xmlXPathObjectPtr next;
1532
1533
32.5k
        next = (void *) list->stringval;
1534
1535
32.5k
  if (list->nodesetval != NULL) {
1536
22.9k
      if (list->nodesetval->nodeTab != NULL)
1537
20.2k
    xmlFree(list->nodesetval->nodeTab);
1538
22.9k
      xmlFree(list->nodesetval);
1539
22.9k
  }
1540
32.5k
  xmlFree(list);
1541
1542
32.5k
        list = next;
1543
32.5k
    }
1544
12.6k
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
24.2k
{
1549
24.2k
    if (cache == NULL)
1550
0
  return;
1551
24.2k
    if (cache->nodesetObjs)
1552
7.87k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
24.2k
    if (cache->miscObjs)
1554
4.73k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
24.2k
    xmlFree(cache);
1556
24.2k
}
1557
1558
/**
1559
 * Creates/frees an object cache on the XPath context.
1560
 * If activates XPath objects (xmlXPathObject) will be cached internally
1561
 * to be reused.
1562
 *
1563
 * `options` must be set to 0 to enable XPath object caching.
1564
 * Other values for `options` have currently no effect.
1565
 *
1566
 * `value` sets the maximum number of XPath objects to be cached per slot.
1567
 * There are two slots for node-set and misc objects.
1568
 * Use <0 for the default number (100).
1569
 *
1570
 * @param ctxt  the XPath context
1571
 * @param active  enables/disables (creates/frees) the cache
1572
 * @param value  a value with semantics dependent on `options`
1573
 * @param options  options (currently only the value 0 is used)
1574
 * @returns 0 if the setting succeeded, and -1 on API or internal errors.
1575
 */
1576
int
1577
xmlXPathContextSetCache(xmlXPathContext *ctxt,
1578
      int active,
1579
      int value,
1580
      int options)
1581
24.8k
{
1582
24.8k
    if (ctxt == NULL)
1583
0
  return(-1);
1584
24.8k
    if (active) {
1585
24.8k
  xmlXPathContextCachePtr cache;
1586
1587
24.8k
  if (ctxt->cache == NULL) {
1588
24.8k
      ctxt->cache = xmlXPathNewCache();
1589
24.8k
      if (ctxt->cache == NULL) {
1590
565
                xmlXPathErrMemory(ctxt);
1591
565
    return(-1);
1592
565
            }
1593
24.8k
  }
1594
24.2k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
24.2k
  if (options == 0) {
1596
24.2k
      if (value < 0)
1597
0
    value = 100;
1598
24.2k
      cache->maxNodeset = value;
1599
24.2k
      cache->maxMisc = value;
1600
24.2k
  }
1601
24.2k
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
24.2k
    return(0);
1606
24.8k
}
1607
1608
/**
1609
 * This is the cached version of #xmlXPathWrapNodeSet.
1610
 * Wrap the Nodeset `val` in a new xmlXPathObject
1611
 *
1612
 * In case of error the node set is destroyed and NULL is returned.
1613
 *
1614
 * @param pctxt  the XPath context
1615
 * @param val  the NodePtr value
1616
 * @returns the created or reused object.
1617
 */
1618
static xmlXPathObjectPtr
1619
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1620
2.92M
{
1621
2.92M
    xmlXPathObjectPtr ret;
1622
2.92M
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
2.92M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
401k
  xmlXPathContextCachePtr cache =
1626
401k
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
401k
  if (cache->miscObjs != NULL) {
1629
369k
      ret = cache->miscObjs;
1630
369k
            cache->miscObjs = (void *) ret->stringval;
1631
369k
            cache->numMisc -= 1;
1632
369k
            ret->stringval = NULL;
1633
369k
      ret->type = XPATH_NODESET;
1634
369k
      ret->nodesetval = val;
1635
369k
      return(ret);
1636
369k
  }
1637
401k
    }
1638
1639
2.55M
    ret = xmlXPathWrapNodeSet(val);
1640
2.55M
    if (ret == NULL)
1641
311
        xmlXPathPErrMemory(pctxt);
1642
2.55M
    return(ret);
1643
2.92M
}
1644
1645
/**
1646
 * This is the cached version of #xmlXPathWrapString.
1647
 * Wraps the `val` string into an XPath object.
1648
 *
1649
 * @param pctxt  the XPath context
1650
 * @param val  the xmlChar * value
1651
 * @returns the created or reused object.
1652
 */
1653
static xmlXPathObjectPtr
1654
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1655
171k
{
1656
171k
    xmlXPathObjectPtr ret;
1657
171k
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
171k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
35.3k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
35.3k
  if (cache->miscObjs != NULL) {
1663
31.9k
      ret = cache->miscObjs;
1664
31.9k
            cache->miscObjs = (void *) ret->stringval;
1665
31.9k
            cache->numMisc -= 1;
1666
31.9k
      ret->type = XPATH_STRING;
1667
31.9k
      ret->stringval = val;
1668
31.9k
      return(ret);
1669
31.9k
  }
1670
35.3k
    }
1671
1672
139k
    ret = xmlXPathWrapString(val);
1673
139k
    if (ret == NULL)
1674
54
        xmlXPathPErrMemory(pctxt);
1675
139k
    return(ret);
1676
171k
}
1677
1678
/**
1679
 * This is the cached version of #xmlXPathNewNodeSet.
1680
 * Acquire an xmlXPathObject of type NodeSet and initialize
1681
 * it with the single Node `val`
1682
 *
1683
 * @param pctxt  the XPath context
1684
 * @param val  the NodePtr value
1685
 * @returns the created or reused object.
1686
 */
1687
static xmlXPathObjectPtr
1688
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1689
3.63M
{
1690
3.63M
    xmlXPathObjectPtr ret;
1691
3.63M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
3.63M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
476k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
476k
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
462k
      ret = cache->nodesetObjs;
1701
462k
            cache->nodesetObjs = (void *) ret->stringval;
1702
462k
            cache->numNodeset -= 1;
1703
462k
            ret->stringval = NULL;
1704
462k
      ret->type = XPATH_NODESET;
1705
462k
      ret->boolval = 0;
1706
462k
      if (val) {
1707
462k
    if ((ret->nodesetval->nodeMax == 0) ||
1708
462k
        (val->type == XML_NAMESPACE_DECL))
1709
56.5k
    {
1710
56.5k
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
9
                        xmlXPathPErrMemory(pctxt);
1712
405k
    } else {
1713
405k
        ret->nodesetval->nodeTab[0] = val;
1714
405k
        ret->nodesetval->nodeNr = 1;
1715
405k
    }
1716
462k
      }
1717
462k
      return(ret);
1718
462k
  } else if (cache->miscObjs != NULL) {
1719
3.72k
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
3.72k
      set = xmlXPathNodeSetCreate(val);
1725
3.72k
      if (set == NULL) {
1726
2
                xmlXPathPErrMemory(pctxt);
1727
2
    return(NULL);
1728
2
      }
1729
1730
3.72k
      ret = cache->miscObjs;
1731
3.72k
            cache->miscObjs = (void *) ret->stringval;
1732
3.72k
            cache->numMisc -= 1;
1733
3.72k
            ret->stringval = NULL;
1734
3.72k
      ret->type = XPATH_NODESET;
1735
3.72k
      ret->boolval = 0;
1736
3.72k
      ret->nodesetval = set;
1737
3.72k
      return(ret);
1738
3.72k
  }
1739
476k
    }
1740
3.17M
    ret = xmlXPathNewNodeSet(val);
1741
3.17M
    if (ret == NULL)
1742
624
        xmlXPathPErrMemory(pctxt);
1743
3.17M
    return(ret);
1744
3.63M
}
1745
1746
/**
1747
 * This is the cached version of #xmlXPathNewString.
1748
 * Acquire an xmlXPathObject of type string and of value `val`
1749
 *
1750
 * @param pctxt  the XPath context
1751
 * @param val  the xmlChar * value
1752
 * @returns the created or reused object.
1753
 */
1754
static xmlXPathObjectPtr
1755
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1756
1.38M
{
1757
1.38M
    xmlXPathObjectPtr ret;
1758
1.38M
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
1.38M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
45.2k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
45.2k
  if (cache->miscObjs != NULL) {
1764
40.5k
            xmlChar *copy;
1765
1766
40.5k
            if (val == NULL)
1767
275
                val = BAD_CAST "";
1768
40.5k
            copy = xmlStrdup(val);
1769
40.5k
            if (copy == NULL) {
1770
9
                xmlXPathPErrMemory(pctxt);
1771
9
                return(NULL);
1772
9
            }
1773
1774
40.5k
      ret = cache->miscObjs;
1775
40.5k
            cache->miscObjs = (void *) ret->stringval;
1776
40.5k
            cache->numMisc -= 1;
1777
40.5k
      ret->type = XPATH_STRING;
1778
40.5k
            ret->stringval = copy;
1779
40.5k
      return(ret);
1780
40.5k
  }
1781
45.2k
    }
1782
1783
1.34M
    ret = xmlXPathNewString(val);
1784
1.34M
    if (ret == NULL)
1785
63
        xmlXPathPErrMemory(pctxt);
1786
1.34M
    return(ret);
1787
1.38M
}
1788
1789
/**
1790
 * This is the cached version of #xmlXPathNewCString.
1791
 * Acquire an xmlXPathObject of type string and of value `val`
1792
 *
1793
 * @param pctxt  the XPath context
1794
 * @param val  the char * value
1795
 * @returns the created or reused object.
1796
 */
1797
static xmlXPathObjectPtr
1798
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1799
17.1k
{
1800
17.1k
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
17.1k
}
1802
1803
/**
1804
 * This is the cached version of #xmlXPathNewBoolean.
1805
 * Acquires an xmlXPathObject of type boolean and of value `val`
1806
 *
1807
 * @param pctxt  the XPath context
1808
 * @param val  the boolean value
1809
 * @returns the created or reused object.
1810
 */
1811
static xmlXPathObjectPtr
1812
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1813
1.23M
{
1814
1.23M
    xmlXPathObjectPtr ret;
1815
1.23M
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
1.23M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
85.9k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
85.9k
  if (cache->miscObjs != NULL) {
1821
68.8k
      ret = cache->miscObjs;
1822
68.8k
            cache->miscObjs = (void *) ret->stringval;
1823
68.8k
            cache->numMisc -= 1;
1824
68.8k
            ret->stringval = NULL;
1825
68.8k
      ret->type = XPATH_BOOLEAN;
1826
68.8k
      ret->boolval = (val != 0);
1827
68.8k
      return(ret);
1828
68.8k
  }
1829
85.9k
    }
1830
1831
1.16M
    ret = xmlXPathNewBoolean(val);
1832
1.16M
    if (ret == NULL)
1833
124
        xmlXPathPErrMemory(pctxt);
1834
1.16M
    return(ret);
1835
1.23M
}
1836
1837
/**
1838
 * This is the cached version of #xmlXPathNewFloat.
1839
 * Acquires an xmlXPathObject of type double and of value `val`
1840
 *
1841
 * @param pctxt  the XPath context
1842
 * @param val  the double value
1843
 * @returns the created or reused object.
1844
 */
1845
static xmlXPathObjectPtr
1846
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1847
2.85M
{
1848
2.85M
    xmlXPathObjectPtr ret;
1849
2.85M
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
2.85M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
441k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
441k
  if (cache->miscObjs != NULL) {
1855
410k
      ret = cache->miscObjs;
1856
410k
            cache->miscObjs = (void *) ret->stringval;
1857
410k
            cache->numMisc -= 1;
1858
410k
            ret->stringval = NULL;
1859
410k
      ret->type = XPATH_NUMBER;
1860
410k
      ret->floatval = val;
1861
410k
      return(ret);
1862
410k
  }
1863
441k
    }
1864
1865
2.44M
    ret = xmlXPathNewFloat(val);
1866
2.44M
    if (ret == NULL)
1867
214
        xmlXPathPErrMemory(pctxt);
1868
2.44M
    return(ret);
1869
2.85M
}
1870
1871
/**
1872
 * This is the cached version of #xmlXPathObjectCopy.
1873
 * Acquire a copy of a given object
1874
 *
1875
 * @param pctxt  the XPath context
1876
 * @param val  the original object
1877
 * @returns a created or reused created object.
1878
 */
1879
static xmlXPathObjectPtr
1880
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1881
1.58M
{
1882
1.58M
    xmlXPathObjectPtr ret;
1883
1.58M
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
1.58M
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
1.58M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
344k
  switch (val->type) {
1890
0
            case XPATH_NODESET: {
1891
0
                xmlNodeSetPtr set;
1892
1893
0
                set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1894
0
                if (set == NULL) {
1895
0
                    xmlXPathPErrMemory(pctxt);
1896
0
                    return(NULL);
1897
0
                }
1898
0
                return(xmlXPathCacheWrapNodeSet(pctxt, set));
1899
0
            }
1900
16.4k
      case XPATH_STRING:
1901
16.4k
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
328k
      case XPATH_NUMBER:
1905
328k
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
344k
  }
1909
344k
    }
1910
1.24M
    ret = xmlXPathObjectCopy(val);
1911
1.24M
    if (ret == NULL)
1912
126
        xmlXPathPErrMemory(pctxt);
1913
1.24M
    return(ret);
1914
1.58M
}
1915
1916
/************************************************************************
1917
 *                  *
1918
 *    Parser stacks related functions and macros    *
1919
 *                  *
1920
 ************************************************************************/
1921
1922
/**
1923
 * Converts an XPath object to its number value
1924
 *
1925
 * @param ctxt  parser context
1926
 * @param val  an XPath object
1927
 * @returns the number value
1928
 */
1929
static double
1930
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1931
3.27M
                             xmlXPathObjectPtr val) {
1932
3.27M
    double ret = 0.0;
1933
1934
3.27M
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
3.27M
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
1.13M
    case XPATH_NODESET:
1941
1.13M
    case XPATH_XSLT_TREE: {
1942
1.13M
        xmlChar *str;
1943
1944
1.13M
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
1.13M
        if (str == NULL) {
1946
124
            xmlXPathPErrMemory(ctxt);
1947
124
            ret = xmlXPathNAN;
1948
1.13M
        } else {
1949
1.13M
      ret = xmlXPathCastStringToNumber(str);
1950
1.13M
            xmlFree(str);
1951
1.13M
        }
1952
1.13M
  break;
1953
1.13M
    }
1954
1.61M
    case XPATH_STRING:
1955
1.61M
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
1.61M
  break;
1957
370k
    case XPATH_NUMBER:
1958
370k
  ret = val->floatval;
1959
370k
  break;
1960
154k
    case XPATH_BOOLEAN:
1961
154k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
154k
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
3.27M
    }
1968
3.27M
    return(ret);
1969
3.27M
}
1970
1971
/**
1972
 * Pops the top XPath object from the value stack
1973
 *
1974
 * @param ctxt  an XPath evaluation context
1975
 * @returns the XPath object just removed
1976
 */
1977
xmlXPathObject *
1978
xmlXPathValuePop(xmlXPathParserContext *ctxt)
1979
15.0M
{
1980
15.0M
    xmlXPathObjectPtr ret;
1981
1982
15.0M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
42.6k
        return (NULL);
1984
1985
14.9M
    ctxt->valueNr--;
1986
14.9M
    if (ctxt->valueNr > 0)
1987
9.60M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
5.35M
    else
1989
5.35M
        ctxt->value = NULL;
1990
14.9M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
14.9M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
14.9M
    return (ret);
1993
15.0M
}
1994
1995
/**
1996
 * Pushes a new XPath object on top of the value stack. If value is NULL,
1997
 * a memory error is recorded in the parser context.
1998
 *
1999
 * The object is destroyed in case of error.
2000
 *
2001
 * @param ctxt  an XPath evaluation context
2002
 * @param value  the XPath object
2003
 * @returns the number of items on the value stack, or -1 in case of error.
2004
 */
2005
int
2006
xmlXPathValuePush(xmlXPathParserContext *ctxt, xmlXPathObject *value)
2007
15.0M
{
2008
15.0M
    if (ctxt == NULL) return(-1);
2009
15.0M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
1.55k
        xmlXPathPErrMemory(ctxt);
2014
1.55k
        return(-1);
2015
1.55k
    }
2016
15.0M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
8.62k
        xmlXPathObjectPtr *tmp;
2018
8.62k
        int newSize;
2019
2020
8.62k
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
8.62k
                                  10, XPATH_MAX_STACK_DEPTH);
2022
8.62k
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
8.62k
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
8.62k
        if (tmp == NULL) {
2029
3
            xmlXPathPErrMemory(ctxt);
2030
3
            xmlXPathFreeObject(value);
2031
3
            return (-1);
2032
3
        }
2033
8.62k
  ctxt->valueTab = tmp;
2034
8.62k
        ctxt->valueMax = newSize;
2035
8.62k
    }
2036
15.0M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
15.0M
    ctxt->value = value;
2038
15.0M
    return (ctxt->valueNr++);
2039
15.0M
}
2040
2041
/**
2042
 * Pops a boolean from the stack, handling conversion if needed.
2043
 * Check error with xmlXPathCheckError.
2044
 *
2045
 * @param ctxt  an XPath parser context
2046
 * @returns the boolean
2047
 */
2048
int
2049
0
xmlXPathPopBoolean (xmlXPathParserContext *ctxt) {
2050
0
    xmlXPathObjectPtr obj;
2051
0
    int ret;
2052
2053
0
    obj = xmlXPathValuePop(ctxt);
2054
0
    if (obj == NULL) {
2055
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2056
0
  return(0);
2057
0
    }
2058
0
    if (obj->type != XPATH_BOOLEAN)
2059
0
  ret = xmlXPathCastToBoolean(obj);
2060
0
    else
2061
0
        ret = obj->boolval;
2062
0
    xmlXPathReleaseObject(ctxt->context, obj);
2063
0
    return(ret);
2064
0
}
2065
2066
/**
2067
 * Pops a number from the stack, handling conversion if needed.
2068
 * Check error with xmlXPathCheckError.
2069
 *
2070
 * @param ctxt  an XPath parser context
2071
 * @returns the number
2072
 */
2073
double
2074
0
xmlXPathPopNumber (xmlXPathParserContext *ctxt) {
2075
0
    xmlXPathObjectPtr obj;
2076
0
    double ret;
2077
2078
0
    obj = xmlXPathValuePop(ctxt);
2079
0
    if (obj == NULL) {
2080
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2081
0
  return(0);
2082
0
    }
2083
0
    if (obj->type != XPATH_NUMBER)
2084
0
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2085
0
    else
2086
0
        ret = obj->floatval;
2087
0
    xmlXPathReleaseObject(ctxt->context, obj);
2088
0
    return(ret);
2089
0
}
2090
2091
/**
2092
 * Pops a string from the stack, handling conversion if needed.
2093
 * Check error with xmlXPathCheckError.
2094
 *
2095
 * @param ctxt  an XPath parser context
2096
 * @returns the string
2097
 */
2098
xmlChar *
2099
0
xmlXPathPopString (xmlXPathParserContext *ctxt) {
2100
0
    xmlXPathObjectPtr obj;
2101
0
    xmlChar * ret;
2102
2103
0
    obj = xmlXPathValuePop(ctxt);
2104
0
    if (obj == NULL) {
2105
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2106
0
  return(NULL);
2107
0
    }
2108
0
    ret = xmlXPathCastToString(obj);
2109
0
    if (ret == NULL)
2110
0
        xmlXPathPErrMemory(ctxt);
2111
0
    xmlXPathReleaseObject(ctxt->context, obj);
2112
0
    return(ret);
2113
0
}
2114
2115
/**
2116
 * Pops a node-set from the stack, handling conversion if needed.
2117
 * Check error with xmlXPathCheckError.
2118
 *
2119
 * @param ctxt  an XPath parser context
2120
 * @returns the node-set
2121
 */
2122
xmlNodeSet *
2123
0
xmlXPathPopNodeSet (xmlXPathParserContext *ctxt) {
2124
0
    xmlXPathObjectPtr obj;
2125
0
    xmlNodeSetPtr ret;
2126
2127
0
    if (ctxt == NULL) return(NULL);
2128
0
    if (ctxt->value == NULL) {
2129
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2130
0
  return(NULL);
2131
0
    }
2132
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2133
0
  xmlXPathSetTypeError(ctxt);
2134
0
  return(NULL);
2135
0
    }
2136
0
    obj = xmlXPathValuePop(ctxt);
2137
0
    ret = obj->nodesetval;
2138
0
    obj->nodesetval = NULL;
2139
0
    xmlXPathReleaseObject(ctxt->context, obj);
2140
0
    return(ret);
2141
0
}
2142
2143
/**
2144
 * Pops an external object from the stack, handling conversion if needed.
2145
 * Check error with xmlXPathCheckError.
2146
 *
2147
 * @param ctxt  an XPath parser context
2148
 * @returns the object
2149
 */
2150
void *
2151
0
xmlXPathPopExternal (xmlXPathParserContext *ctxt) {
2152
0
    xmlXPathObjectPtr obj;
2153
0
    void * ret;
2154
2155
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2156
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2157
0
  return(NULL);
2158
0
    }
2159
0
    if (ctxt->value->type != XPATH_USERS) {
2160
0
  xmlXPathSetTypeError(ctxt);
2161
0
  return(NULL);
2162
0
    }
2163
0
    obj = xmlXPathValuePop(ctxt);
2164
0
    ret = obj->user;
2165
0
    obj->user = NULL;
2166
0
    xmlXPathReleaseObject(ctxt->context, obj);
2167
0
    return(ret);
2168
0
}
2169
2170
/*
2171
 * Macros for accessing the content. Those should be used only by the parser,
2172
 * and not exported.
2173
 *
2174
 * Dirty macros, i.e. one need to make assumption on the context to use them
2175
 *
2176
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2177
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2178
 *           in ISO-Latin or UTF-8.
2179
 *           This should be used internally by the parser
2180
 *           only to compare to ASCII values otherwise it would break when
2181
 *           running with UTF-8 encoding.
2182
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2183
 *           to compare on ASCII based substring.
2184
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2185
 *           strings within the parser.
2186
 *   CURRENT Returns the current char value, with the full decoding of
2187
 *           UTF-8 if we are using this mode. It returns an int.
2188
 *   NEXT    Skip to the next character, this does the proper decoding
2189
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2190
 *           It returns the pointer to the current xmlChar.
2191
 */
2192
2193
379M
#define CUR (*ctxt->cur)
2194
217k
#define SKIP(val) ctxt->cur += (val)
2195
18.0M
#define NXT(val) ctxt->cur[(val)]
2196
28.9M
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
175M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
97.9M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2203
2204
2205
#ifndef DBL_DIG
2206
#define DBL_DIG 16
2207
#endif
2208
#ifndef DBL_EPSILON
2209
#define DBL_EPSILON 1E-9
2210
#endif
2211
2212
11.2k
#define UPPER_DOUBLE 1E9
2213
4.04k
#define LOWER_DOUBLE 1E-5
2214
#define LOWER_DOUBLE_EXP 5
2215
2216
#define INTEGER_DIGITS DBL_DIG
2217
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2218
8.78k
#define EXPONENT_DIGITS (3 + 2)
2219
2220
/**
2221
 * Convert the number into a string representation.
2222
 *
2223
 * @param number  number to format
2224
 * @param buffer  output buffer
2225
 * @param buffersize  size of output buffer
2226
 */
2227
static void
2228
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2229
18.5k
{
2230
18.5k
    switch (xmlXPathIsInf(number)) {
2231
0
    case 1:
2232
0
  if (buffersize > (int)sizeof("Infinity"))
2233
0
      snprintf(buffer, buffersize, "Infinity");
2234
0
  break;
2235
0
    case -1:
2236
0
  if (buffersize > (int)sizeof("-Infinity"))
2237
0
      snprintf(buffer, buffersize, "-Infinity");
2238
0
  break;
2239
18.5k
    default:
2240
18.5k
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
18.5k
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
18.5k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
18.5k
                   (number == (int) number)) {
2248
7.27k
      char work[30];
2249
7.27k
      char *ptr, *cur;
2250
7.27k
      int value = (int) number;
2251
2252
7.27k
            ptr = &buffer[0];
2253
7.27k
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
7.27k
      } else {
2256
7.27k
    snprintf(work, 29, "%d", value);
2257
7.27k
    cur = &work[0];
2258
24.8k
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
17.5k
        *ptr++ = *cur++;
2260
17.5k
    }
2261
7.27k
      }
2262
7.27k
      if (ptr - buffer < buffersize) {
2263
7.27k
    *ptr = 0;
2264
7.27k
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
11.2k
  } else {
2269
      /*
2270
        For the dimension of work,
2271
            DBL_DIG is number of significant digits
2272
      EXPONENT is only needed for "scientific notation"
2273
            3 is sign, decimal point, and terminating zero
2274
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2275
        Note that this dimension is slightly (a few characters)
2276
        larger than actually necessary.
2277
      */
2278
11.2k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
11.2k
      int integer_place, fraction_place;
2280
11.2k
      char *ptr;
2281
11.2k
      char *after_fraction;
2282
11.2k
      double absolute_value;
2283
11.2k
      int size;
2284
2285
11.2k
      absolute_value = fabs(number);
2286
2287
      /*
2288
       * First choose format - scientific or regular floating point.
2289
       * In either case, result is in work, and after_fraction points
2290
       * just past the fractional part.
2291
      */
2292
11.2k
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
11.2k
      (absolute_value < LOWER_DOUBLE)) &&
2294
11.2k
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
8.78k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
8.78k
    fraction_place = DBL_DIG - 1;
2298
8.78k
    size = snprintf(work, sizeof(work),"%*.*e",
2299
8.78k
       integer_place, fraction_place, number);
2300
45.5k
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
8.78k
      }
2303
2.51k
      else {
2304
    /* Use regular notation */
2305
2.51k
    if (absolute_value > 0.0) {
2306
2.51k
        integer_place = (int)log10(absolute_value);
2307
2.51k
        if (integer_place > 0)
2308
1.09k
            fraction_place = DBL_DIG - integer_place - 1;
2309
1.41k
        else
2310
1.41k
            fraction_place = DBL_DIG - integer_place;
2311
2.51k
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
2.51k
    size = snprintf(work, sizeof(work), "%0.*f",
2315
2.51k
        fraction_place, number);
2316
2.51k
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
15.7k
      while (work[0] == ' ') {
2320
93.6k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
4.45k
    size--;
2322
4.45k
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
11.2k
      after_fraction = work + size;
2326
11.2k
      ptr = after_fraction;
2327
90.4k
      while (*(--ptr) == '0')
2328
79.1k
    ;
2329
11.2k
      if (*ptr != '.')
2330
8.66k
          ptr++;
2331
48.1k
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
11.2k
      size = strlen(work) + 1;
2335
11.2k
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
11.2k
      memmove(buffer, work, size);
2340
11.2k
  }
2341
18.5k
  break;
2342
18.5k
    }
2343
18.5k
}
2344
2345
2346
/************************************************************************
2347
 *                  *
2348
 *      Routines to handle NodeSets     *
2349
 *                  *
2350
 ************************************************************************/
2351
2352
/**
2353
 * Call this routine to speed up XPath computation on static documents.
2354
 * This stamps all the element nodes with the document order
2355
 * Like for line information, the order is kept in the element->content
2356
 * field, the value stored is actually - the node number (starting at -1)
2357
 * to be able to differentiate from line numbers.
2358
 *
2359
 * @param doc  an input document
2360
 * @returns the number of elements found in the document or -1 in case
2361
 *    of error.
2362
 */
2363
long
2364
8.58k
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
8.58k
    XML_INTPTR_T count = 0;
2366
8.58k
    xmlNodePtr cur;
2367
2368
8.58k
    if (doc == NULL)
2369
0
  return(-1);
2370
8.58k
    cur = doc->children;
2371
25.7k
    while (cur != NULL) {
2372
17.1k
  if (cur->type == XML_ELEMENT_NODE) {
2373
8.58k
            count += 1;
2374
8.58k
            cur->content = XML_INT_TO_PTR(-count);
2375
8.58k
      if (cur->children != NULL) {
2376
8.58k
    cur = cur->children;
2377
8.58k
    continue;
2378
8.58k
      }
2379
8.58k
  }
2380
8.58k
  if (cur->next != NULL) {
2381
0
      cur = cur->next;
2382
0
      continue;
2383
0
  }
2384
17.1k
  do {
2385
17.1k
      cur = cur->parent;
2386
17.1k
      if (cur == NULL)
2387
0
    break;
2388
17.1k
      if (cur == (xmlNodePtr) doc) {
2389
8.58k
    cur = NULL;
2390
8.58k
    break;
2391
8.58k
      }
2392
8.58k
      if (cur->next != NULL) {
2393
0
    cur = cur->next;
2394
0
    break;
2395
0
      }
2396
8.58k
  } while (cur != NULL);
2397
8.58k
    }
2398
8.58k
    return(count);
2399
8.58k
}
2400
2401
/**
2402
 * Compare two nodes w.r.t document order
2403
 *
2404
 * @param node1  the first node
2405
 * @param node2  the second node
2406
 * @returns -2 in case of error 1 if first point < second point, 0 if
2407
 *         it's the same node, -1 otherwise
2408
 */
2409
int
2410
0
xmlXPathCmpNodes(xmlNode *node1, xmlNode *node2) {
2411
0
    int depth1, depth2;
2412
0
    int attr1 = 0, attr2 = 0;
2413
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2414
0
    xmlNodePtr cur, root;
2415
2416
0
    if ((node1 == NULL) || (node2 == NULL))
2417
0
  return(-2);
2418
    /*
2419
     * a couple of optimizations which will avoid computations in most cases
2420
     */
2421
0
    if (node1 == node2)   /* trivial case */
2422
0
  return(0);
2423
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2424
0
  attr1 = 1;
2425
0
  attrNode1 = node1;
2426
0
  node1 = node1->parent;
2427
0
    }
2428
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2429
0
  attr2 = 1;
2430
0
  attrNode2 = node2;
2431
0
  node2 = node2->parent;
2432
0
    }
2433
0
    if (node1 == node2) {
2434
0
  if (attr1 == attr2) {
2435
      /* not required, but we keep attributes in order */
2436
0
      if (attr1 != 0) {
2437
0
          cur = attrNode2->prev;
2438
0
    while (cur != NULL) {
2439
0
        if (cur == attrNode1)
2440
0
            return (1);
2441
0
        cur = cur->prev;
2442
0
    }
2443
0
    return (-1);
2444
0
      }
2445
0
      return(0);
2446
0
  }
2447
0
  if (attr2 == 1)
2448
0
      return(1);
2449
0
  return(-1);
2450
0
    }
2451
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2452
0
        (node2->type == XML_NAMESPACE_DECL))
2453
0
  return(1);
2454
0
    if (node1 == node2->prev)
2455
0
  return(1);
2456
0
    if (node1 == node2->next)
2457
0
  return(-1);
2458
2459
    /*
2460
     * Speedup using document order if available.
2461
     */
2462
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2463
0
  (node2->type == XML_ELEMENT_NODE) &&
2464
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2465
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2466
0
  (node1->doc == node2->doc)) {
2467
0
  XML_INTPTR_T l1, l2;
2468
2469
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2470
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2471
0
  if (l1 < l2)
2472
0
      return(1);
2473
0
  if (l1 > l2)
2474
0
      return(-1);
2475
0
    }
2476
2477
    /*
2478
     * compute depth to root
2479
     */
2480
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2481
0
  if (cur->parent == node1)
2482
0
      return(1);
2483
0
  depth2++;
2484
0
    }
2485
0
    root = cur;
2486
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2487
0
  if (cur->parent == node2)
2488
0
      return(-1);
2489
0
  depth1++;
2490
0
    }
2491
    /*
2492
     * Distinct document (or distinct entities :-( ) case.
2493
     */
2494
0
    if (root != cur) {
2495
0
  return(-2);
2496
0
    }
2497
    /*
2498
     * get the nearest common ancestor.
2499
     */
2500
0
    while (depth1 > depth2) {
2501
0
  depth1--;
2502
0
  node1 = node1->parent;
2503
0
    }
2504
0
    while (depth2 > depth1) {
2505
0
  depth2--;
2506
0
  node2 = node2->parent;
2507
0
    }
2508
0
    while (node1->parent != node2->parent) {
2509
0
  node1 = node1->parent;
2510
0
  node2 = node2->parent;
2511
  /* should not happen but just in case ... */
2512
0
  if ((node1 == NULL) || (node2 == NULL))
2513
0
      return(-2);
2514
0
    }
2515
    /*
2516
     * Find who's first.
2517
     */
2518
0
    if (node1 == node2->prev)
2519
0
  return(1);
2520
0
    if (node1 == node2->next)
2521
0
  return(-1);
2522
    /*
2523
     * Speedup using document order if available.
2524
     */
2525
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2526
0
  (node2->type == XML_ELEMENT_NODE) &&
2527
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2528
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2529
0
  (node1->doc == node2->doc)) {
2530
0
  XML_INTPTR_T l1, l2;
2531
2532
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2533
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2534
0
  if (l1 < l2)
2535
0
      return(1);
2536
0
  if (l1 > l2)
2537
0
      return(-1);
2538
0
    }
2539
2540
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2541
0
  if (cur == node2)
2542
0
      return(1);
2543
0
    return(-1); /* assume there is no sibling list corruption */
2544
0
}
2545
2546
/**
2547
 * Sort the node set in document order
2548
 *
2549
 * @param set  the node set
2550
 */
2551
void
2552
323k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
323k
    if (set == NULL)
2559
0
  return;
2560
2561
#ifndef WITH_TIM_SORT
2562
    /*
2563
     * Use the old Shell's sort implementation to sort the node-set
2564
     * Timsort ought to be quite faster
2565
     */
2566
    len = set->nodeNr;
2567
    for (incr = len / 2; incr > 0; incr /= 2) {
2568
  for (i = incr; i < len; i++) {
2569
      j = i - incr;
2570
      while (j >= 0) {
2571
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2572
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
2573
      set->nodeTab[j + incr]) == -1)
2574
#else
2575
    if (xmlXPathCmpNodes(set->nodeTab[j],
2576
      set->nodeTab[j + incr]) == -1)
2577
#endif
2578
    {
2579
        tmp = set->nodeTab[j];
2580
        set->nodeTab[j] = set->nodeTab[j + incr];
2581
        set->nodeTab[j + incr] = tmp;
2582
        j -= incr;
2583
    } else
2584
        break;
2585
      }
2586
  }
2587
    }
2588
#else /* WITH_TIM_SORT */
2589
323k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
323k
#endif /* WITH_TIM_SORT */
2591
323k
}
2592
2593
15.5M
#define XML_NODESET_DEFAULT 10
2594
/**
2595
 * Namespace node in libxml don't match the XPath semantic. In a node set
2596
 * the namespace nodes are duplicated and the next pointer is set to the
2597
 * parent node in the XPath semantic.
2598
 *
2599
 * @param node  the parent node of the namespace XPath node
2600
 * @param ns  the libxml namespace declaration node.
2601
 * @returns the newly created object.
2602
 */
2603
static xmlNodePtr
2604
1.43M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
1.43M
    xmlNsPtr cur;
2606
2607
1.43M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
1.43M
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2610
0
  return((xmlNodePtr) ns);
2611
2612
    /*
2613
     * Allocate a new Namespace and fill the fields.
2614
     */
2615
1.43M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
1.43M
    if (cur == NULL)
2617
37
  return(NULL);
2618
1.43M
    memset(cur, 0, sizeof(xmlNs));
2619
1.43M
    cur->type = XML_NAMESPACE_DECL;
2620
1.43M
    if (ns->href != NULL) {
2621
1.43M
  cur->href = xmlStrdup(ns->href);
2622
1.43M
        if (cur->href == NULL) {
2623
35
            xmlFree(cur);
2624
35
            return(NULL);
2625
35
        }
2626
1.43M
    }
2627
1.43M
    if (ns->prefix != NULL) {
2628
1.15M
  cur->prefix = xmlStrdup(ns->prefix);
2629
1.15M
        if (cur->prefix == NULL) {
2630
38
            xmlFree((xmlChar *) cur->href);
2631
38
            xmlFree(cur);
2632
38
            return(NULL);
2633
38
        }
2634
1.15M
    }
2635
1.43M
    cur->next = (xmlNsPtr) node;
2636
1.43M
    return((xmlNodePtr) cur);
2637
1.43M
}
2638
2639
/**
2640
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2641
 * the namespace nodes are duplicated and the next pointer is set to the
2642
 * parent node in the XPath semantic. Check if such a node needs to be freed
2643
 *
2644
 * @param ns  the XPath namespace node found in a nodeset.
2645
 */
2646
void
2647
1.43M
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
1.43M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
1.43M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
1.43M
  if (ns->href != NULL)
2653
1.43M
      xmlFree((xmlChar *)ns->href);
2654
1.43M
  if (ns->prefix != NULL)
2655
1.15M
      xmlFree((xmlChar *)ns->prefix);
2656
1.43M
  xmlFree(ns);
2657
1.43M
    }
2658
1.43M
}
2659
2660
/**
2661
 * Create a new xmlNodeSet of type double and of value `val`
2662
 *
2663
 * @param val  an initial xmlNode, or NULL
2664
 * @returns the newly created object.
2665
 */
2666
xmlNodeSet *
2667
8.04M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
8.04M
    xmlNodeSetPtr ret;
2669
2670
8.04M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
8.04M
    if (ret == NULL)
2672
540
  return(NULL);
2673
8.04M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
8.04M
    if (val != NULL) {
2675
3.17M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
3.17M
               sizeof(xmlNodePtr));
2677
3.17M
  if (ret->nodeTab == NULL) {
2678
229
      xmlFree(ret);
2679
229
      return(NULL);
2680
229
  }
2681
3.17M
  memset(ret->nodeTab, 0 ,
2682
3.17M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
3.17M
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
3.17M
  if (val->type == XML_NAMESPACE_DECL) {
2685
100k
      xmlNsPtr ns = (xmlNsPtr) val;
2686
100k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2687
2688
100k
            if (nsNode == NULL) {
2689
12
                xmlXPathFreeNodeSet(ret);
2690
12
                return(NULL);
2691
12
            }
2692
100k
      ret->nodeTab[ret->nodeNr++] = nsNode;
2693
100k
  } else
2694
3.07M
      ret->nodeTab[ret->nodeNr++] = val;
2695
3.17M
    }
2696
8.04M
    return(ret);
2697
8.04M
}
2698
2699
/**
2700
 * checks whether `cur` contains `val`
2701
 *
2702
 * @param cur  the node-set
2703
 * @param val  the node
2704
 * @returns true (1) if `cur` contains `val`, false (0) otherwise
2705
 */
2706
int
2707
0
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2708
0
    int i;
2709
2710
0
    if ((cur == NULL) || (val == NULL)) return(0);
2711
0
    if (val->type == XML_NAMESPACE_DECL) {
2712
0
  for (i = 0; i < cur->nodeNr; i++) {
2713
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2714
0
    xmlNsPtr ns1, ns2;
2715
2716
0
    ns1 = (xmlNsPtr) val;
2717
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2718
0
    if (ns1 == ns2)
2719
0
        return(1);
2720
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2721
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2722
0
        return(1);
2723
0
      }
2724
0
  }
2725
0
    } else {
2726
0
  for (i = 0; i < cur->nodeNr; i++) {
2727
0
      if (cur->nodeTab[i] == val)
2728
0
    return(1);
2729
0
  }
2730
0
    }
2731
0
    return(0);
2732
0
}
2733
2734
static int
2735
5.24M
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
5.24M
    xmlNodePtr *temp;
2737
5.24M
    int newSize;
2738
2739
5.24M
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
5.24M
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
5.24M
    if (newSize < 0)
2742
0
        return(-1);
2743
5.24M
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
5.24M
    if (temp == NULL)
2745
697
        return(-1);
2746
5.23M
    cur->nodeMax = newSize;
2747
5.23M
    cur->nodeTab = temp;
2748
2749
5.23M
    return(0);
2750
5.24M
}
2751
2752
/**
2753
 * add a new namespace node to an existing NodeSet
2754
 *
2755
 * @param cur  the initial node set
2756
 * @param node  the hosting node
2757
 * @param ns  a the namespace node
2758
 * @returns 0 in case of success and -1 in case of error
2759
 */
2760
int
2761
875k
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
875k
    int i;
2763
875k
    xmlNodePtr nsNode;
2764
2765
875k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
875k
        (ns->type != XML_NAMESPACE_DECL) ||
2767
875k
  (node->type != XML_ELEMENT_NODE))
2768
0
  return(-1);
2769
2770
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2771
    /*
2772
     * prevent duplicates
2773
     */
2774
2.71M
    for (i = 0;i < cur->nodeNr;i++) {
2775
1.84M
        if ((cur->nodeTab[i] != NULL) &&
2776
1.84M
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
1.84M
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
1.84M
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
1.84M
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
875k
    if (cur->nodeNr >= cur->nodeMax) {
2786
35.1k
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
13
            return(-1);
2788
35.1k
    }
2789
875k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
875k
    if(nsNode == NULL)
2791
46
        return(-1);
2792
875k
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
875k
    return(0);
2794
875k
}
2795
2796
/**
2797
 * add a new xmlNode to an existing NodeSet
2798
 *
2799
 * @param cur  the initial node set
2800
 * @param val  a new xmlNode
2801
 * @returns 0 in case of success, and -1 in case of error
2802
 */
2803
int
2804
95.9k
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
95.9k
    int i;
2806
2807
95.9k
    if ((cur == NULL) || (val == NULL)) return(-1);
2808
2809
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2810
    /*
2811
     * prevent duplicates
2812
     */
2813
156k
    for (i = 0;i < cur->nodeNr;i++)
2814
145k
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
11.2k
    if (cur->nodeNr >= cur->nodeMax) {
2820
11.0k
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
13
            return(-1);
2822
11.0k
    }
2823
2824
11.2k
    if (val->type == XML_NAMESPACE_DECL) {
2825
0
  xmlNsPtr ns = (xmlNsPtr) val;
2826
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2827
2828
0
        if (nsNode == NULL)
2829
0
            return(-1);
2830
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2831
0
    } else
2832
11.2k
  cur->nodeTab[cur->nodeNr++] = val;
2833
11.2k
    return(0);
2834
11.2k
}
2835
2836
/**
2837
 * add a new xmlNode to an existing NodeSet, optimized version
2838
 * when we are sure the node is not already in the set.
2839
 *
2840
 * @param cur  the initial node set
2841
 * @param val  a new xmlNode
2842
 * @returns 0 in case of success and -1 in case of failure
2843
 */
2844
int
2845
45.8M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
45.8M
    if ((cur == NULL) || (val == NULL)) return(-1);
2847
2848
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2849
    /*
2850
     * grow the nodeTab if needed
2851
     */
2852
45.8M
    if (cur->nodeNr >= cur->nodeMax) {
2853
4.15M
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
366
            return(-1);
2855
4.15M
    }
2856
2857
45.8M
    if (val->type == XML_NAMESPACE_DECL) {
2858
113k
  xmlNsPtr ns = (xmlNsPtr) val;
2859
113k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
113k
        if (nsNode == NULL)
2862
15
            return(-1);
2863
113k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
113k
    } else
2865
45.7M
  cur->nodeTab[cur->nodeNr++] = val;
2866
45.8M
    return(0);
2867
45.8M
}
2868
2869
/**
2870
 * Merges two nodesets, all nodes from `val2` are added to `val1`
2871
 * if `val1` is NULL, a new set is created and copied from `val2`
2872
 *
2873
 * Frees `val1` in case of error.
2874
 *
2875
 * @param val1  the first NodeSet or NULL
2876
 * @param val2  the second NodeSet
2877
 * @returns `val1` once extended or NULL in case of error.
2878
 */
2879
xmlNodeSet *
2880
2.10M
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
2.10M
    int i, j, initNr, skip;
2882
2.10M
    xmlNodePtr n1, n2;
2883
2884
2.10M
    if (val1 == NULL) {
2885
12
  val1 = xmlXPathNodeSetCreate(NULL);
2886
12
        if (val1 == NULL)
2887
0
            return (NULL);
2888
12
    }
2889
2.10M
    if (val2 == NULL)
2890
91
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
2.10M
    initNr = val1->nodeNr;
2894
2895
7.79M
    for (i = 0;i < val2->nodeNr;i++) {
2896
5.69M
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
5.69M
  skip = 0;
2901
48.6M
  for (j = 0; j < initNr; j++) {
2902
43.3M
      n1 = val1->nodeTab[j];
2903
43.3M
      if (n1 == n2) {
2904
325k
    skip = 1;
2905
325k
    break;
2906
42.9M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
42.9M
           (n2->type == XML_NAMESPACE_DECL)) {
2908
21.8M
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2909
21.8M
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2910
50.1k
      ((xmlNsPtr) n2)->prefix)))
2911
30.2k
    {
2912
30.2k
        skip = 1;
2913
30.2k
        break;
2914
30.2k
    }
2915
21.8M
      }
2916
43.3M
  }
2917
5.69M
  if (skip)
2918
355k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
5.33M
        if (val1->nodeNr >= val1->nodeMax) {
2924
556k
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
60
                goto error;
2926
556k
        }
2927
5.33M
  if (n2->type == XML_NAMESPACE_DECL) {
2928
346k
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
346k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
346k
            if (nsNode == NULL)
2932
37
                goto error;
2933
346k
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
346k
  } else
2935
4.98M
      val1->nodeTab[val1->nodeNr++] = n2;
2936
5.33M
    }
2937
2938
2.09M
    return(val1);
2939
2940
97
error:
2941
97
    xmlXPathFreeNodeSet(val1);
2942
97
    return(NULL);
2943
2.10M
}
2944
2945
2946
/**
2947
 * Merges two nodesets, all nodes from `set2` are added to `set1`.
2948
 * Checks for duplicate nodes. Clears set2.
2949
 *
2950
 * Frees `set1` in case of error.
2951
 *
2952
 * @param set1  the first NodeSet or NULL
2953
 * @param set2  the second NodeSet
2954
 * @returns `set1` once extended or NULL in case of error.
2955
 */
2956
static xmlNodeSetPtr
2957
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
2958
1.93M
{
2959
1.93M
    {
2960
1.93M
  int i, j, initNbSet1;
2961
1.93M
  xmlNodePtr n1, n2;
2962
2963
1.93M
  initNbSet1 = set1->nodeNr;
2964
24.4M
  for (i = 0;i < set2->nodeNr;i++) {
2965
22.4M
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
3.74G
      for (j = 0; j < initNbSet1; j++) {
2970
3.74G
    n1 = set1->nodeTab[j];
2971
3.74G
    if (n1 == n2) {
2972
19.3M
        goto skip_node;
2973
3.72G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
3.72G
        (n2->type == XML_NAMESPACE_DECL))
2975
67.2M
    {
2976
67.2M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
67.2M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
75.5k
      ((xmlNsPtr) n2)->prefix)))
2979
0
        {
2980
      /*
2981
      * Free the namespace node.
2982
      */
2983
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
2984
0
      goto skip_node;
2985
0
        }
2986
67.2M
    }
2987
3.74G
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
3.11M
            if (set1->nodeNr >= set1->nodeMax) {
2992
248k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
112
                    goto error;
2994
248k
            }
2995
3.11M
      set1->nodeTab[set1->nodeNr++] = n2;
2996
22.4M
skip_node:
2997
22.4M
            set2->nodeTab[i] = NULL;
2998
22.4M
  }
2999
1.93M
    }
3000
1.93M
    set2->nodeNr = 0;
3001
1.93M
    return(set1);
3002
3003
112
error:
3004
112
    xmlXPathFreeNodeSet(set1);
3005
112
    xmlXPathNodeSetClear(set2, 1);
3006
112
    return(NULL);
3007
1.93M
}
3008
3009
/**
3010
 * Merges two nodesets, all nodes from `set2` are added to `set1`.
3011
 * Doesn't check for duplicate nodes. Clears set2.
3012
 *
3013
 * Frees `set1` in case of error.
3014
 *
3015
 * @param set1  the first NodeSet or NULL
3016
 * @param set2  the second NodeSet
3017
 * @returns `set1` once extended or NULL in case of error.
3018
 */
3019
static xmlNodeSetPtr
3020
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3021
465k
{
3022
465k
    {
3023
465k
  int i;
3024
465k
  xmlNodePtr n2;
3025
3026
3.01M
  for (i = 0;i < set2->nodeNr;i++) {
3027
2.54M
      n2 = set2->nodeTab[i];
3028
2.54M
            if (set1->nodeNr >= set1->nodeMax) {
3029
230k
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
133
                    goto error;
3031
230k
            }
3032
2.54M
      set1->nodeTab[set1->nodeNr++] = n2;
3033
2.54M
            set2->nodeTab[i] = NULL;
3034
2.54M
  }
3035
465k
    }
3036
465k
    set2->nodeNr = 0;
3037
465k
    return(set1);
3038
3039
133
error:
3040
133
    xmlXPathFreeNodeSet(set1);
3041
133
    xmlXPathNodeSetClear(set2, 1);
3042
133
    return(NULL);
3043
465k
}
3044
3045
/**
3046
 * Removes an xmlNode from an existing NodeSet
3047
 *
3048
 * @param cur  the initial node set
3049
 * @param val  an xmlNode
3050
 */
3051
void
3052
0
xmlXPathNodeSetDel(xmlNodeSet *cur, xmlNode *val) {
3053
0
    int i;
3054
3055
0
    if (cur == NULL) return;
3056
0
    if (val == NULL) return;
3057
3058
    /*
3059
     * find node in nodeTab
3060
     */
3061
0
    for (i = 0;i < cur->nodeNr;i++)
3062
0
        if (cur->nodeTab[i] == val) break;
3063
3064
0
    if (i >= cur->nodeNr) { /* not found */
3065
0
        return;
3066
0
    }
3067
0
    if ((cur->nodeTab[i] != NULL) &&
3068
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3069
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3070
0
    cur->nodeNr--;
3071
0
    for (;i < cur->nodeNr;i++)
3072
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
3073
0
    cur->nodeTab[cur->nodeNr] = NULL;
3074
0
}
3075
3076
/**
3077
 * Removes an entry from an existing NodeSet list.
3078
 *
3079
 * @param cur  the initial node set
3080
 * @param val  the index to remove
3081
 */
3082
void
3083
0
xmlXPathNodeSetRemove(xmlNodeSet *cur, int val) {
3084
0
    if (cur == NULL) return;
3085
0
    if (val >= cur->nodeNr) return;
3086
0
    if ((cur->nodeTab[val] != NULL) &&
3087
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3088
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3089
0
    cur->nodeNr--;
3090
0
    for (;val < cur->nodeNr;val++)
3091
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
3092
0
    cur->nodeTab[cur->nodeNr] = NULL;
3093
0
}
3094
3095
/**
3096
 * Free the NodeSet compound (not the actual nodes !).
3097
 *
3098
 * @param obj  the xmlNodeSet to free
3099
 */
3100
void
3101
8.02M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
8.02M
    if (obj == NULL) return;
3103
8.02M
    if (obj->nodeTab != NULL) {
3104
4.36M
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
37.3M
  for (i = 0;i < obj->nodeNr;i++)
3108
32.9M
      if ((obj->nodeTab[i] != NULL) &&
3109
32.9M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
1.10M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
4.36M
  xmlFree(obj->nodeTab);
3112
4.36M
    }
3113
8.02M
    xmlFree(obj);
3114
8.02M
}
3115
3116
/**
3117
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3118
 * are feed) starting with the entry at `pos`, but does *not* free the list
3119
 * itself. Sets the length of the list to `pos`.
3120
 *
3121
 * @param set  the node set to be cleared
3122
 * @param pos  the start position to clear from
3123
 * @param hasNsNodes  the node set might contain namespace nodes
3124
 */
3125
static void
3126
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3127
19.0k
{
3128
19.0k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
19.0k
    else if ((hasNsNodes)) {
3131
16.4k
  int i;
3132
16.4k
  xmlNodePtr node;
3133
3134
577k
  for (i = pos; i < set->nodeNr; i++) {
3135
561k
      node = set->nodeTab[i];
3136
561k
      if ((node != NULL) &&
3137
561k
    (node->type == XML_NAMESPACE_DECL))
3138
44.8k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
561k
  }
3140
16.4k
    }
3141
19.0k
    set->nodeNr = pos;
3142
19.0k
}
3143
3144
/**
3145
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3146
 * are feed), but does *not* free the list itself. Sets the length of the
3147
 * list to 0.
3148
 *
3149
 * @param set  the node set to clear
3150
 * @param hasNsNodes  the node set might contain namespace nodes
3151
 */
3152
static void
3153
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3154
4.36k
{
3155
4.36k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
4.36k
}
3157
3158
/**
3159
 * Move the last node to the first position and clear temporary XPath objects
3160
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3161
 * to 1.
3162
 *
3163
 * @param set  the node set to be cleared
3164
 */
3165
static void
3166
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3167
13.4k
{
3168
13.4k
    int i;
3169
13.4k
    xmlNodePtr node;
3170
3171
13.4k
    if ((set == NULL) || (set->nodeNr <= 1))
3172
0
  return;
3173
432k
    for (i = 0; i < set->nodeNr - 1; i++) {
3174
419k
        node = set->nodeTab[i];
3175
419k
        if ((node != NULL) &&
3176
419k
            (node->type == XML_NAMESPACE_DECL))
3177
83.0k
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3178
419k
    }
3179
13.4k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3180
13.4k
    set->nodeNr = 1;
3181
13.4k
}
3182
3183
/**
3184
 * Create a new xmlXPathObject of type NodeSet and initialize
3185
 * it with the single Node `val`
3186
 *
3187
 * @param val  the NodePtr value
3188
 * @returns the newly created object.
3189
 */
3190
xmlXPathObject *
3191
3.17M
xmlXPathNewNodeSet(xmlNode *val) {
3192
3.17M
    xmlXPathObjectPtr ret;
3193
3194
3.17M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
3.17M
    if (ret == NULL)
3196
206
  return(NULL);
3197
3.17M
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
3.17M
    ret->type = XPATH_NODESET;
3199
3.17M
    ret->boolval = 0;
3200
3.17M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
3.17M
    if (ret->nodesetval == NULL) {
3202
448
        xmlFree(ret);
3203
448
        return(NULL);
3204
448
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
3.17M
    return(ret);
3207
3.17M
}
3208
3209
/**
3210
 * Create a new xmlXPathObject of type Value Tree (XSLT) and initialize
3211
 * it with the tree root `val`
3212
 *
3213
 * @param val  the NodePtr value
3214
 * @returns the newly created object.
3215
 */
3216
xmlXPathObject *
3217
0
xmlXPathNewValueTree(xmlNode *val) {
3218
0
    xmlXPathObjectPtr ret;
3219
3220
0
    ret = xmlXPathNewNodeSet(val);
3221
0
    if (ret == NULL)
3222
0
  return(NULL);
3223
0
    ret->type = XPATH_XSLT_TREE;
3224
3225
0
    return(ret);
3226
0
}
3227
3228
/**
3229
 * Create a new xmlXPathObject of type NodeSet and initialize
3230
 * it with the Nodeset `val`
3231
 *
3232
 * @param val  an existing NodeSet
3233
 * @returns the newly created object.
3234
 */
3235
xmlXPathObject *
3236
xmlXPathNewNodeSetList(xmlNodeSet *val)
3237
0
{
3238
0
    xmlXPathObjectPtr ret;
3239
3240
0
    if (val == NULL)
3241
0
        ret = NULL;
3242
0
    else if (val->nodeTab == NULL)
3243
0
        ret = xmlXPathNewNodeSet(NULL);
3244
0
    else {
3245
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3246
0
        if (ret) {
3247
0
            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3248
0
            if (ret->nodesetval == NULL) {
3249
0
                xmlFree(ret);
3250
0
                return(NULL);
3251
0
            }
3252
0
        }
3253
0
    }
3254
3255
0
    return (ret);
3256
0
}
3257
3258
/**
3259
 * Wrap the Nodeset `val` in a new xmlXPathObject
3260
 *
3261
 * In case of error the node set is destroyed and NULL is returned.
3262
 *
3263
 * @param val  the NodePtr value
3264
 * @returns the newly created object.
3265
 */
3266
xmlXPathObject *
3267
2.55M
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
2.55M
    xmlXPathObjectPtr ret;
3269
3270
2.55M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
2.55M
    if (ret == NULL) {
3272
311
        xmlXPathFreeNodeSet(val);
3273
311
  return(NULL);
3274
311
    }
3275
2.55M
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
2.55M
    ret->type = XPATH_NODESET;
3277
2.55M
    ret->nodesetval = val;
3278
2.55M
    return(ret);
3279
2.55M
}
3280
3281
/**
3282
 * Free up the xmlXPathObject `obj` but don't deallocate the objects in
3283
 * the list contrary to #xmlXPathFreeObject.
3284
 *
3285
 * @param obj  an existing NodeSetList object
3286
 */
3287
void
3288
0
xmlXPathFreeNodeSetList(xmlXPathObject *obj) {
3289
0
    if (obj == NULL) return;
3290
0
    xmlFree(obj);
3291
0
}
3292
3293
/**
3294
 * Implements the EXSLT - Sets difference() function:
3295
 *    node-set set:difference (node-set, node-set)
3296
 *
3297
 * @param nodes1  a node-set
3298
 * @param nodes2  a node-set
3299
 * @returns the difference between the two node sets, or nodes1 if
3300
 *         nodes2 is empty
3301
 */
3302
xmlNodeSet *
3303
0
xmlXPathDifference (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3304
0
    xmlNodeSetPtr ret;
3305
0
    int i, l1;
3306
0
    xmlNodePtr cur;
3307
3308
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3309
0
  return(nodes1);
3310
3311
0
    ret = xmlXPathNodeSetCreate(NULL);
3312
0
    if (ret == NULL)
3313
0
        return(NULL);
3314
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3315
0
  return(ret);
3316
3317
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3318
3319
0
    for (i = 0; i < l1; i++) {
3320
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3321
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3322
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3323
0
                xmlXPathFreeNodeSet(ret);
3324
0
          return(NULL);
3325
0
            }
3326
0
  }
3327
0
    }
3328
0
    return(ret);
3329
0
}
3330
3331
/**
3332
 * Implements the EXSLT - Sets intersection() function:
3333
 *    node-set set:intersection (node-set, node-set)
3334
 *
3335
 * @param nodes1  a node-set
3336
 * @param nodes2  a node-set
3337
 * @returns a node set comprising the nodes that are within both the
3338
 *         node sets passed as arguments
3339
 */
3340
xmlNodeSet *
3341
0
xmlXPathIntersection (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3342
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3343
0
    int i, l1;
3344
0
    xmlNodePtr cur;
3345
3346
0
    if (ret == NULL)
3347
0
        return(ret);
3348
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3349
0
  return(ret);
3350
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3351
0
  return(ret);
3352
3353
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3354
3355
0
    for (i = 0; i < l1; i++) {
3356
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3357
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3358
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3359
0
                xmlXPathFreeNodeSet(ret);
3360
0
          return(NULL);
3361
0
            }
3362
0
  }
3363
0
    }
3364
0
    return(ret);
3365
0
}
3366
3367
/**
3368
 * Implements the EXSLT - Sets distinct() function:
3369
 *    node-set set:distinct (node-set)
3370
 *
3371
 * @param nodes  a node-set, sorted by document order
3372
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3373
 *         it is empty
3374
 */
3375
xmlNodeSet *
3376
0
xmlXPathDistinctSorted (xmlNodeSet *nodes) {
3377
0
    xmlNodeSetPtr ret;
3378
0
    xmlHashTablePtr hash;
3379
0
    int i, l;
3380
0
    xmlChar * strval;
3381
0
    xmlNodePtr cur;
3382
3383
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3384
0
  return(nodes);
3385
3386
0
    ret = xmlXPathNodeSetCreate(NULL);
3387
0
    if (ret == NULL)
3388
0
        return(ret);
3389
0
    l = xmlXPathNodeSetGetLength(nodes);
3390
0
    hash = xmlHashCreate (l);
3391
0
    for (i = 0; i < l; i++) {
3392
0
  cur = xmlXPathNodeSetItem(nodes, i);
3393
0
  strval = xmlXPathCastNodeToString(cur);
3394
0
  if (xmlHashLookup(hash, strval) == NULL) {
3395
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3396
0
                xmlFree(strval);
3397
0
                goto error;
3398
0
            }
3399
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3400
0
          goto error;
3401
0
  } else {
3402
0
      xmlFree(strval);
3403
0
  }
3404
0
    }
3405
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3406
0
    return(ret);
3407
3408
0
error:
3409
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3410
0
    xmlXPathFreeNodeSet(ret);
3411
0
    return(NULL);
3412
0
}
3413
3414
/**
3415
 * Implements the EXSLT - Sets distinct() function:
3416
 *    node-set set:distinct (node-set)
3417
 * `nodes` is sorted by document order, then exslSetsDistinctSorted
3418
 * is called with the sorted node-set
3419
 *
3420
 * @param nodes  a node-set
3421
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3422
 *         it is empty
3423
 */
3424
xmlNodeSet *
3425
0
xmlXPathDistinct (xmlNodeSet *nodes) {
3426
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3427
0
  return(nodes);
3428
3429
0
    xmlXPathNodeSetSort(nodes);
3430
0
    return(xmlXPathDistinctSorted(nodes));
3431
0
}
3432
3433
/**
3434
 * Implements the EXSLT - Sets has-same-nodes function:
3435
 *    boolean set:has-same-node(node-set, node-set)
3436
 *
3437
 * @param nodes1  a node-set
3438
 * @param nodes2  a node-set
3439
 * @returns true (1) if `nodes1` shares any node with `nodes2`, false (0)
3440
 *         otherwise
3441
 */
3442
int
3443
0
xmlXPathHasSameNodes (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3444
0
    int i, l;
3445
0
    xmlNodePtr cur;
3446
3447
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3448
0
  xmlXPathNodeSetIsEmpty(nodes2))
3449
0
  return(0);
3450
3451
0
    l = xmlXPathNodeSetGetLength(nodes1);
3452
0
    for (i = 0; i < l; i++) {
3453
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3454
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3455
0
      return(1);
3456
0
    }
3457
0
    return(0);
3458
0
}
3459
3460
/**
3461
 * Implements the EXSLT - Sets leading() function:
3462
 *    node-set set:leading (node-set, node-set)
3463
 *
3464
 * @param nodes  a node-set, sorted by document order
3465
 * @param node  a node
3466
 * @returns the nodes in `nodes` that precede `node` in document order,
3467
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3468
 *         doesn't contain `node`
3469
 */
3470
xmlNodeSet *
3471
0
xmlXPathNodeLeadingSorted (xmlNodeSet *nodes, xmlNode *node) {
3472
0
    int i, l;
3473
0
    xmlNodePtr cur;
3474
0
    xmlNodeSetPtr ret;
3475
3476
0
    if (node == NULL)
3477
0
  return(nodes);
3478
3479
0
    ret = xmlXPathNodeSetCreate(NULL);
3480
0
    if (ret == NULL)
3481
0
        return(ret);
3482
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3483
0
  (!xmlXPathNodeSetContains(nodes, node)))
3484
0
  return(ret);
3485
3486
0
    l = xmlXPathNodeSetGetLength(nodes);
3487
0
    for (i = 0; i < l; i++) {
3488
0
  cur = xmlXPathNodeSetItem(nodes, i);
3489
0
  if (cur == node)
3490
0
      break;
3491
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3492
0
            xmlXPathFreeNodeSet(ret);
3493
0
      return(NULL);
3494
0
        }
3495
0
    }
3496
0
    return(ret);
3497
0
}
3498
3499
/**
3500
 * Implements the EXSLT - Sets leading() function:
3501
 *    node-set set:leading (node-set, node-set)
3502
 * `nodes` is sorted by document order, then exslSetsNodeLeadingSorted
3503
 * is called.
3504
 *
3505
 * @param nodes  a node-set
3506
 * @param node  a node
3507
 * @returns the nodes in `nodes` that precede `node` in document order,
3508
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3509
 *         doesn't contain `node`
3510
 */
3511
xmlNodeSet *
3512
0
xmlXPathNodeLeading (xmlNodeSet *nodes, xmlNode *node) {
3513
0
    xmlXPathNodeSetSort(nodes);
3514
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
3515
0
}
3516
3517
/**
3518
 * Implements the EXSLT - Sets leading() function:
3519
 *    node-set set:leading (node-set, node-set)
3520
 *
3521
 * @param nodes1  a node-set, sorted by document order
3522
 * @param nodes2  a node-set, sorted by document order
3523
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3524
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3525
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3526
 */
3527
xmlNodeSet *
3528
0
xmlXPathLeadingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3529
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3530
0
  return(nodes1);
3531
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3532
0
             xmlXPathNodeSetItem(nodes2, 1)));
3533
0
}
3534
3535
/**
3536
 * Implements the EXSLT - Sets leading() function:
3537
 *    node-set set:leading (node-set, node-set)
3538
 * `nodes1` and `nodes2` are sorted by document order, then
3539
 * exslSetsLeadingSorted is called.
3540
 *
3541
 * @param nodes1  a node-set
3542
 * @param nodes2  a node-set
3543
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3544
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3545
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3546
 */
3547
xmlNodeSet *
3548
0
xmlXPathLeading (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3549
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3550
0
  return(nodes1);
3551
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3552
0
  return(xmlXPathNodeSetCreate(NULL));
3553
0
    xmlXPathNodeSetSort(nodes1);
3554
0
    xmlXPathNodeSetSort(nodes2);
3555
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3556
0
             xmlXPathNodeSetItem(nodes2, 1)));
3557
0
}
3558
3559
/**
3560
 * Implements the EXSLT - Sets trailing() function:
3561
 *    node-set set:trailing (node-set, node-set)
3562
 *
3563
 * @param nodes  a node-set, sorted by document order
3564
 * @param node  a node
3565
 * @returns the nodes in `nodes` that follow `node` in document order,
3566
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3567
 *         doesn't contain `node`
3568
 */
3569
xmlNodeSet *
3570
0
xmlXPathNodeTrailingSorted (xmlNodeSet *nodes, xmlNode *node) {
3571
0
    int i, l;
3572
0
    xmlNodePtr cur;
3573
0
    xmlNodeSetPtr ret;
3574
3575
0
    if (node == NULL)
3576
0
  return(nodes);
3577
3578
0
    ret = xmlXPathNodeSetCreate(NULL);
3579
0
    if (ret == NULL)
3580
0
        return(ret);
3581
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3582
0
  (!xmlXPathNodeSetContains(nodes, node)))
3583
0
  return(ret);
3584
3585
0
    l = xmlXPathNodeSetGetLength(nodes);
3586
0
    for (i = l - 1; i >= 0; i--) {
3587
0
  cur = xmlXPathNodeSetItem(nodes, i);
3588
0
  if (cur == node)
3589
0
      break;
3590
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3591
0
            xmlXPathFreeNodeSet(ret);
3592
0
      return(NULL);
3593
0
        }
3594
0
    }
3595
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3596
0
    return(ret);
3597
0
}
3598
3599
/**
3600
 * Implements the EXSLT - Sets trailing() function:
3601
 *    node-set set:trailing (node-set, node-set)
3602
 * `nodes` is sorted by document order, then #xmlXPathNodeTrailingSorted
3603
 * is called.
3604
 *
3605
 * @param nodes  a node-set
3606
 * @param node  a node
3607
 * @returns the nodes in `nodes` that follow `node` in document order,
3608
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3609
 *         doesn't contain `node`
3610
 */
3611
xmlNodeSet *
3612
0
xmlXPathNodeTrailing (xmlNodeSet *nodes, xmlNode *node) {
3613
0
    xmlXPathNodeSetSort(nodes);
3614
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
3615
0
}
3616
3617
/**
3618
 * Implements the EXSLT - Sets trailing() function:
3619
 *    node-set set:trailing (node-set, node-set)
3620
 *
3621
 * @param nodes1  a node-set, sorted by document order
3622
 * @param nodes2  a node-set, sorted by document order
3623
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3624
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3625
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3626
 */
3627
xmlNodeSet *
3628
0
xmlXPathTrailingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3629
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3630
0
  return(nodes1);
3631
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3632
0
              xmlXPathNodeSetItem(nodes2, 0)));
3633
0
}
3634
3635
/**
3636
 * Implements the EXSLT - Sets trailing() function:
3637
 *    node-set set:trailing (node-set, node-set)
3638
 * `nodes1` and `nodes2` are sorted by document order, then
3639
 * #xmlXPathTrailingSorted is called.
3640
 *
3641
 * @param nodes1  a node-set
3642
 * @param nodes2  a node-set
3643
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3644
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3645
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3646
 */
3647
xmlNodeSet *
3648
0
xmlXPathTrailing (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3649
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3650
0
  return(nodes1);
3651
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3652
0
  return(xmlXPathNodeSetCreate(NULL));
3653
0
    xmlXPathNodeSetSort(nodes1);
3654
0
    xmlXPathNodeSetSort(nodes2);
3655
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3656
0
              xmlXPathNodeSetItem(nodes2, 0)));
3657
0
}
3658
3659
/************************************************************************
3660
 *                  *
3661
 *    Routines to handle extra functions      *
3662
 *                  *
3663
 ************************************************************************/
3664
3665
/**
3666
 * Register a new function. If `f` is NULL it unregisters the function
3667
 *
3668
 * @param ctxt  the XPath context
3669
 * @param name  the function name
3670
 * @param f  the function implementation or NULL
3671
 * @returns 0 in case of success, -1 in case of error
3672
 */
3673
int
3674
xmlXPathRegisterFunc(xmlXPathContext *ctxt, const xmlChar *name,
3675
0
         xmlXPathFunction f) {
3676
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3677
0
}
3678
3679
/**
3680
 * Register a new function. If `f` is NULL it unregisters the function
3681
 *
3682
 * @param ctxt  the XPath context
3683
 * @param name  the function name
3684
 * @param ns_uri  the function namespace URI
3685
 * @param f  the function implementation or NULL
3686
 * @returns 0 in case of success, -1 in case of error
3687
 */
3688
int
3689
xmlXPathRegisterFuncNS(xmlXPathContext *ctxt, const xmlChar *name,
3690
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
3691
0
    int ret;
3692
0
    void *payload;
3693
3694
0
    if (ctxt == NULL)
3695
0
  return(-1);
3696
0
    if (name == NULL)
3697
0
  return(-1);
3698
3699
0
    if (ctxt->funcHash == NULL)
3700
0
  ctxt->funcHash = xmlHashCreate(0);
3701
0
    if (ctxt->funcHash == NULL) {
3702
0
        xmlXPathErrMemory(ctxt);
3703
0
  return(-1);
3704
0
    }
3705
0
    if (f == NULL)
3706
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3707
0
    memcpy(&payload, &f, sizeof(f));
3708
0
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3709
0
    if (ret < 0) {
3710
0
        xmlXPathErrMemory(ctxt);
3711
0
        return(-1);
3712
0
    }
3713
3714
0
    return(0);
3715
0
}
3716
3717
/**
3718
 * Registers an external mechanism to do function lookup.
3719
 *
3720
 * @param ctxt  the XPath context
3721
 * @param f  the lookup function
3722
 * @param funcCtxt  the lookup data
3723
 */
3724
void
3725
xmlXPathRegisterFuncLookup (xmlXPathContext *ctxt,
3726
          xmlXPathFuncLookupFunc f,
3727
0
          void *funcCtxt) {
3728
0
    if (ctxt == NULL)
3729
0
  return;
3730
0
    ctxt->funcLookupFunc = f;
3731
0
    ctxt->funcLookupData = funcCtxt;
3732
0
}
3733
3734
/**
3735
 * Search in the Function array of the context for the given
3736
 * function.
3737
 *
3738
 * @param ctxt  the XPath context
3739
 * @param name  the function name
3740
 * @returns the xmlXPathFunction or NULL if not found
3741
 */
3742
xmlXPathFunction
3743
17.6k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
17.6k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
17.6k
}
3746
3747
/**
3748
 * Search in the Function array of the context for the given
3749
 * function.
3750
 *
3751
 * @param ctxt  the XPath context
3752
 * @param name  the function name
3753
 * @param ns_uri  the function namespace URI
3754
 * @returns the xmlXPathFunction or NULL if not found
3755
 */
3756
xmlXPathFunction
3757
xmlXPathFunctionLookupNS(xmlXPathContext *ctxt, const xmlChar *name,
3758
17.7k
       const xmlChar *ns_uri) {
3759
17.7k
    xmlXPathFunction ret;
3760
17.7k
    void *payload;
3761
3762
17.7k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
17.7k
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
17.7k
    if (ns_uri == NULL) {
3768
17.6k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
26.6k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
24.6k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
24.6k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
24.6k
                       (char *) name) == 0)
3775
15.5k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
9.01k
            bucketIndex += 1;
3778
9.01k
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
9.01k
        }
3781
17.6k
    }
3782
3783
2.14k
    if (ctxt->funcLookupFunc != NULL) {
3784
0
  xmlXPathFuncLookupFunc f;
3785
3786
0
  f = ctxt->funcLookupFunc;
3787
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
3788
0
  if (ret != NULL)
3789
0
      return(ret);
3790
0
    }
3791
3792
2.14k
    if (ctxt->funcHash == NULL)
3793
2.14k
  return(NULL);
3794
3795
0
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3796
0
    memcpy(&ret, &payload, sizeof(payload));
3797
3798
0
    return(ret);
3799
2.14k
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
46.5k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
46.5k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
46.5k
    xmlHashFree(ctxt->funcHash, NULL);
3812
46.5k
    ctxt->funcHash = NULL;
3813
46.5k
}
3814
3815
/************************************************************************
3816
 *                  *
3817
 *      Routines to handle Variables      *
3818
 *                  *
3819
 ************************************************************************/
3820
3821
/**
3822
 * Register a new variable value. If `value` is NULL it unregisters
3823
 * the variable
3824
 *
3825
 * @param ctxt  the XPath context
3826
 * @param name  the variable name
3827
 * @param value  the variable value or NULL
3828
 * @returns 0 in case of success, -1 in case of error
3829
 */
3830
int
3831
xmlXPathRegisterVariable(xmlXPathContext *ctxt, const xmlChar *name,
3832
0
       xmlXPathObject *value) {
3833
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3834
0
}
3835
3836
/**
3837
 * Register a new variable value. If `value` is NULL it unregisters
3838
 * the variable
3839
 *
3840
 * @param ctxt  the XPath context
3841
 * @param name  the variable name
3842
 * @param ns_uri  the variable namespace URI
3843
 * @param value  the variable value or NULL
3844
 * @returns 0 in case of success, -1 in case of error
3845
 */
3846
int
3847
xmlXPathRegisterVariableNS(xmlXPathContext *ctxt, const xmlChar *name,
3848
         const xmlChar *ns_uri,
3849
0
         xmlXPathObject *value) {
3850
0
    if (ctxt == NULL)
3851
0
  return(-1);
3852
0
    if (name == NULL)
3853
0
  return(-1);
3854
3855
0
    if (ctxt->varHash == NULL)
3856
0
  ctxt->varHash = xmlHashCreate(0);
3857
0
    if (ctxt->varHash == NULL)
3858
0
  return(-1);
3859
0
    if (value == NULL)
3860
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3861
0
                             xmlXPathFreeObjectEntry));
3862
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3863
0
             (void *) value, xmlXPathFreeObjectEntry));
3864
0
}
3865
3866
/**
3867
 * register an external mechanism to do variable lookup
3868
 *
3869
 * @param ctxt  the XPath context
3870
 * @param f  the lookup function
3871
 * @param data  the lookup data
3872
 */
3873
void
3874
xmlXPathRegisterVariableLookup(xmlXPathContext *ctxt,
3875
0
   xmlXPathVariableLookupFunc f, void *data) {
3876
0
    if (ctxt == NULL)
3877
0
  return;
3878
0
    ctxt->varLookupFunc = f;
3879
0
    ctxt->varLookupData = data;
3880
0
}
3881
3882
/**
3883
 * Search in the Variable array of the context for the given
3884
 * variable value.
3885
 *
3886
 * @param ctxt  the XPath context
3887
 * @param name  the variable name
3888
 * @returns a copy of the value or NULL if not found
3889
 */
3890
xmlXPathObject *
3891
355
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
355
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
355
    if (ctxt->varLookupFunc != NULL) {
3896
0
  xmlXPathObjectPtr ret;
3897
3898
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3899
0
          (ctxt->varLookupData, name, NULL);
3900
0
  return(ret);
3901
0
    }
3902
355
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
355
}
3904
3905
/**
3906
 * Search in the Variable array of the context for the given
3907
 * variable value.
3908
 *
3909
 * @param ctxt  the XPath context
3910
 * @param name  the variable name
3911
 * @param ns_uri  the variable namespace URI
3912
 * @returns the a copy of the value or NULL if not found
3913
 */
3914
xmlXPathObject *
3915
xmlXPathVariableLookupNS(xmlXPathContext *ctxt, const xmlChar *name,
3916
405
       const xmlChar *ns_uri) {
3917
405
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
405
    if (ctxt->varLookupFunc != NULL) {
3921
0
  xmlXPathObjectPtr ret;
3922
3923
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3924
0
          (ctxt->varLookupData, name, ns_uri);
3925
0
  if (ret != NULL) return(ret);
3926
0
    }
3927
3928
405
    if (ctxt->varHash == NULL)
3929
405
  return(NULL);
3930
0
    if (name == NULL)
3931
0
  return(NULL);
3932
3933
0
    return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
3934
0
}
3935
3936
/**
3937
 * Cleanup the XPath context data associated to registered variables
3938
 *
3939
 * @param ctxt  the XPath context
3940
 */
3941
void
3942
46.5k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
46.5k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
46.5k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
46.5k
    ctxt->varHash = NULL;
3948
46.5k
}
3949
3950
/**
3951
 * Register a new namespace. If `ns_uri` is NULL it unregisters
3952
 * the namespace
3953
 *
3954
 * @param ctxt  the XPath context
3955
 * @param prefix  the namespace prefix cannot be NULL or empty string
3956
 * @param ns_uri  the namespace name
3957
 * @returns 0 in case of success, -1 in case of error
3958
 */
3959
int
3960
xmlXPathRegisterNs(xmlXPathContext *ctxt, const xmlChar *prefix,
3961
1.66k
         const xmlChar *ns_uri) {
3962
1.66k
    xmlChar *copy;
3963
3964
1.66k
    if (ctxt == NULL)
3965
0
  return(-1);
3966
1.66k
    if (prefix == NULL)
3967
0
  return(-1);
3968
1.66k
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
1.66k
    if (ctxt->nsHash == NULL)
3972
153
  ctxt->nsHash = xmlHashCreate(10);
3973
1.66k
    if (ctxt->nsHash == NULL) {
3974
8
        xmlXPathErrMemory(ctxt);
3975
8
  return(-1);
3976
8
    }
3977
1.66k
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
1.66k
    copy = xmlStrdup(ns_uri);
3982
1.66k
    if (copy == NULL) {
3983
7
        xmlXPathErrMemory(ctxt);
3984
7
        return(-1);
3985
7
    }
3986
1.65k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
1.65k
                           xmlHashDefaultDeallocator) < 0) {
3988
3
        xmlXPathErrMemory(ctxt);
3989
3
        xmlFree(copy);
3990
3
        return(-1);
3991
3
    }
3992
3993
1.65k
    return(0);
3994
1.65k
}
3995
3996
/**
3997
 * Search in the namespace declaration array of the context for the given
3998
 * namespace name associated to the given prefix
3999
 *
4000
 * @param ctxt  the XPath context
4001
 * @param prefix  the namespace prefix value
4002
 * @returns the value or NULL if not found
4003
 */
4004
const xmlChar *
4005
47.1k
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
47.1k
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
47.1k
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
47.1k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
46.3k
  return(XML_XML_NAMESPACE);
4013
4014
814
    if (ctxt->namespaces != NULL) {
4015
0
  int i;
4016
4017
0
  for (i = 0;i < ctxt->nsNr;i++) {
4018
0
      if ((ctxt->namespaces[i] != NULL) &&
4019
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4020
0
    return(ctxt->namespaces[i]->href);
4021
0
  }
4022
0
    }
4023
4024
814
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
814
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
46.5k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
46.5k
    if (ctxt == NULL)
4035
0
  return;
4036
4037
46.5k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
46.5k
    ctxt->nsHash = NULL;
4039
46.5k
}
4040
4041
/************************************************************************
4042
 *                  *
4043
 *      Routines to handle Values     *
4044
 *                  *
4045
 ************************************************************************/
4046
4047
/* Allocations are terrible, one needs to optimize all this !!! */
4048
4049
/**
4050
 * Create a new xmlXPathObject of type double and of value `val`
4051
 *
4052
 * @param val  the double value
4053
 * @returns the newly created object.
4054
 */
4055
xmlXPathObject *
4056
2.44M
xmlXPathNewFloat(double val) {
4057
2.44M
    xmlXPathObjectPtr ret;
4058
4059
2.44M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
2.44M
    if (ret == NULL)
4061
214
  return(NULL);
4062
2.44M
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
2.44M
    ret->type = XPATH_NUMBER;
4064
2.44M
    ret->floatval = val;
4065
2.44M
    return(ret);
4066
2.44M
}
4067
4068
/**
4069
 * Create a new xmlXPathObject of type boolean and of value `val`
4070
 *
4071
 * @param val  the boolean value
4072
 * @returns the newly created object.
4073
 */
4074
xmlXPathObject *
4075
1.16M
xmlXPathNewBoolean(int val) {
4076
1.16M
    xmlXPathObjectPtr ret;
4077
4078
1.16M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
1.16M
    if (ret == NULL)
4080
124
  return(NULL);
4081
1.16M
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
1.16M
    ret->type = XPATH_BOOLEAN;
4083
1.16M
    ret->boolval = (val != 0);
4084
1.16M
    return(ret);
4085
1.16M
}
4086
4087
/**
4088
 * Create a new xmlXPathObject of type string and of value `val`
4089
 *
4090
 * @param val  the xmlChar * value
4091
 * @returns the newly created object.
4092
 */
4093
xmlXPathObject *
4094
1.34M
xmlXPathNewString(const xmlChar *val) {
4095
1.34M
    xmlXPathObjectPtr ret;
4096
4097
1.34M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
1.34M
    if (ret == NULL)
4099
51
  return(NULL);
4100
1.34M
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
1.34M
    ret->type = XPATH_STRING;
4102
1.34M
    if (val == NULL)
4103
1.35k
        val = BAD_CAST "";
4104
1.34M
    ret->stringval = xmlStrdup(val);
4105
1.34M
    if (ret->stringval == NULL) {
4106
43
        xmlFree(ret);
4107
43
        return(NULL);
4108
43
    }
4109
1.34M
    return(ret);
4110
1.34M
}
4111
4112
/**
4113
 * Wraps the `val` string into an XPath object.
4114
 *
4115
 * Frees `val` in case of error.
4116
 *
4117
 * @param val  the xmlChar * value
4118
 * @returns the newly created object.
4119
 */
4120
xmlXPathObject *
4121
139k
xmlXPathWrapString (xmlChar *val) {
4122
139k
    xmlXPathObjectPtr ret;
4123
4124
139k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
139k
    if (ret == NULL) {
4126
54
        xmlFree(val);
4127
54
  return(NULL);
4128
54
    }
4129
139k
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
139k
    ret->type = XPATH_STRING;
4131
139k
    ret->stringval = val;
4132
139k
    return(ret);
4133
139k
}
4134
4135
/**
4136
 * Create a new xmlXPathObject of type string and of value `val`
4137
 *
4138
 * @param val  the char * value
4139
 * @returns the newly created object.
4140
 */
4141
xmlXPathObject *
4142
0
xmlXPathNewCString(const char *val) {
4143
0
    return(xmlXPathNewString(BAD_CAST val));
4144
0
}
4145
4146
/**
4147
 * Wraps a string into an XPath object.
4148
 *
4149
 * @param val  the char * value
4150
 * @returns the newly created object.
4151
 */
4152
xmlXPathObject *
4153
0
xmlXPathWrapCString (char * val) {
4154
0
    return(xmlXPathWrapString((xmlChar *)(val)));
4155
0
}
4156
4157
/**
4158
 * Wraps the `val` data into an XPath object.
4159
 *
4160
 * @param val  the user data
4161
 * @returns the newly created object.
4162
 */
4163
xmlXPathObject *
4164
0
xmlXPathWrapExternal (void *val) {
4165
0
    xmlXPathObjectPtr ret;
4166
4167
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4168
0
    if (ret == NULL)
4169
0
  return(NULL);
4170
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4171
0
    ret->type = XPATH_USERS;
4172
0
    ret->user = val;
4173
0
    return(ret);
4174
0
}
4175
4176
/**
4177
 * allocate a new copy of a given object
4178
 *
4179
 * @param val  the original object
4180
 * @returns the newly created object.
4181
 */
4182
xmlXPathObject *
4183
1.24M
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
1.24M
    xmlXPathObjectPtr ret;
4185
4186
1.24M
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
1.24M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
1.24M
    if (ret == NULL)
4191
114
  return(NULL);
4192
1.24M
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
1.24M
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
895k
  case XPATH_NUMBER:
4196
895k
      break;
4197
349k
  case XPATH_STRING:
4198
349k
      ret->stringval = xmlStrdup(val->stringval);
4199
349k
            if (ret->stringval == NULL) {
4200
12
                xmlFree(ret);
4201
12
                return(NULL);
4202
12
            }
4203
349k
      break;
4204
349k
  case XPATH_XSLT_TREE:
4205
0
  case XPATH_NODESET:
4206
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4207
0
            if (ret->nodesetval == NULL) {
4208
0
                xmlFree(ret);
4209
0
                return(NULL);
4210
0
            }
4211
      /* Do not deallocate the copied tree value */
4212
0
      ret->boolval = 0;
4213
0
      break;
4214
0
        case XPATH_USERS:
4215
0
      ret->user = val->user;
4216
0
      break;
4217
0
        default:
4218
0
            xmlFree(ret);
4219
0
            ret = NULL;
4220
0
      break;
4221
1.24M
    }
4222
1.24M
    return(ret);
4223
1.24M
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
12.0M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
12.0M
    if (obj == NULL) return;
4233
12.0M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
5.73M
        if (obj->nodesetval != NULL)
4235
5.73M
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
6.29M
    } else if (obj->type == XPATH_STRING) {
4237
1.82M
  if (obj->stringval != NULL)
4238
1.82M
      xmlFree(obj->stringval);
4239
1.82M
    }
4240
12.0M
    xmlFree(obj);
4241
12.0M
}
4242
4243
static void
4244
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4245
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4246
0
}
4247
4248
/**
4249
 * Depending on the state of the cache this frees the given
4250
 * XPath object or stores it in the cache.
4251
 *
4252
 * @param ctxt  XPath context
4253
 * @param obj  the xmlXPathObject to free or to cache
4254
 */
4255
static void
4256
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4257
12.9M
{
4258
12.9M
    if (obj == NULL)
4259
39
  return;
4260
12.9M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
11.5M
   xmlXPathFreeObject(obj);
4262
11.5M
    } else {
4263
1.42M
  xmlXPathContextCachePtr cache =
4264
1.42M
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
1.42M
  switch (obj->type) {
4267
836k
      case XPATH_NODESET:
4268
836k
      case XPATH_XSLT_TREE:
4269
836k
    if (obj->nodesetval != NULL) {
4270
836k
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
836k
      (cache->numNodeset < cache->maxNodeset)) {
4272
485k
                        obj->stringval = (void *) cache->nodesetObjs;
4273
485k
                        cache->nodesetObjs = obj;
4274
485k
                        cache->numNodeset += 1;
4275
485k
      goto obj_cached;
4276
485k
        } else {
4277
351k
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
351k
      obj->nodesetval = NULL;
4279
351k
        }
4280
836k
    }
4281
351k
    break;
4282
351k
      case XPATH_STRING:
4283
80.4k
    if (obj->stringval != NULL)
4284
80.4k
        xmlFree(obj->stringval);
4285
80.4k
                obj->stringval = NULL;
4286
80.4k
    break;
4287
84.1k
      case XPATH_BOOLEAN:
4288
511k
      case XPATH_NUMBER:
4289
511k
    break;
4290
0
      default:
4291
0
    goto free_obj;
4292
1.42M
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
943k
        if (cache->numMisc >= cache->maxMisc)
4298
8.25k
      goto free_obj;
4299
934k
        obj->stringval = (void *) cache->miscObjs;
4300
934k
        cache->miscObjs = obj;
4301
934k
        cache->numMisc += 1;
4302
4303
1.42M
obj_cached:
4304
1.42M
        obj->boolval = 0;
4305
1.42M
  if (obj->nodesetval != NULL) {
4306
485k
      xmlNodeSetPtr tmpset = obj->nodesetval;
4307
4308
      /*
4309
      * Due to those nasty ns-nodes, we need to traverse
4310
      * the list and free the ns-nodes.
4311
      */
4312
485k
      if (tmpset->nodeNr > 0) {
4313
461k
    int i;
4314
461k
    xmlNodePtr node;
4315
4316
1.00M
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
548k
        node = tmpset->nodeTab[i];
4318
548k
        if ((node != NULL) &&
4319
548k
      (node->type == XML_NAMESPACE_DECL))
4320
50.7k
        {
4321
50.7k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
50.7k
        }
4323
548k
    }
4324
461k
      }
4325
485k
      tmpset->nodeNr = 0;
4326
485k
        }
4327
4328
1.42M
  return;
4329
4330
8.25k
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
8.25k
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
8.25k
  xmlFree(obj);
4337
8.25k
    }
4338
12.9M
}
4339
4340
4341
/************************************************************************
4342
 *                  *
4343
 *      Type Casting Routines       *
4344
 *                  *
4345
 ************************************************************************/
4346
4347
/**
4348
 * Converts a boolean to its string value.
4349
 *
4350
 * @param val  a boolean
4351
 * @returns a newly allocated string.
4352
 */
4353
xmlChar *
4354
12.7k
xmlXPathCastBooleanToString (int val) {
4355
12.7k
    xmlChar *ret;
4356
12.7k
    if (val)
4357
2.86k
  ret = xmlStrdup((const xmlChar *) "true");
4358
9.91k
    else
4359
9.91k
  ret = xmlStrdup((const xmlChar *) "false");
4360
12.7k
    return(ret);
4361
12.7k
}
4362
4363
/**
4364
 * Converts a number to its string value.
4365
 *
4366
 * @param val  a number
4367
 * @returns a newly allocated string.
4368
 */
4369
xmlChar *
4370
81.6k
xmlXPathCastNumberToString (double val) {
4371
81.6k
    xmlChar *ret;
4372
81.6k
    switch (xmlXPathIsInf(val)) {
4373
1.10k
    case 1:
4374
1.10k
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
1.10k
  break;
4376
1.73k
    case -1:
4377
1.73k
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
1.73k
  break;
4379
78.8k
    default:
4380
78.8k
  if (xmlXPathIsNaN(val)) {
4381
56.9k
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
56.9k
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
3.27k
      ret = xmlStrdup((const xmlChar *) "0");
4385
18.5k
  } else {
4386
      /* could be improved */
4387
18.5k
      char buf[100];
4388
18.5k
      xmlXPathFormatNumber(val, buf, 99);
4389
18.5k
      buf[99] = 0;
4390
18.5k
      ret = xmlStrdup((const xmlChar *) buf);
4391
18.5k
  }
4392
81.6k
    }
4393
81.6k
    return(ret);
4394
81.6k
}
4395
4396
/**
4397
 * Converts a node to its string value.
4398
 *
4399
 * @param node  a node
4400
 * @returns a newly allocated string.
4401
 */
4402
xmlChar *
4403
8.13M
xmlXPathCastNodeToString (xmlNode *node) {
4404
8.13M
    return(xmlNodeGetContent(node));
4405
8.13M
}
4406
4407
/**
4408
 * Converts a node-set to its string value.
4409
 *
4410
 * @param ns  a node-set
4411
 * @returns a newly allocated string.
4412
 */
4413
xmlChar *
4414
1.20M
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
1.20M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
729k
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
476k
    if (ns->nodeNr > 1)
4419
70.1k
  xmlXPathNodeSetSort(ns);
4420
476k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
1.20M
}
4422
4423
/**
4424
 * Converts an existing object to its string() equivalent
4425
 *
4426
 * @param val  an XPath object
4427
 * @returns the allocated string value of the object, NULL in case of error.
4428
 *         It's up to the caller to free the string memory with #xmlFree.
4429
 */
4430
xmlChar *
4431
169k
xmlXPathCastToString(xmlXPathObject *val) {
4432
169k
    xmlChar *ret = NULL;
4433
4434
169k
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
169k
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
70.8k
        case XPATH_NODESET:
4441
70.8k
        case XPATH_XSLT_TREE:
4442
70.8k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
70.8k
      break;
4444
4.43k
  case XPATH_STRING:
4445
4.43k
      return(xmlStrdup(val->stringval));
4446
12.7k
        case XPATH_BOOLEAN:
4447
12.7k
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
12.7k
      break;
4449
81.6k
  case XPATH_NUMBER: {
4450
81.6k
      ret = xmlXPathCastNumberToString(val->floatval);
4451
81.6k
      break;
4452
70.8k
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
169k
    }
4458
165k
    return(ret);
4459
169k
}
4460
4461
/**
4462
 * Converts an existing object to its string() equivalent
4463
 *
4464
 * @param val  an XPath object
4465
 * @returns the new object, the old one is freed (or the operation
4466
 *         is done directly on `val`)
4467
 */
4468
xmlXPathObject *
4469
0
xmlXPathConvertString(xmlXPathObject *val) {
4470
0
    xmlChar *res = NULL;
4471
4472
0
    if (val == NULL)
4473
0
  return(xmlXPathNewCString(""));
4474
4475
0
    switch (val->type) {
4476
0
    case XPATH_UNDEFINED:
4477
0
  break;
4478
0
    case XPATH_NODESET:
4479
0
    case XPATH_XSLT_TREE:
4480
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4481
0
  break;
4482
0
    case XPATH_STRING:
4483
0
  return(val);
4484
0
    case XPATH_BOOLEAN:
4485
0
  res = xmlXPathCastBooleanToString(val->boolval);
4486
0
  break;
4487
0
    case XPATH_NUMBER:
4488
0
  res = xmlXPathCastNumberToString(val->floatval);
4489
0
  break;
4490
0
    case XPATH_USERS:
4491
  /* TODO */
4492
0
  break;
4493
0
    }
4494
0
    xmlXPathFreeObject(val);
4495
0
    if (res == NULL)
4496
0
  return(xmlXPathNewCString(""));
4497
0
    return(xmlXPathWrapString(res));
4498
0
}
4499
4500
/**
4501
 * Converts a boolean to its number value
4502
 *
4503
 * @param val  a boolean
4504
 * @returns the number value
4505
 */
4506
double
4507
154k
xmlXPathCastBooleanToNumber(int val) {
4508
154k
    if (val)
4509
21.2k
  return(1.0);
4510
133k
    return(0.0);
4511
154k
}
4512
4513
/**
4514
 * Converts a string to its number value
4515
 *
4516
 * @param val  a string
4517
 * @returns the number value
4518
 */
4519
double
4520
7.28M
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
7.28M
    return(xmlXPathStringEvalNumber(val));
4522
7.28M
}
4523
4524
/**
4525
 * Converts a node to its number value
4526
 *
4527
 * @param ctxt  XPath parser context
4528
 * @param node  a node
4529
 * @returns the number value
4530
 */
4531
static double
4532
4.53M
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
4.53M
    xmlChar *strval;
4534
4.53M
    double ret;
4535
4536
4.53M
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
4.53M
    strval = xmlXPathCastNodeToString(node);
4539
4.53M
    if (strval == NULL) {
4540
58
        xmlXPathPErrMemory(ctxt);
4541
58
  return(xmlXPathNAN);
4542
58
    }
4543
4.53M
    ret = xmlXPathCastStringToNumber(strval);
4544
4.53M
    xmlFree(strval);
4545
4546
4.53M
    return(ret);
4547
4.53M
}
4548
4549
/**
4550
 * Converts a node to its number value
4551
 *
4552
 * @param node  a node
4553
 * @returns the number value
4554
 */
4555
double
4556
0
xmlXPathCastNodeToNumber (xmlNode *node) {
4557
0
    return(xmlXPathNodeToNumberInternal(NULL, node));
4558
0
}
4559
4560
/**
4561
 * Converts a node-set to its number value
4562
 *
4563
 * @param ns  a node-set
4564
 * @returns the number value
4565
 */
4566
double
4567
0
xmlXPathCastNodeSetToNumber (xmlNodeSet *ns) {
4568
0
    xmlChar *str;
4569
0
    double ret;
4570
4571
0
    if (ns == NULL)
4572
0
  return(xmlXPathNAN);
4573
0
    str = xmlXPathCastNodeSetToString(ns);
4574
0
    ret = xmlXPathCastStringToNumber(str);
4575
0
    xmlFree(str);
4576
0
    return(ret);
4577
0
}
4578
4579
/**
4580
 * Converts an XPath object to its number value
4581
 *
4582
 * @param val  an XPath object
4583
 * @returns the number value
4584
 */
4585
double
4586
0
xmlXPathCastToNumber(xmlXPathObject *val) {
4587
0
    return(xmlXPathCastToNumberInternal(NULL, val));
4588
0
}
4589
4590
/**
4591
 * Converts an existing object to its number() equivalent
4592
 *
4593
 * @param val  an XPath object
4594
 * @returns the new object, the old one is freed (or the operation
4595
 *         is done directly on `val`)
4596
 */
4597
xmlXPathObject *
4598
0
xmlXPathConvertNumber(xmlXPathObject *val) {
4599
0
    xmlXPathObjectPtr ret;
4600
4601
0
    if (val == NULL)
4602
0
  return(xmlXPathNewFloat(0.0));
4603
0
    if (val->type == XPATH_NUMBER)
4604
0
  return(val);
4605
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4606
0
    xmlXPathFreeObject(val);
4607
0
    return(ret);
4608
0
}
4609
4610
/**
4611
 * Converts a number to its boolean value
4612
 *
4613
 * @param val  a number
4614
 * @returns the boolean value
4615
 */
4616
int
4617
210k
xmlXPathCastNumberToBoolean (double val) {
4618
210k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
179k
   return(0);
4620
30.4k
     return(1);
4621
210k
}
4622
4623
/**
4624
 * Converts a string to its boolean value
4625
 *
4626
 * @param val  a string
4627
 * @returns the boolean value
4628
 */
4629
int
4630
1.86k
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
1.86k
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
930
  return(0);
4633
937
    return(1);
4634
1.86k
}
4635
4636
/**
4637
 * Converts a node-set to its boolean value
4638
 *
4639
 * @param ns  a node-set
4640
 * @returns the boolean value
4641
 */
4642
int
4643
132k
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
132k
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
123k
  return(0);
4646
9.27k
    return(1);
4647
132k
}
4648
4649
/**
4650
 * Converts an XPath object to its boolean value
4651
 *
4652
 * @param val  an XPath object
4653
 * @returns the boolean value
4654
 */
4655
int
4656
144k
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
144k
    int ret = 0;
4658
4659
144k
    if (val == NULL)
4660
0
  return(0);
4661
144k
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
132k
    case XPATH_NODESET:
4666
132k
    case XPATH_XSLT_TREE:
4667
132k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
132k
  break;
4669
1.86k
    case XPATH_STRING:
4670
1.86k
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
1.86k
  break;
4672
9.50k
    case XPATH_NUMBER:
4673
9.50k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
9.50k
  break;
4675
0
    case XPATH_BOOLEAN:
4676
0
  ret = val->boolval;
4677
0
  break;
4678
0
    case XPATH_USERS:
4679
  /* TODO */
4680
0
  ret = 0;
4681
0
  break;
4682
144k
    }
4683
144k
    return(ret);
4684
144k
}
4685
4686
4687
/**
4688
 * Converts an existing object to its boolean() equivalent
4689
 *
4690
 * @param val  an XPath object
4691
 * @returns the new object, the old one is freed (or the operation
4692
 *         is done directly on `val`)
4693
 */
4694
xmlXPathObject *
4695
0
xmlXPathConvertBoolean(xmlXPathObject *val) {
4696
0
    xmlXPathObjectPtr ret;
4697
4698
0
    if (val == NULL)
4699
0
  return(xmlXPathNewBoolean(0));
4700
0
    if (val->type == XPATH_BOOLEAN)
4701
0
  return(val);
4702
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4703
0
    xmlXPathFreeObject(val);
4704
0
    return(ret);
4705
0
}
4706
4707
/************************************************************************
4708
 *                  *
4709
 *    Routines to handle XPath contexts     *
4710
 *                  *
4711
 ************************************************************************/
4712
4713
/**
4714
 * Create a new xmlXPathContext
4715
 *
4716
 * @param doc  the XML document
4717
 * @returns the xmlXPathContext just allocated. The caller will need to free it.
4718
 */
4719
xmlXPathContext *
4720
46.6k
xmlXPathNewContext(xmlDoc *doc) {
4721
46.6k
    xmlXPathContextPtr ret;
4722
4723
46.6k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
46.6k
    if (ret == NULL)
4725
110
  return(NULL);
4726
46.5k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
46.5k
    ret->doc = doc;
4728
46.5k
    ret->node = NULL;
4729
4730
46.5k
    ret->varHash = NULL;
4731
4732
46.5k
    ret->nb_types = 0;
4733
46.5k
    ret->max_types = 0;
4734
46.5k
    ret->types = NULL;
4735
4736
46.5k
    ret->nb_axis = 0;
4737
46.5k
    ret->max_axis = 0;
4738
46.5k
    ret->axis = NULL;
4739
4740
46.5k
    ret->nsHash = NULL;
4741
46.5k
    ret->user = NULL;
4742
4743
46.5k
    ret->contextSize = -1;
4744
46.5k
    ret->proximityPosition = -1;
4745
4746
#ifdef XP_DEFAULT_CACHE_ON
4747
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
4748
  xmlXPathFreeContext(ret);
4749
  return(NULL);
4750
    }
4751
#endif
4752
4753
46.5k
    return(ret);
4754
46.6k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
46.5k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
46.5k
    if (ctxt == NULL) return;
4764
4765
46.5k
    if (ctxt->cache != NULL)
4766
24.2k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
46.5k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
46.5k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
46.5k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
46.5k
    xmlResetError(&ctxt->lastError);
4771
46.5k
    xmlFree(ctxt);
4772
46.5k
}
4773
4774
/**
4775
 * Register a callback function that will be called on errors and
4776
 * warnings. If handler is NULL, the error handler will be deactivated.
4777
 *
4778
 * @since 2.13.0
4779
 * @param ctxt  the XPath context
4780
 * @param handler  error handler
4781
 * @param data  user data which will be passed to the handler
4782
 */
4783
void
4784
xmlXPathSetErrorHandler(xmlXPathContext *ctxt,
4785
5.51k
                        xmlStructuredErrorFunc handler, void *data) {
4786
5.51k
    if (ctxt == NULL)
4787
0
        return;
4788
4789
5.51k
    ctxt->error = handler;
4790
5.51k
    ctxt->userData = data;
4791
5.51k
}
4792
4793
/************************************************************************
4794
 *                  *
4795
 *    Routines to handle XPath parser contexts    *
4796
 *                  *
4797
 ************************************************************************/
4798
4799
/**
4800
 * Create a new xmlXPathParserContext
4801
 *
4802
 * @param str  the XPath expression
4803
 * @param ctxt  the XPath context
4804
 * @returns the xmlXPathParserContext just allocated.
4805
 */
4806
xmlXPathParserContext *
4807
59.3k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
59.3k
    xmlXPathParserContextPtr ret;
4809
4810
59.3k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
59.3k
    if (ret == NULL) {
4812
112
        xmlXPathErrMemory(ctxt);
4813
112
  return(NULL);
4814
112
    }
4815
59.2k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
59.2k
    ret->cur = ret->base = str;
4817
59.2k
    ret->context = ctxt;
4818
4819
59.2k
    ret->comp = xmlXPathNewCompExpr();
4820
59.2k
    if (ret->comp == NULL) {
4821
332
        xmlXPathErrMemory(ctxt);
4822
332
  xmlFree(ret->valueTab);
4823
332
  xmlFree(ret);
4824
332
  return(NULL);
4825
332
    }
4826
58.8k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
0
        ret->comp->dict = ctxt->dict;
4828
0
  xmlDictReference(ret->comp->dict);
4829
0
    }
4830
4831
58.8k
    return(ret);
4832
59.2k
}
4833
4834
/**
4835
 * Create a new xmlXPathParserContext when processing a compiled expression
4836
 *
4837
 * @param comp  the XPath compiled expression
4838
 * @param ctxt  the XPath context
4839
 * @returns the xmlXPathParserContext just allocated.
4840
 */
4841
static xmlXPathParserContextPtr
4842
6.51k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
6.51k
    xmlXPathParserContextPtr ret;
4844
4845
6.51k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
6.51k
    if (ret == NULL) {
4847
0
        xmlXPathErrMemory(ctxt);
4848
0
  return(NULL);
4849
0
    }
4850
6.51k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
6.51k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
6.51k
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
6.51k
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
6.51k
    if (ret->valueTab == NULL) {
4860
0
  xmlFree(ret);
4861
0
  xmlXPathErrMemory(ctxt);
4862
0
  return(NULL);
4863
0
    }
4864
6.51k
    ret->valueNr = 0;
4865
6.51k
    ret->value = NULL;
4866
4867
6.51k
    ret->context = ctxt;
4868
6.51k
    ret->comp = comp;
4869
4870
6.51k
    return(ret);
4871
6.51k
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
65.3k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
65.3k
    int i;
4881
4882
65.3k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
65.3k
    if (ctxt->valueTab != NULL) {
4886
150k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
94.2k
            if (ctxt->context)
4888
94.2k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
94.2k
        }
4892
56.6k
        xmlFree(ctxt->valueTab);
4893
56.6k
    }
4894
65.3k
    if (ctxt->comp != NULL) {
4895
#ifdef XPATH_STREAMING
4896
  if (ctxt->comp->stream != NULL) {
4897
      xmlFreePatternList(ctxt->comp->stream);
4898
      ctxt->comp->stream = NULL;
4899
  }
4900
#endif
4901
52.3k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
52.3k
    }
4903
65.3k
    xmlFree(ctxt);
4904
65.3k
}
4905
4906
/************************************************************************
4907
 *                  *
4908
 *    The implicit core function library      *
4909
 *                  *
4910
 ************************************************************************/
4911
4912
/**
4913
 * Function computing the beginning of the string value of the node,
4914
 * used to speed up comparisons
4915
 *
4916
 * @param node  a node pointer
4917
 * @returns an int usable as a hash
4918
 */
4919
static unsigned int
4920
215k
xmlXPathNodeValHash(xmlNodePtr node) {
4921
215k
    int len = 2;
4922
215k
    const xmlChar * string = NULL;
4923
215k
    xmlNodePtr tmp = NULL;
4924
215k
    unsigned int ret = 0;
4925
4926
215k
    if (node == NULL)
4927
0
  return(0);
4928
4929
215k
    if (node->type == XML_DOCUMENT_NODE) {
4930
28.4k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
28.4k
  if (tmp == NULL)
4932
155
      node = node->children;
4933
28.2k
  else
4934
28.2k
      node = tmp;
4935
4936
28.4k
  if (node == NULL)
4937
82
      return(0);
4938
28.4k
    }
4939
4940
215k
    switch (node->type) {
4941
922
  case XML_COMMENT_NODE:
4942
3.98k
  case XML_PI_NODE:
4943
4.72k
  case XML_CDATA_SECTION_NODE:
4944
24.9k
  case XML_TEXT_NODE:
4945
24.9k
      string = node->content;
4946
24.9k
      if (string == NULL)
4947
3.05k
    return(0);
4948
21.8k
      if (string[0] == 0)
4949
748
    return(0);
4950
21.1k
      return(string[0] + (string[1] << 8));
4951
8.34k
  case XML_NAMESPACE_DECL:
4952
8.34k
      string = ((xmlNsPtr)node)->href;
4953
8.34k
      if (string == NULL)
4954
0
    return(0);
4955
8.34k
      if (string[0] == 0)
4956
454
    return(0);
4957
7.89k
      return(string[0] + (string[1] << 8));
4958
1.05k
  case XML_ATTRIBUTE_NODE:
4959
1.05k
      tmp = ((xmlAttrPtr) node)->children;
4960
1.05k
      break;
4961
180k
  case XML_ELEMENT_NODE:
4962
180k
      tmp = node->children;
4963
180k
      break;
4964
66
  default:
4965
66
      return(0);
4966
215k
    }
4967
612k
    while (tmp != NULL) {
4968
515k
  switch (tmp->type) {
4969
1.42k
      case XML_CDATA_SECTION_NODE:
4970
118k
      case XML_TEXT_NODE:
4971
118k
    string = tmp->content;
4972
118k
    break;
4973
397k
      default:
4974
397k
                string = NULL;
4975
397k
    break;
4976
515k
  }
4977
515k
  if ((string != NULL) && (string[0] != 0)) {
4978
117k
      if (len == 1) {
4979
28.6k
    return(ret + (string[0] << 8));
4980
28.6k
      }
4981
88.7k
      if (string[1] == 0) {
4982
32.6k
    len = 1;
4983
32.6k
    ret = string[0];
4984
56.0k
      } else {
4985
56.0k
    return(string[0] + (string[1] << 8));
4986
56.0k
      }
4987
88.7k
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
430k
        if ((tmp->children != NULL) &&
4992
430k
            (tmp->type != XML_DTD_NODE) &&
4993
430k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
430k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
353k
            tmp = tmp->children;
4996
353k
            continue;
4997
353k
  }
4998
77.4k
  if (tmp == node)
4999
0
      break;
5000
5001
77.4k
  if (tmp->next != NULL) {
5002
68.3k
      tmp = tmp->next;
5003
68.3k
      continue;
5004
68.3k
  }
5005
5006
22.6k
  do {
5007
22.6k
      tmp = tmp->parent;
5008
22.6k
      if (tmp == NULL)
5009
0
    break;
5010
22.6k
      if (tmp == node) {
5011
8.17k
    tmp = NULL;
5012
8.17k
    break;
5013
8.17k
      }
5014
14.4k
      if (tmp->next != NULL) {
5015
959
    tmp = tmp->next;
5016
959
    break;
5017
959
      }
5018
14.4k
  } while (tmp != NULL);
5019
9.13k
    }
5020
97.1k
    return(ret);
5021
181k
}
5022
5023
/**
5024
 * Function computing the beginning of the string value of the node,
5025
 * used to speed up comparisons
5026
 *
5027
 * @param string  a string
5028
 * @returns an int usable as a hash
5029
 */
5030
static unsigned int
5031
10.1k
xmlXPathStringHash(const xmlChar * string) {
5032
10.1k
    if (string == NULL)
5033
0
  return(0);
5034
10.1k
    if (string[0] == 0)
5035
2.25k
  return(0);
5036
7.93k
    return(string[0] + (string[1] << 8));
5037
10.1k
}
5038
5039
/**
5040
 * Implement the compare operation between a nodeset and a number
5041
 *     `ns` < `val`    (1, 1, ...
5042
 *     `ns` <= `val`   (1, 0, ...
5043
 *     `ns` > `val`    (0, 1, ...
5044
 *     `ns` >= `val`   (0, 0, ...
5045
 *
5046
 * If one object to be compared is a node-set and the other is a number,
5047
 * then the comparison will be true if and only if there is a node in the
5048
 * node-set such that the result of performing the comparison on the number
5049
 * to be compared and on the result of converting the string-value of that
5050
 * node to a number using the number function is true.
5051
 *
5052
 * @param ctxt  the XPath Parser context
5053
 * @param inf  less than (1) or greater than (0)
5054
 * @param strict  is the comparison strict
5055
 * @param arg  the node set
5056
 * @param f  the value
5057
 * @returns 0 or 1 depending on the results of the test.
5058
 */
5059
static int
5060
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5061
65.6k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
65.6k
    int i, ret = 0;
5063
65.6k
    xmlNodeSetPtr ns;
5064
65.6k
    xmlChar *str2;
5065
5066
65.6k
    if ((f == NULL) || (arg == NULL) ||
5067
65.6k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5068
0
  xmlXPathReleaseObject(ctxt->context, arg);
5069
0
  xmlXPathReleaseObject(ctxt->context, f);
5070
0
        return(0);
5071
0
    }
5072
65.6k
    ns = arg->nodesetval;
5073
65.6k
    if (ns != NULL) {
5074
550k
  for (i = 0;i < ns->nodeNr;i++) {
5075
486k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
486k
       if (str2 != NULL) {
5077
486k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
486k
     xmlFree(str2);
5079
486k
     xmlXPathNumberFunction(ctxt, 1);
5080
486k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
486k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
486k
     if (ret)
5083
2.46k
         break;
5084
486k
       } else {
5085
20
                 xmlXPathPErrMemory(ctxt);
5086
20
             }
5087
486k
  }
5088
65.6k
    }
5089
65.6k
    xmlXPathReleaseObject(ctxt->context, arg);
5090
65.6k
    xmlXPathReleaseObject(ctxt->context, f);
5091
65.6k
    return(ret);
5092
65.6k
}
5093
5094
/**
5095
 * Implement the compare operation between a nodeset and a string
5096
 *     `ns` < `val`    (1, 1, ...
5097
 *     `ns` <= `val`   (1, 0, ...
5098
 *     `ns` > `val`    (0, 1, ...
5099
 *     `ns` >= `val`   (0, 0, ...
5100
 *
5101
 * If one object to be compared is a node-set and the other is a string,
5102
 * then the comparison will be true if and only if there is a node in
5103
 * the node-set such that the result of performing the comparison on the
5104
 * string-value of the node and the other string is true.
5105
 *
5106
 * @param ctxt  the XPath Parser context
5107
 * @param inf  less than (1) or greater than (0)
5108
 * @param strict  is the comparison strict
5109
 * @param arg  the node set
5110
 * @param s  the value
5111
 * @returns 0 or 1 depending on the results of the test.
5112
 */
5113
static int
5114
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5115
15.1k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
15.1k
    int i, ret = 0;
5117
15.1k
    xmlNodeSetPtr ns;
5118
15.1k
    xmlChar *str2;
5119
5120
15.1k
    if ((s == NULL) || (arg == NULL) ||
5121
15.1k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5122
0
  xmlXPathReleaseObject(ctxt->context, arg);
5123
0
  xmlXPathReleaseObject(ctxt->context, s);
5124
0
        return(0);
5125
0
    }
5126
15.1k
    ns = arg->nodesetval;
5127
15.1k
    if (ns != NULL) {
5128
320k
  for (i = 0;i < ns->nodeNr;i++) {
5129
305k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
305k
       if (str2 != NULL) {
5131
305k
     xmlXPathValuePush(ctxt,
5132
305k
         xmlXPathCacheNewString(ctxt, str2));
5133
305k
     xmlFree(str2);
5134
305k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
305k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
305k
     if (ret)
5137
400
         break;
5138
305k
       } else {
5139
6
                 xmlXPathPErrMemory(ctxt);
5140
6
             }
5141
305k
  }
5142
15.1k
    }
5143
15.1k
    xmlXPathReleaseObject(ctxt->context, arg);
5144
15.1k
    xmlXPathReleaseObject(ctxt->context, s);
5145
15.1k
    return(ret);
5146
15.1k
}
5147
5148
/**
5149
 * Implement the compare operation on nodesets:
5150
 *
5151
 * If both objects to be compared are node-sets, then the comparison
5152
 * will be true if and only if there is a node in the first node-set
5153
 * and a node in the second node-set such that the result of performing
5154
 * the comparison on the string-values of the two nodes is true.
5155
 * ....
5156
 * When neither object to be compared is a node-set and the operator
5157
 * is <=, <, >= or >, then the objects are compared by converting both
5158
 * objects to numbers and comparing the numbers according to IEEE 754.
5159
 * ....
5160
 * The number function converts its argument to a number as follows:
5161
 *  - a string that consists of optional whitespace followed by an
5162
 *    optional minus sign followed by a Number followed by whitespace
5163
 *    is converted to the IEEE 754 number that is nearest (according
5164
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5165
 *    represented by the string; any other string is converted to NaN
5166
 *
5167
 * Conclusion all nodes need to be converted first to their string value
5168
 * and then the comparison must be done when possible
5169
 *
5170
 * @param ctxt  XPath parser context
5171
 * @param inf  less than (1) or greater than (0)
5172
 * @param strict  is the comparison strict
5173
 * @param arg1  the first node set object
5174
 * @param arg2  the second node set object
5175
 */
5176
static int
5177
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5178
140k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
140k
    int i, j, init = 0;
5180
140k
    double val1;
5181
140k
    double *values2;
5182
140k
    int ret = 0;
5183
140k
    xmlNodeSetPtr ns1;
5184
140k
    xmlNodeSetPtr ns2;
5185
5186
140k
    if ((arg1 == NULL) ||
5187
140k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
140k
    if ((arg2 == NULL) ||
5192
140k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5193
0
  xmlXPathFreeObject(arg1);
5194
0
  xmlXPathFreeObject(arg2);
5195
0
        return(0);
5196
0
    }
5197
5198
140k
    ns1 = arg1->nodesetval;
5199
140k
    ns2 = arg2->nodesetval;
5200
5201
140k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
122k
  xmlXPathFreeObject(arg1);
5203
122k
  xmlXPathFreeObject(arg2);
5204
122k
  return(0);
5205
122k
    }
5206
17.9k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
8.64k
  xmlXPathFreeObject(arg1);
5208
8.64k
  xmlXPathFreeObject(arg2);
5209
8.64k
  return(0);
5210
8.64k
    }
5211
5212
9.29k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
9.29k
    if (values2 == NULL) {
5214
4
        xmlXPathPErrMemory(ctxt);
5215
4
  xmlXPathFreeObject(arg1);
5216
4
  xmlXPathFreeObject(arg2);
5217
4
  return(0);
5218
4
    }
5219
59.3k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
51.5k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
51.5k
  if (xmlXPathIsNaN(val1))
5222
44.8k
      continue;
5223
20.9k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
15.7k
      if (init == 0) {
5225
11.1k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
11.1k
                                                          ns2->nodeTab[j]);
5227
11.1k
      }
5228
15.7k
      if (xmlXPathIsNaN(values2[j]))
5229
10.0k
    continue;
5230
5.71k
      if (inf && strict)
5231
1.55k
    ret = (val1 < values2[j]);
5232
4.16k
      else if (inf && !strict)
5233
704
    ret = (val1 <= values2[j]);
5234
3.45k
      else if (!inf && strict)
5235
2.71k
    ret = (val1 > values2[j]);
5236
741
      else if (!inf && !strict)
5237
741
    ret = (val1 >= values2[j]);
5238
5.71k
      if (ret)
5239
1.49k
    break;
5240
5.71k
  }
5241
6.70k
  if (ret)
5242
1.49k
      break;
5243
5.21k
  init = 1;
5244
5.21k
    }
5245
9.29k
    xmlFree(values2);
5246
9.29k
    xmlXPathFreeObject(arg1);
5247
9.29k
    xmlXPathFreeObject(arg2);
5248
9.29k
    return(ret);
5249
9.29k
}
5250
5251
/**
5252
 * Implement the compare operation between a nodeset and a value
5253
 *     `ns` < `val`    (1, 1, ...
5254
 *     `ns` <= `val`   (1, 0, ...
5255
 *     `ns` > `val`    (0, 1, ...
5256
 *     `ns` >= `val`   (0, 0, ...
5257
 *
5258
 * If one object to be compared is a node-set and the other is a boolean,
5259
 * then the comparison will be true if and only if the result of performing
5260
 * the comparison on the boolean and on the result of converting
5261
 * the node-set to a boolean using the boolean function is true.
5262
 *
5263
 * @param ctxt  the XPath Parser context
5264
 * @param inf  less than (1) or greater than (0)
5265
 * @param strict  is the comparison strict
5266
 * @param arg  the node set
5267
 * @param val  the value
5268
 * @returns 0 or 1 depending on the results of the test.
5269
 */
5270
static int
5271
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5272
139k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
139k
    if ((val == NULL) || (arg == NULL) ||
5274
139k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
139k
    switch(val->type) {
5278
65.6k
        case XPATH_NUMBER:
5279
65.6k
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5280
0
        case XPATH_NODESET:
5281
0
        case XPATH_XSLT_TREE:
5282
0
      return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5283
15.1k
        case XPATH_STRING:
5284
15.1k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
58.6k
        case XPATH_BOOLEAN:
5286
58.6k
      xmlXPathValuePush(ctxt, arg);
5287
58.6k
      xmlXPathBooleanFunction(ctxt, 1);
5288
58.6k
      xmlXPathValuePush(ctxt, val);
5289
58.6k
      return(xmlXPathCompareValues(ctxt, inf, strict));
5290
0
  default:
5291
0
            xmlXPathReleaseObject(ctxt->context, arg);
5292
0
            xmlXPathReleaseObject(ctxt->context, val);
5293
0
            XP_ERROR0(XPATH_INVALID_TYPE);
5294
139k
    }
5295
0
    return(0);
5296
139k
}
5297
5298
/**
5299
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5300
 * If one object to be compared is a node-set and the other is a string,
5301
 * then the comparison will be true if and only if there is a node in
5302
 * the node-set such that the result of performing the comparison on the
5303
 * string-value of the node and the other string is true.
5304
 *
5305
 * @param ctxt  XPath parser context
5306
 * @param arg  the nodeset object argument
5307
 * @param str  the string to compare to.
5308
 * @param neq  flag to show whether for '=' (0) or '!=' (1)
5309
 * @returns 0 or 1 depending on the results of the test.
5310
 */
5311
static int
5312
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5313
                           xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5314
13.2k
{
5315
13.2k
    int i;
5316
13.2k
    xmlNodeSetPtr ns;
5317
13.2k
    xmlChar *str2;
5318
13.2k
    unsigned int hash;
5319
5320
13.2k
    if ((str == NULL) || (arg == NULL) ||
5321
13.2k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
13.2k
    ns = arg->nodesetval;
5324
    /*
5325
     * A NULL nodeset compared with a string is always false
5326
     * (since there is no node equal, and no node not equal)
5327
     */
5328
13.2k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
3.10k
        return (0);
5330
10.1k
    hash = xmlXPathStringHash(str);
5331
76.1k
    for (i = 0; i < ns->nodeNr; i++) {
5332
70.6k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
6.48k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
6.48k
            if (str2 == NULL) {
5335
5
                xmlXPathPErrMemory(ctxt);
5336
5
                return(0);
5337
5
            }
5338
6.48k
            if (xmlStrEqual(str, str2)) {
5339
2.92k
                xmlFree(str2);
5340
2.92k
    if (neq)
5341
1.78k
        continue;
5342
1.13k
                return (1);
5343
3.55k
            } else if (neq) {
5344
1.04k
    xmlFree(str2);
5345
1.04k
    return (1);
5346
1.04k
      }
5347
2.51k
            xmlFree(str2);
5348
64.2k
        } else if (neq)
5349
2.58k
      return (1);
5350
70.6k
    }
5351
5.42k
    return (0);
5352
10.1k
}
5353
5354
/**
5355
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5356
 * If one object to be compared is a node-set and the other is a number,
5357
 * then the comparison will be true if and only if there is a node in
5358
 * the node-set such that the result of performing the comparison on the
5359
 * number to be compared and on the result of converting the string-value
5360
 * of that node to a number using the number function is true.
5361
 *
5362
 * @param ctxt  XPath parser context
5363
 * @param arg  the nodeset object argument
5364
 * @param f  the float to compare to
5365
 * @param neq  flag to show whether to compare '=' (0) or '!=' (1)
5366
 * @returns 0 or 1 depending on the results of the test.
5367
 */
5368
static int
5369
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5370
87.0k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
87.0k
  int i, ret=0;
5372
87.0k
  xmlNodeSetPtr ns;
5373
87.0k
  xmlChar *str2;
5374
87.0k
  xmlXPathObjectPtr val;
5375
87.0k
  double v;
5376
5377
87.0k
    if ((arg == NULL) ||
5378
87.0k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
87.0k
    ns = arg->nodesetval;
5382
87.0k
    if (ns != NULL) {
5383
572k
  for (i=0;i<ns->nodeNr;i++) {
5384
491k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
491k
      if (str2 != NULL) {
5386
491k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
491k
    xmlFree(str2);
5388
491k
    xmlXPathNumberFunction(ctxt, 1);
5389
491k
                CHECK_ERROR0;
5390
491k
    val = xmlXPathValuePop(ctxt);
5391
491k
    v = val->floatval;
5392
491k
    xmlXPathReleaseObject(ctxt->context, val);
5393
491k
    if (!xmlXPathIsNaN(v)) {
5394
18.3k
        if ((!neq) && (v==f)) {
5395
4.28k
      ret = 1;
5396
4.28k
      break;
5397
14.0k
        } else if ((neq) && (v!=f)) {
5398
1.21k
      ret = 1;
5399
1.21k
      break;
5400
1.21k
        }
5401
473k
    } else { /* NaN is unequal to any value */
5402
473k
        if (neq)
5403
44.6k
      ret = 1;
5404
473k
    }
5405
491k
      } else {
5406
22
                xmlXPathPErrMemory(ctxt);
5407
22
            }
5408
491k
  }
5409
87.0k
    }
5410
5411
87.0k
    return(ret);
5412
87.0k
}
5413
5414
5415
/**
5416
 * Implement the equal / not equal operation on XPath nodesets:
5417
 * `arg1` == `arg2`  or  `arg1` != `arg2`
5418
 * If both objects to be compared are node-sets, then the comparison
5419
 * will be true if and only if there is a node in the first node-set and
5420
 * a node in the second node-set such that the result of performing the
5421
 * comparison on the string-values of the two nodes is true.
5422
 *
5423
 * (needless to say, this is a costly operation)
5424
 *
5425
 * @param ctxt  XPath parser context
5426
 * @param arg1  first nodeset object argument
5427
 * @param arg2  second nodeset object argument
5428
 * @param neq  flag to show whether to test '=' (0) or '!=' (1)
5429
 * @returns 0 or 1 depending on the results of the test.
5430
 */
5431
static int
5432
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5433
73.0k
                      xmlXPathObjectPtr arg2, int neq) {
5434
73.0k
    int i, j;
5435
73.0k
    unsigned int *hashs1;
5436
73.0k
    unsigned int *hashs2;
5437
73.0k
    xmlChar **values1;
5438
73.0k
    xmlChar **values2;
5439
73.0k
    int ret = 0;
5440
73.0k
    xmlNodeSetPtr ns1;
5441
73.0k
    xmlNodeSetPtr ns2;
5442
5443
73.0k
    if ((arg1 == NULL) ||
5444
73.0k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
73.0k
    if ((arg2 == NULL) ||
5447
73.0k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
73.0k
    ns1 = arg1->nodesetval;
5451
73.0k
    ns2 = arg2->nodesetval;
5452
5453
73.0k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
33.9k
  return(0);
5455
39.1k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
5.39k
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
33.7k
    if (neq == 0)
5462
135k
  for (i = 0;i < ns1->nodeNr;i++)
5463
301k
      for (j = 0;j < ns2->nodeNr;j++)
5464
195k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
3.83k
        return(1);
5466
5467
29.8k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
29.8k
    if (values1 == NULL) {
5469
5
        xmlXPathPErrMemory(ctxt);
5470
5
  return(0);
5471
5
    }
5472
29.8k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
29.8k
    if (hashs1 == NULL) {
5474
6
        xmlXPathPErrMemory(ctxt);
5475
6
  xmlFree(values1);
5476
6
  return(0);
5477
6
    }
5478
29.8k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
29.8k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
29.8k
    if (values2 == NULL) {
5481
5
        xmlXPathPErrMemory(ctxt);
5482
5
  xmlFree(hashs1);
5483
5
  xmlFree(values1);
5484
5
  return(0);
5485
5
    }
5486
29.8k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
29.8k
    if (hashs2 == NULL) {
5488
3
        xmlXPathPErrMemory(ctxt);
5489
3
  xmlFree(hashs1);
5490
3
  xmlFree(values1);
5491
3
  xmlFree(values2);
5492
3
  return(0);
5493
3
    }
5494
29.8k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
129k
    for (i = 0;i < ns1->nodeNr;i++) {
5496
105k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
217k
  for (j = 0;j < ns2->nodeNr;j++) {
5498
118k
      if (i == 0)
5499
38.6k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
118k
      if (hashs1[i] != hashs2[j]) {
5501
98.8k
    if (neq) {
5502
2.29k
        ret = 1;
5503
2.29k
        break;
5504
2.29k
    }
5505
98.8k
      }
5506
19.4k
      else {
5507
19.4k
    if (values1[i] == NULL) {
5508
11.3k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
11.3k
                    if (values1[i] == NULL)
5510
20
                        xmlXPathPErrMemory(ctxt);
5511
11.3k
                }
5512
19.4k
    if (values2[j] == NULL) {
5513
12.1k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
12.1k
                    if (values2[j] == NULL)
5515
11
                        xmlXPathPErrMemory(ctxt);
5516
12.1k
                }
5517
19.4k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
19.4k
    if (ret)
5519
4.48k
        break;
5520
19.4k
      }
5521
118k
  }
5522
105k
  if (ret)
5523
6.77k
      break;
5524
105k
    }
5525
139k
    for (i = 0;i < ns1->nodeNr;i++)
5526
109k
  if (values1[i] != NULL)
5527
11.2k
      xmlFree(values1[i]);
5528
181k
    for (j = 0;j < ns2->nodeNr;j++)
5529
151k
  if (values2[j] != NULL)
5530
12.1k
      xmlFree(values2[j]);
5531
29.8k
    xmlFree(values1);
5532
29.8k
    xmlFree(values2);
5533
29.8k
    xmlFree(hashs1);
5534
29.8k
    xmlFree(hashs2);
5535
29.8k
    return(ret);
5536
29.8k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
358k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
358k
    int ret = 0;
5542
    /*
5543
     *At this point we are assured neither arg1 nor arg2
5544
     *is a nodeset, so we can just pick the appropriate routine.
5545
     */
5546
358k
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
188k
        case XPATH_BOOLEAN:
5550
188k
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
88.4k
    case XPATH_BOOLEAN:
5554
88.4k
        ret = (arg1->boolval == arg2->boolval);
5555
88.4k
        break;
5556
95.1k
    case XPATH_NUMBER:
5557
95.1k
        ret = (arg1->boolval ==
5558
95.1k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
95.1k
        break;
5560
5.22k
    case XPATH_STRING:
5561
5.22k
        if ((arg2->stringval == NULL) ||
5562
5.22k
      (arg2->stringval[0] == 0)) ret = 0;
5563
1.95k
        else
5564
1.95k
      ret = 1;
5565
5.22k
        ret = (arg1->boolval == ret);
5566
5.22k
        break;
5567
0
    case XPATH_USERS:
5568
        /* TODO */
5569
0
        break;
5570
0
    case XPATH_NODESET:
5571
0
    case XPATH_XSLT_TREE:
5572
0
        break;
5573
188k
      }
5574
188k
      break;
5575
188k
        case XPATH_NUMBER:
5576
156k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
105k
    case XPATH_BOOLEAN:
5580
105k
        ret = (arg2->boolval==
5581
105k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
105k
        break;
5583
3.01k
    case XPATH_STRING:
5584
3.01k
        xmlXPathValuePush(ctxt, arg2);
5585
3.01k
        xmlXPathNumberFunction(ctxt, 1);
5586
3.01k
        arg2 = xmlXPathValuePop(ctxt);
5587
3.01k
                    if (ctxt->error)
5588
2
                        break;
5589
                    /* Falls through. */
5590
50.6k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
50.6k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
50.6k
          xmlXPathIsNaN(arg2->floatval)) {
5594
23.6k
            ret = 0;
5595
27.0k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
2.40k
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
1.00k
          ret = 1;
5598
1.39k
      else
5599
1.39k
          ret = 0;
5600
24.6k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
2.49k
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
928
          ret = 1;
5603
1.57k
      else
5604
1.57k
          ret = 0;
5605
22.1k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
1.12k
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
1.12k
      else
5609
1.12k
          ret = 0;
5610
21.0k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
1.00k
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
1.00k
      else
5614
1.00k
          ret = 0;
5615
20.0k
        } else {
5616
20.0k
            ret = (arg1->floatval == arg2->floatval);
5617
20.0k
        }
5618
50.6k
        break;
5619
0
    case XPATH_USERS:
5620
        /* TODO */
5621
0
        break;
5622
0
    case XPATH_NODESET:
5623
0
    case XPATH_XSLT_TREE:
5624
0
        break;
5625
156k
      }
5626
156k
      break;
5627
156k
        case XPATH_STRING:
5628
13.1k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
2.30k
    case XPATH_BOOLEAN:
5632
2.30k
        if ((arg1->stringval == NULL) ||
5633
2.30k
      (arg1->stringval[0] == 0)) ret = 0;
5634
1.54k
        else
5635
1.54k
      ret = 1;
5636
2.30k
        ret = (arg2->boolval == ret);
5637
2.30k
        break;
5638
820
    case XPATH_STRING:
5639
820
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
820
        break;
5641
10.0k
    case XPATH_NUMBER:
5642
10.0k
        xmlXPathValuePush(ctxt, arg1);
5643
10.0k
        xmlXPathNumberFunction(ctxt, 1);
5644
10.0k
        arg1 = xmlXPathValuePop(ctxt);
5645
10.0k
                    if (ctxt->error)
5646
10
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
10.0k
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
10.0k
          xmlXPathIsNaN(arg2->floatval)) {
5650
3.92k
            ret = 0;
5651
6.08k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
1.69k
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
741
          ret = 1;
5654
956
      else
5655
956
          ret = 0;
5656
4.39k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
1.84k
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
722
          ret = 1;
5659
1.12k
      else
5660
1.12k
          ret = 0;
5661
2.54k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
765
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
765
      else
5665
765
          ret = 0;
5666
1.78k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
724
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
724
      else
5670
724
          ret = 0;
5671
1.05k
        } else {
5672
1.05k
            ret = (arg1->floatval == arg2->floatval);
5673
1.05k
        }
5674
10.0k
        break;
5675
0
    case XPATH_USERS:
5676
        /* TODO */
5677
0
        break;
5678
0
    case XPATH_NODESET:
5679
0
    case XPATH_XSLT_TREE:
5680
0
        break;
5681
13.1k
      }
5682
13.1k
      break;
5683
13.1k
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
358k
    }
5690
358k
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
358k
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
358k
    return(ret);
5693
358k
}
5694
5695
/**
5696
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5697
 *
5698
 * @param ctxt  the XPath Parser context
5699
 * @returns 0 or 1 depending on the results of the test.
5700
 */
5701
int
5702
532k
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
532k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
532k
    int ret = 0;
5705
5706
532k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
532k
    arg2 = xmlXPathValuePop(ctxt);
5708
532k
    arg1 = xmlXPathValuePop(ctxt);
5709
532k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5710
0
  if (arg1 != NULL)
5711
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5712
0
  else
5713
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5714
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5715
0
    }
5716
5717
532k
    if (arg1 == arg2) {
5718
0
  xmlXPathFreeObject(arg1);
5719
0
        return(1);
5720
0
    }
5721
5722
    /*
5723
     *If either argument is a nodeset, it's a 'special case'
5724
     */
5725
532k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
532k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
222k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
95.6k
    argtmp = arg2;
5732
95.6k
    arg2 = arg1;
5733
95.6k
    arg1 = argtmp;
5734
95.6k
  }
5735
222k
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
67.0k
      case XPATH_NODESET:
5739
67.0k
      case XPATH_XSLT_TREE:
5740
67.0k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
67.0k
    break;
5742
96.2k
      case XPATH_BOOLEAN:
5743
96.2k
    if ((arg1->nodesetval == NULL) ||
5744
96.2k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
20.4k
    else
5746
20.4k
        ret = 1;
5747
96.2k
    ret = (ret == arg2->boolval);
5748
96.2k
    break;
5749
51.3k
      case XPATH_NUMBER:
5750
51.3k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
51.3k
    break;
5752
7.96k
      case XPATH_STRING:
5753
7.96k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
7.96k
                                                 arg2->stringval, 0);
5755
7.96k
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
222k
  }
5760
222k
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
222k
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
222k
  return(ret);
5763
222k
    }
5764
5765
309k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
532k
}
5767
5768
/**
5769
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5770
 *
5771
 * @param ctxt  the XPath Parser context
5772
 * @returns 0 or 1 depending on the results of the test.
5773
 */
5774
int
5775
112k
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
112k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
112k
    int ret = 0;
5778
5779
112k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
112k
    arg2 = xmlXPathValuePop(ctxt);
5781
112k
    arg1 = xmlXPathValuePop(ctxt);
5782
112k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5783
0
  if (arg1 != NULL)
5784
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5785
0
  else
5786
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5787
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5788
0
    }
5789
5790
112k
    if (arg1 == arg2) {
5791
0
  xmlXPathReleaseObject(ctxt->context, arg1);
5792
0
        return(0);
5793
0
    }
5794
5795
    /*
5796
     *If either argument is a nodeset, it's a 'special case'
5797
     */
5798
112k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
112k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
63.5k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
46.2k
    argtmp = arg2;
5805
46.2k
    arg2 = arg1;
5806
46.2k
    arg1 = argtmp;
5807
46.2k
  }
5808
63.5k
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
5.93k
      case XPATH_NODESET:
5812
5.93k
      case XPATH_XSLT_TREE:
5813
5.93k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
5.93k
    break;
5815
16.5k
      case XPATH_BOOLEAN:
5816
16.5k
    if ((arg1->nodesetval == NULL) ||
5817
16.5k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
5.04k
    else
5819
5.04k
        ret = 1;
5820
16.5k
    ret = (ret != arg2->boolval);
5821
16.5k
    break;
5822
35.7k
      case XPATH_NUMBER:
5823
35.7k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
35.7k
    break;
5825
5.32k
      case XPATH_STRING:
5826
5.32k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
5.32k
                                                 arg2->stringval, 1);
5828
5.32k
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
63.5k
  }
5833
63.5k
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
63.5k
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
63.5k
  return(ret);
5836
63.5k
    }
5837
5838
48.7k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
112k
}
5840
5841
/**
5842
 * Implement the compare operation on XPath objects:
5843
 *     `arg1` < `arg2`    (1, 1, ...
5844
 *     `arg1` <= `arg2`   (1, 0, ...
5845
 *     `arg1` > `arg2`    (0, 1, ...
5846
 *     `arg1` >= `arg2`   (0, 0, ...
5847
 *
5848
 * When neither object to be compared is a node-set and the operator is
5849
 * <=, <, >=, >, then the objects are compared by converted both objects
5850
 * to numbers and comparing the numbers according to IEEE 754. The <
5851
 * comparison will be true if and only if the first number is less than the
5852
 * second number. The <= comparison will be true if and only if the first
5853
 * number is less than or equal to the second number. The > comparison
5854
 * will be true if and only if the first number is greater than the second
5855
 * number. The >= comparison will be true if and only if the first number
5856
 * is greater than or equal to the second number.
5857
 *
5858
 * @param ctxt  the XPath Parser context
5859
 * @param inf  less than (1) or greater than (0)
5860
 * @param strict  is the comparison strict
5861
 * @returns 1 if the comparison succeeded, 0 if it failed
5862
 */
5863
int
5864
1.21M
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
1.21M
    int ret = 0, arg1i = 0, arg2i = 0;
5866
1.21M
    xmlXPathObjectPtr arg1, arg2;
5867
5868
1.21M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
1.21M
    arg2 = xmlXPathValuePop(ctxt);
5870
1.21M
    arg1 = xmlXPathValuePop(ctxt);
5871
1.21M
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
30
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
30
  else
5875
30
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
30
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
1.21M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
1.21M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5881
  /*
5882
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
5883
   * are not freed from within this routine; they will be freed from the
5884
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
5885
   */
5886
279k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
279k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
140k
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
140k
  } else {
5890
139k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
33.0k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
33.0k
                                arg1, arg2);
5893
106k
      } else {
5894
106k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
106k
                                arg2, arg1);
5896
106k
      }
5897
139k
  }
5898
279k
  return(ret);
5899
279k
    }
5900
5901
930k
    if (arg1->type != XPATH_NUMBER) {
5902
386k
  xmlXPathValuePush(ctxt, arg1);
5903
386k
  xmlXPathNumberFunction(ctxt, 1);
5904
386k
  arg1 = xmlXPathValuePop(ctxt);
5905
386k
    }
5906
930k
    if (arg2->type != XPATH_NUMBER) {
5907
368k
  xmlXPathValuePush(ctxt, arg2);
5908
368k
  xmlXPathNumberFunction(ctxt, 1);
5909
368k
  arg2 = xmlXPathValuePop(ctxt);
5910
368k
    }
5911
930k
    if (ctxt->error)
5912
982
        goto error;
5913
    /*
5914
     * Add tests for infinity and nan
5915
     * => feedback on 3.4 for Inf and NaN
5916
     */
5917
    /* Hand check NaN and Infinity comparisons */
5918
929k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
823k
  ret=0;
5920
823k
    } else {
5921
106k
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
106k
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
106k
  if (inf && strict) {
5924
40.3k
      if ((arg1i == -1 && arg2i != -1) ||
5925
40.3k
    (arg2i == 1 && arg1i != 1)) {
5926
2.23k
    ret = 1;
5927
38.1k
      } else if (arg1i == 0 && arg2i == 0) {
5928
33.5k
    ret = (arg1->floatval < arg2->floatval);
5929
33.5k
      } else {
5930
4.65k
    ret = 0;
5931
4.65k
      }
5932
40.3k
  }
5933
65.8k
  else if (inf && !strict) {
5934
11.5k
      if (arg1i == -1 || arg2i == 1) {
5935
2.00k
    ret = 1;
5936
9.51k
      } else if (arg1i == 0 && arg2i == 0) {
5937
7.60k
    ret = (arg1->floatval <= arg2->floatval);
5938
7.60k
      } else {
5939
1.91k
    ret = 0;
5940
1.91k
      }
5941
11.5k
  }
5942
54.3k
  else if (!inf && strict) {
5943
44.6k
      if ((arg1i == 1 && arg2i != 1) ||
5944
44.6k
    (arg2i == -1 && arg1i != -1)) {
5945
2.26k
    ret = 1;
5946
42.3k
      } else if (arg1i == 0 && arg2i == 0) {
5947
38.7k
    ret = (arg1->floatval > arg2->floatval);
5948
38.7k
      } else {
5949
3.62k
    ret = 0;
5950
3.62k
      }
5951
44.6k
  }
5952
9.64k
  else if (!inf && !strict) {
5953
9.64k
      if (arg1i == 1 || arg2i == -1) {
5954
5.00k
    ret = 1;
5955
5.00k
      } else if (arg1i == 0 && arg2i == 0) {
5956
2.49k
    ret = (arg1->floatval >= arg2->floatval);
5957
2.49k
      } else {
5958
2.15k
    ret = 0;
5959
2.15k
      }
5960
9.64k
  }
5961
106k
    }
5962
930k
error:
5963
930k
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
930k
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
930k
    return(ret);
5966
929k
}
5967
5968
/**
5969
 * Implement the unary - operation on an XPath object
5970
 * The numeric operators convert their operands to numbers as if
5971
 * by calling the number function.
5972
 *
5973
 * @param ctxt  the XPath Parser context
5974
 */
5975
void
5976
248k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
248k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
248k
    CAST_TO_NUMBER;
5979
248k
    CHECK_TYPE(XPATH_NUMBER);
5980
248k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
248k
}
5982
5983
/**
5984
 * Implement the add operation on XPath objects:
5985
 * The numeric operators convert their operands to numbers as if
5986
 * by calling the number function.
5987
 *
5988
 * @param ctxt  the XPath Parser context
5989
 */
5990
void
5991
106k
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
106k
    xmlXPathObjectPtr arg;
5993
106k
    double val;
5994
5995
106k
    arg = xmlXPathValuePop(ctxt);
5996
106k
    if (arg == NULL)
5997
106k
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
106k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
106k
    xmlXPathReleaseObject(ctxt->context, arg);
6000
106k
    CAST_TO_NUMBER;
6001
106k
    CHECK_TYPE(XPATH_NUMBER);
6002
106k
    ctxt->value->floatval += val;
6003
106k
}
6004
6005
/**
6006
 * Implement the subtraction operation on XPath objects:
6007
 * The numeric operators convert their operands to numbers as if
6008
 * by calling the number function.
6009
 *
6010
 * @param ctxt  the XPath Parser context
6011
 */
6012
void
6013
376k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
376k
    xmlXPathObjectPtr arg;
6015
376k
    double val;
6016
6017
376k
    arg = xmlXPathValuePop(ctxt);
6018
376k
    if (arg == NULL)
6019
376k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
376k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
376k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
376k
    CAST_TO_NUMBER;
6023
376k
    CHECK_TYPE(XPATH_NUMBER);
6024
376k
    ctxt->value->floatval -= val;
6025
376k
}
6026
6027
/**
6028
 * Implement the multiply operation on XPath objects:
6029
 * The numeric operators convert their operands to numbers as if
6030
 * by calling the number function.
6031
 *
6032
 * @param ctxt  the XPath Parser context
6033
 */
6034
void
6035
492k
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
492k
    xmlXPathObjectPtr arg;
6037
492k
    double val;
6038
6039
492k
    arg = xmlXPathValuePop(ctxt);
6040
492k
    if (arg == NULL)
6041
492k
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
492k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
492k
    xmlXPathReleaseObject(ctxt->context, arg);
6044
492k
    CAST_TO_NUMBER;
6045
492k
    CHECK_TYPE(XPATH_NUMBER);
6046
492k
    ctxt->value->floatval *= val;
6047
492k
}
6048
6049
/**
6050
 * Implement the div operation on XPath objects `arg1` / `arg2`.
6051
 * The numeric operators convert their operands to numbers as if
6052
 * by calling the number function.
6053
 *
6054
 * @param ctxt  the XPath Parser context
6055
 */
6056
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6057
void
6058
10.7k
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
10.7k
    xmlXPathObjectPtr arg;
6060
10.7k
    double val;
6061
6062
10.7k
    arg = xmlXPathValuePop(ctxt);
6063
10.7k
    if (arg == NULL)
6064
10.7k
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
10.7k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
10.7k
    xmlXPathReleaseObject(ctxt->context, arg);
6067
10.7k
    CAST_TO_NUMBER;
6068
10.7k
    CHECK_TYPE(XPATH_NUMBER);
6069
10.7k
    ctxt->value->floatval /= val;
6070
10.7k
}
6071
6072
/**
6073
 * Implement the mod operation on XPath objects: `arg1` / `arg2`
6074
 * The numeric operators convert their operands to numbers as if
6075
 * by calling the number function.
6076
 *
6077
 * @param ctxt  the XPath Parser context
6078
 */
6079
void
6080
3.11k
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
3.11k
    xmlXPathObjectPtr arg;
6082
3.11k
    double arg1, arg2;
6083
6084
3.11k
    arg = xmlXPathValuePop(ctxt);
6085
3.11k
    if (arg == NULL)
6086
3.11k
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
3.11k
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
3.11k
    xmlXPathReleaseObject(ctxt->context, arg);
6089
3.11k
    CAST_TO_NUMBER;
6090
3.11k
    CHECK_TYPE(XPATH_NUMBER);
6091
3.11k
    arg1 = ctxt->value->floatval;
6092
3.11k
    if (arg2 == 0)
6093
901
  ctxt->value->floatval = xmlXPathNAN;
6094
2.20k
    else {
6095
2.20k
  ctxt->value->floatval = fmod(arg1, arg2);
6096
2.20k
    }
6097
3.11k
}
6098
6099
/************************************************************************
6100
 *                  *
6101
 *    The traversal functions         *
6102
 *                  *
6103
 ************************************************************************/
6104
6105
/*
6106
 * A traversal function enumerates nodes along an axis.
6107
 * Initially it must be called with NULL, and it indicates
6108
 * termination on the axis by returning NULL.
6109
 */
6110
typedef xmlNode *(*xmlXPathTraversalFunction)
6111
                    (xmlXPathParserContext *ctxt, xmlNode *cur);
6112
6113
/*
6114
 * A traversal function enumerates nodes along an axis.
6115
 * Initially it must be called with NULL, and it indicates
6116
 * termination on the axis by returning NULL.
6117
 * The context node of the traversal is specified via `contextNode`.
6118
 */
6119
typedef xmlNode *(*xmlXPathTraversalFunctionExt)
6120
                    (xmlNode *cur, xmlNode *contextNode);
6121
6122
/*
6123
 * Used for merging node sets in #xmlXPathCollectAndTest.
6124
 */
6125
typedef xmlNodeSet *(*xmlXPathNodeSetMergeFunction)
6126
        (xmlNodeSet *, xmlNodeSet *);
6127
6128
6129
/**
6130
 * Traversal function for the "self" direction
6131
 * The self axis contains just the context node itself
6132
 *
6133
 * @param ctxt  the XPath Parser context
6134
 * @param cur  the current node in the traversal
6135
 * @returns the next element following that axis
6136
 */
6137
xmlNode *
6138
6.21k
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
6.21k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
6.21k
    if (cur == NULL)
6141
3.54k
        return(ctxt->context->node);
6142
2.67k
    return(NULL);
6143
6.21k
}
6144
6145
/**
6146
 * Traversal function for the "child" direction
6147
 * The child axis contains the children of the context node in document order.
6148
 *
6149
 * @param ctxt  the XPath Parser context
6150
 * @param cur  the current node in the traversal
6151
 * @returns the next element following that axis
6152
 */
6153
xmlNode *
6154
3.84M
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
3.84M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
3.84M
    if (cur == NULL) {
6157
1.98M
  if (ctxt->context->node == NULL) return(NULL);
6158
1.98M
  switch (ctxt->context->node->type) {
6159
1.42M
            case XML_ELEMENT_NODE:
6160
1.82M
            case XML_TEXT_NODE:
6161
1.84M
            case XML_CDATA_SECTION_NODE:
6162
1.84M
            case XML_ENTITY_REF_NODE:
6163
1.84M
            case XML_ENTITY_NODE:
6164
1.89M
            case XML_PI_NODE:
6165
1.89M
            case XML_COMMENT_NODE:
6166
1.89M
            case XML_NOTATION_NODE:
6167
1.89M
            case XML_DTD_NODE:
6168
1.89M
    return(ctxt->context->node->children);
6169
37.6k
            case XML_DOCUMENT_NODE:
6170
37.6k
            case XML_DOCUMENT_TYPE_NODE:
6171
37.6k
            case XML_DOCUMENT_FRAG_NODE:
6172
37.6k
            case XML_HTML_DOCUMENT_NODE:
6173
37.6k
    return(((xmlDocPtr) ctxt->context->node)->children);
6174
0
      case XML_ELEMENT_DECL:
6175
0
      case XML_ATTRIBUTE_DECL:
6176
0
      case XML_ENTITY_DECL:
6177
330
            case XML_ATTRIBUTE_NODE:
6178
47.9k
      case XML_NAMESPACE_DECL:
6179
47.9k
      case XML_XINCLUDE_START:
6180
47.9k
      case XML_XINCLUDE_END:
6181
47.9k
    return(NULL);
6182
1.98M
  }
6183
0
  return(NULL);
6184
1.98M
    }
6185
1.85M
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
1.85M
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
1.85M
    return(cur->next);
6189
1.85M
}
6190
6191
/**
6192
 * Traversal function for the "child" direction and nodes of type element.
6193
 * The child axis contains the children of the context node in document order.
6194
 *
6195
 * @param ctxt  the XPath Parser context
6196
 * @param cur  the current node in the traversal
6197
 * @returns the next element following that axis
6198
 */
6199
static xmlNodePtr
6200
5.85M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
5.85M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
5.85M
    if (cur == NULL) {
6203
3.07M
  cur = ctxt->context->node;
6204
3.07M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
3.07M
  switch (cur->type) {
6209
1.98M
            case XML_ELEMENT_NODE:
6210
1.98M
      case XML_DOCUMENT_FRAG_NODE:
6211
1.98M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
1.98M
            case XML_ENTITY_NODE:
6213
1.98M
    cur = cur->children;
6214
1.98M
    if (cur != NULL) {
6215
934k
        if (cur->type == XML_ELEMENT_NODE)
6216
616k
      return(cur);
6217
329k
        do {
6218
329k
      cur = cur->next;
6219
329k
        } while ((cur != NULL) &&
6220
329k
      (cur->type != XML_ELEMENT_NODE));
6221
318k
        return(cur);
6222
934k
    }
6223
1.05M
    return(NULL);
6224
688k
            case XML_DOCUMENT_NODE:
6225
688k
            case XML_HTML_DOCUMENT_NODE:
6226
688k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
395k
      default:
6228
395k
    return(NULL);
6229
3.07M
  }
6230
0
  return(NULL);
6231
3.07M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
2.78M
    switch (cur->type) {
6236
2.78M
  case XML_ELEMENT_NODE:
6237
2.78M
  case XML_TEXT_NODE:
6238
2.78M
  case XML_ENTITY_REF_NODE:
6239
2.78M
  case XML_ENTITY_NODE:
6240
2.78M
  case XML_CDATA_SECTION_NODE:
6241
2.78M
  case XML_PI_NODE:
6242
2.78M
  case XML_COMMENT_NODE:
6243
2.78M
  case XML_XINCLUDE_END:
6244
2.78M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
2.78M
    }
6249
2.78M
    if (cur->next != NULL) {
6250
1.42M
  if (cur->next->type == XML_ELEMENT_NODE)
6251
1.08M
      return(cur->next);
6252
342k
  cur = cur->next;
6253
368k
  do {
6254
368k
      cur = cur->next;
6255
368k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
342k
  return(cur);
6257
1.42M
    }
6258
1.36M
    return(NULL);
6259
2.78M
}
6260
6261
/**
6262
 * Traversal function for the "descendant" direction
6263
 * the descendant axis contains the descendants of the context node in document
6264
 * order; a descendant is a child or a child of a child and so on.
6265
 *
6266
 * @param ctxt  the XPath Parser context
6267
 * @param cur  the current node in the traversal
6268
 * @returns the next element following that axis
6269
 */
6270
xmlNode *
6271
41.8M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
41.8M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
41.8M
    if (cur == NULL) {
6274
356k
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
356k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
356k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
6.17k
      return(NULL);
6279
6280
350k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
52.2k
      return(ctxt->context->doc->children);
6282
298k
        return(ctxt->context->node->children);
6283
350k
    }
6284
6285
41.5M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
41.5M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
6.31M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
6.31M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
6.31M
      if (cur->type != XML_DTD_NODE)
6297
6.28M
    return(cur);
6298
6.31M
  }
6299
6.31M
    }
6300
6301
35.2M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
34.6M
    while (cur->next != NULL) {
6304
33.4M
  cur = cur->next;
6305
33.4M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
33.4M
      (cur->type != XML_DTD_NODE))
6307
33.4M
      return(cur);
6308
33.4M
    }
6309
6310
6.30M
    do {
6311
6.30M
        cur = cur->parent;
6312
6.30M
  if (cur == NULL) break;
6313
6.30M
  if (cur == ctxt->context->node) return(NULL);
6314
5.70M
  if (cur->next != NULL) {
6315
627k
      cur = cur->next;
6316
627k
      return(cur);
6317
627k
  }
6318
5.70M
    } while (cur != NULL);
6319
0
    return(cur);
6320
1.22M
}
6321
6322
/**
6323
 * Traversal function for the "descendant-or-self" direction
6324
 * the descendant-or-self axis contains the context node and the descendants
6325
 * of the context node in document order; thus the context node is the first
6326
 * node on the axis, and the first child of the context node is the second node
6327
 * on the axis
6328
 *
6329
 * @param ctxt  the XPath Parser context
6330
 * @param cur  the current node in the traversal
6331
 * @returns the next element following that axis
6332
 */
6333
xmlNode *
6334
36.8M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
36.8M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
36.8M
    if (cur == NULL)
6337
1.15M
        return(ctxt->context->node);
6338
6339
35.7M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
35.7M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
35.7M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
67.8k
        return(NULL);
6344
6345
35.6M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
35.7M
}
6347
6348
/**
6349
 * Traversal function for the "parent" direction
6350
 * The parent axis contains the parent of the context node, if there is one.
6351
 *
6352
 * @param ctxt  the XPath Parser context
6353
 * @param cur  the current node in the traversal
6354
 * @returns the next element following that axis
6355
 */
6356
xmlNode *
6357
2.20M
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
2.20M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6359
    /*
6360
     * the parent of an attribute or namespace node is the element
6361
     * to which the attribute or namespace node is attached
6362
     * Namespace handling !!!
6363
     */
6364
2.20M
    if (cur == NULL) {
6365
1.12M
  if (ctxt->context->node == NULL) return(NULL);
6366
1.12M
  switch (ctxt->context->node->type) {
6367
832k
            case XML_ELEMENT_NODE:
6368
1.06M
            case XML_TEXT_NODE:
6369
1.06M
            case XML_CDATA_SECTION_NODE:
6370
1.06M
            case XML_ENTITY_REF_NODE:
6371
1.06M
            case XML_ENTITY_NODE:
6372
1.08M
            case XML_PI_NODE:
6373
1.09M
            case XML_COMMENT_NODE:
6374
1.09M
            case XML_NOTATION_NODE:
6375
1.09M
            case XML_DTD_NODE:
6376
1.09M
      case XML_ELEMENT_DECL:
6377
1.09M
      case XML_ATTRIBUTE_DECL:
6378
1.09M
      case XML_XINCLUDE_START:
6379
1.09M
      case XML_XINCLUDE_END:
6380
1.09M
      case XML_ENTITY_DECL:
6381
1.09M
    if (ctxt->context->node->parent == NULL)
6382
66
        return((xmlNodePtr) ctxt->context->doc);
6383
1.09M
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
1.09M
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
1.06M
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
1.06M
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
1.09M
    return(ctxt->context->node->parent);
6389
1.75k
            case XML_ATTRIBUTE_NODE: {
6390
1.75k
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
1.75k
    return(att->parent);
6393
1.09M
      }
6394
24.4k
            case XML_DOCUMENT_NODE:
6395
24.4k
            case XML_DOCUMENT_TYPE_NODE:
6396
24.4k
            case XML_DOCUMENT_FRAG_NODE:
6397
24.4k
            case XML_HTML_DOCUMENT_NODE:
6398
24.4k
                return(NULL);
6399
8.58k
      case XML_NAMESPACE_DECL: {
6400
8.58k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6401
6402
8.58k
    if ((ns->next != NULL) &&
6403
8.58k
        (ns->next->type != XML_NAMESPACE_DECL))
6404
8.58k
        return((xmlNodePtr) ns->next);
6405
0
                return(NULL);
6406
8.58k
      }
6407
1.12M
  }
6408
1.12M
    }
6409
1.08M
    return(NULL);
6410
2.20M
}
6411
6412
/**
6413
 * Traversal function for the "ancestor" direction
6414
 * the ancestor axis contains the ancestors of the context node; the ancestors
6415
 * of the context node consist of the parent of context node and the parent's
6416
 * parent and so on; the nodes are ordered in reverse document order; thus the
6417
 * parent is the first node on the axis, and the parent's parent is the second
6418
 * node on the axis
6419
 *
6420
 * @param ctxt  the XPath Parser context
6421
 * @param cur  the current node in the traversal
6422
 * @returns the next element following that axis
6423
 */
6424
xmlNode *
6425
1.73M
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
1.73M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6427
    /*
6428
     * the parent of an attribute or namespace node is the element
6429
     * to which the attribute or namespace node is attached
6430
     * !!!!!!!!!!!!!
6431
     */
6432
1.73M
    if (cur == NULL) {
6433
80.7k
  if (ctxt->context->node == NULL) return(NULL);
6434
80.7k
  switch (ctxt->context->node->type) {
6435
60.0k
            case XML_ELEMENT_NODE:
6436
73.0k
            case XML_TEXT_NODE:
6437
73.8k
            case XML_CDATA_SECTION_NODE:
6438
73.8k
            case XML_ENTITY_REF_NODE:
6439
73.8k
            case XML_ENTITY_NODE:
6440
75.2k
            case XML_PI_NODE:
6441
75.8k
            case XML_COMMENT_NODE:
6442
75.8k
      case XML_DTD_NODE:
6443
75.8k
      case XML_ELEMENT_DECL:
6444
75.8k
      case XML_ATTRIBUTE_DECL:
6445
75.8k
      case XML_ENTITY_DECL:
6446
75.8k
            case XML_NOTATION_NODE:
6447
75.8k
      case XML_XINCLUDE_START:
6448
75.8k
      case XML_XINCLUDE_END:
6449
75.8k
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
75.8k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
75.8k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
71.8k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
71.8k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
75.8k
    return(ctxt->context->node->parent);
6457
1.00k
            case XML_ATTRIBUTE_NODE: {
6458
1.00k
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
1.00k
    return(tmp->parent);
6461
75.8k
      }
6462
3.06k
            case XML_DOCUMENT_NODE:
6463
3.06k
            case XML_DOCUMENT_TYPE_NODE:
6464
3.06k
            case XML_DOCUMENT_FRAG_NODE:
6465
3.06k
            case XML_HTML_DOCUMENT_NODE:
6466
3.06k
                return(NULL);
6467
814
      case XML_NAMESPACE_DECL: {
6468
814
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
814
    if ((ns->next != NULL) &&
6471
814
        (ns->next->type != XML_NAMESPACE_DECL))
6472
814
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
814
      }
6476
80.7k
  }
6477
0
  return(NULL);
6478
80.7k
    }
6479
1.65M
    if (cur == ctxt->context->doc->children)
6480
82.5k
  return((xmlNodePtr) ctxt->context->doc);
6481
1.57M
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
149k
  return(NULL);
6483
1.42M
    switch (cur->type) {
6484
1.39M
  case XML_ELEMENT_NODE:
6485
1.41M
  case XML_TEXT_NODE:
6486
1.41M
  case XML_CDATA_SECTION_NODE:
6487
1.41M
  case XML_ENTITY_REF_NODE:
6488
1.41M
  case XML_ENTITY_NODE:
6489
1.41M
  case XML_PI_NODE:
6490
1.41M
  case XML_COMMENT_NODE:
6491
1.41M
  case XML_NOTATION_NODE:
6492
1.41M
  case XML_DTD_NODE:
6493
1.41M
        case XML_ELEMENT_DECL:
6494
1.41M
        case XML_ATTRIBUTE_DECL:
6495
1.42M
        case XML_ENTITY_DECL:
6496
1.42M
  case XML_XINCLUDE_START:
6497
1.42M
  case XML_XINCLUDE_END:
6498
1.42M
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
1.42M
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
1.42M
    ((cur->parent->name[0] == ' ') ||
6502
1.35M
     (xmlStrEqual(cur->parent->name,
6503
1.35M
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
1.42M
      return(cur->parent);
6506
400
  case XML_ATTRIBUTE_NODE: {
6507
400
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
400
      return(att->parent);
6510
1.42M
  }
6511
1.03k
  case XML_NAMESPACE_DECL: {
6512
1.03k
      xmlNsPtr ns = (xmlNsPtr) cur;
6513
6514
1.03k
      if ((ns->next != NULL) &&
6515
1.03k
          (ns->next->type != XML_NAMESPACE_DECL))
6516
1.03k
          return((xmlNodePtr) ns->next);
6517
      /* Bad, how did that namespace end up here ? */
6518
0
            return(NULL);
6519
1.03k
  }
6520
0
  case XML_DOCUMENT_NODE:
6521
0
  case XML_DOCUMENT_TYPE_NODE:
6522
0
  case XML_DOCUMENT_FRAG_NODE:
6523
0
  case XML_HTML_DOCUMENT_NODE:
6524
0
      return(NULL);
6525
1.42M
    }
6526
0
    return(NULL);
6527
1.42M
}
6528
6529
/**
6530
 * Traversal function for the "ancestor-or-self" direction
6531
 * he ancestor-or-self axis contains the context node and ancestors of
6532
 * the context node in reverse document order; thus the context node is
6533
 * the first node on the axis, and the context node's parent the second;
6534
 * parent here is defined the same as with the parent axis.
6535
 *
6536
 * @param ctxt  the XPath Parser context
6537
 * @param cur  the current node in the traversal
6538
 * @returns the next element following that axis
6539
 */
6540
xmlNode *
6541
1.37M
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
1.37M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
1.37M
    if (cur == NULL)
6544
72.4k
        return(ctxt->context->node);
6545
1.30M
    return(xmlXPathNextAncestor(ctxt, cur));
6546
1.37M
}
6547
6548
/**
6549
 * Traversal function for the "following-sibling" direction
6550
 * The following-sibling axis contains the following siblings of the context
6551
 * node in document order.
6552
 *
6553
 * @param ctxt  the XPath Parser context
6554
 * @param cur  the current node in the traversal
6555
 * @returns the next element following that axis
6556
 */
6557
xmlNode *
6558
6.00k
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
6.00k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
6.00k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
6.00k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
1.38k
  return(NULL);
6563
4.62k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6564
0
        return(NULL);
6565
4.62k
    if (cur == NULL)
6566
1.44k
        return(ctxt->context->node->next);
6567
3.17k
    return(cur->next);
6568
4.62k
}
6569
6570
/**
6571
 * Traversal function for the "preceding-sibling" direction
6572
 * The preceding-sibling axis contains the preceding siblings of the context
6573
 * node in reverse document order; the first preceding sibling is first on the
6574
 * axis; the sibling preceding that node is the second on the axis and so on.
6575
 *
6576
 * @param ctxt  the XPath Parser context
6577
 * @param cur  the current node in the traversal
6578
 * @returns the next element following that axis
6579
 */
6580
xmlNode *
6581
75.9k
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6582
75.9k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6583
75.9k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6584
75.9k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6585
1.98k
  return(NULL);
6586
73.9k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6587
0
        return(NULL);
6588
73.9k
    if (cur == NULL)
6589
20.9k
        return(ctxt->context->node->prev);
6590
53.0k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6591
235
  cur = cur->prev;
6592
235
  if (cur == NULL)
6593
0
      return(ctxt->context->node->prev);
6594
235
    }
6595
53.0k
    return(cur->prev);
6596
53.0k
}
6597
6598
/**
6599
 * Traversal function for the "following" direction
6600
 * The following axis contains all nodes in the same document as the context
6601
 * node that are after the context node in document order, excluding any
6602
 * descendants and excluding attribute nodes and namespace nodes; the nodes
6603
 * are ordered in document order
6604
 *
6605
 * @param ctxt  the XPath Parser context
6606
 * @param cur  the current node in the traversal
6607
 * @returns the next element following that axis
6608
 */
6609
xmlNode *
6610
4.27M
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6611
4.27M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6612
4.27M
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6613
4.27M
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6614
2.86M
        return(cur->children);
6615
6616
1.40M
    if (cur == NULL) {
6617
20.9k
        cur = ctxt->context->node;
6618
20.9k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6619
1.61k
            cur = cur->parent;
6620
19.3k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6621
852
            xmlNsPtr ns = (xmlNsPtr) cur;
6622
6623
852
            if ((ns->next == NULL) ||
6624
852
                (ns->next->type == XML_NAMESPACE_DECL))
6625
0
                return (NULL);
6626
852
            cur = (xmlNodePtr) ns->next;
6627
852
        }
6628
20.9k
    }
6629
1.40M
    if (cur == NULL) return(NULL) ; /* ERROR */
6630
1.40M
    if (cur->next != NULL) return(cur->next) ;
6631
897k
    do {
6632
897k
        cur = cur->parent;
6633
897k
        if (cur == NULL) break;
6634
896k
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6635
877k
        if (cur->next != NULL) return(cur->next);
6636
877k
    } while (cur != NULL);
6637
1.68k
    return(cur);
6638
347k
}
6639
6640
/*
6641
 * @param ancestor  the ancestor node
6642
 * @param node  the current node
6643
 *
6644
 * Check that `ancestor` is a `node`'s ancestor
6645
 *
6646
 * @returns 1 if `ancestor` is a `node`'s ancestor, 0 otherwise.
6647
 */
6648
static int
6649
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6650
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
6651
0
    if (node->type == XML_NAMESPACE_DECL)
6652
0
        return(0);
6653
0
    if (ancestor->type == XML_NAMESPACE_DECL)
6654
0
        return(0);
6655
    /* nodes need to be in the same document */
6656
0
    if (ancestor->doc != node->doc) return(0);
6657
    /* avoid searching if ancestor or node is the root node */
6658
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
6659
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
6660
0
    while (node->parent != NULL) {
6661
0
        if (node->parent == ancestor)
6662
0
            return(1);
6663
0
  node = node->parent;
6664
0
    }
6665
0
    return(0);
6666
0
}
6667
6668
/**
6669
 * Traversal function for the "preceding" direction
6670
 * the preceding axis contains all nodes in the same document as the context
6671
 * node that are before the context node in document order, excluding any
6672
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6673
 * ordered in reverse document order
6674
 *
6675
 * @param ctxt  the XPath Parser context
6676
 * @param cur  the current node in the traversal
6677
 * @returns the next element following that axis
6678
 */
6679
xmlNode *
6680
xmlXPathNextPreceding(xmlXPathParserContext *ctxt, xmlNode *cur)
6681
0
{
6682
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6683
0
    if (cur == NULL) {
6684
0
        cur = ctxt->context->node;
6685
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6686
0
            cur = cur->parent;
6687
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6688
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6689
6690
0
            if ((ns->next == NULL) ||
6691
0
                (ns->next->type == XML_NAMESPACE_DECL))
6692
0
                return (NULL);
6693
0
            cur = (xmlNodePtr) ns->next;
6694
0
        }
6695
0
    }
6696
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
6697
0
  return (NULL);
6698
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6699
0
  cur = cur->prev;
6700
0
    do {
6701
0
        if (cur->prev != NULL) {
6702
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6703
0
            return (cur);
6704
0
        }
6705
6706
0
        cur = cur->parent;
6707
0
        if (cur == NULL)
6708
0
            return (NULL);
6709
0
        if (cur == ctxt->context->doc->children)
6710
0
            return (NULL);
6711
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
6712
0
    return (cur);
6713
0
}
6714
6715
/**
6716
 * Traversal function for the "preceding" direction
6717
 * the preceding axis contains all nodes in the same document as the context
6718
 * node that are before the context node in document order, excluding any
6719
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6720
 * ordered in reverse document order
6721
 * This is a faster implementation but internal only since it requires a
6722
 * state kept in the parser context: ctxt->ancestor.
6723
 *
6724
 * @param ctxt  the XPath Parser context
6725
 * @param cur  the current node in the traversal
6726
 * @returns the next element following that axis
6727
 */
6728
static xmlNodePtr
6729
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6730
                              xmlNodePtr cur)
6731
1.57M
{
6732
1.57M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6733
1.57M
    if (cur == NULL) {
6734
30.2k
        cur = ctxt->context->node;
6735
30.2k
        if (cur == NULL)
6736
0
            return (NULL);
6737
30.2k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6738
407
            cur = cur->parent;
6739
29.8k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6740
1.18k
            xmlNsPtr ns = (xmlNsPtr) cur;
6741
6742
1.18k
            if ((ns->next == NULL) ||
6743
1.18k
                (ns->next->type == XML_NAMESPACE_DECL))
6744
0
                return (NULL);
6745
1.18k
            cur = (xmlNodePtr) ns->next;
6746
1.18k
        }
6747
30.2k
        ctxt->ancestor = cur->parent;
6748
30.2k
    }
6749
1.57M
    if (cur->type == XML_NAMESPACE_DECL)
6750
0
        return(NULL);
6751
1.57M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6752
771
  cur = cur->prev;
6753
1.73M
    while (cur->prev == NULL) {
6754
432k
        cur = cur->parent;
6755
432k
        if (cur == NULL)
6756
4.73k
            return (NULL);
6757
427k
        if (cur == ctxt->context->doc->children)
6758
25.2k
            return (NULL);
6759
402k
        if (cur != ctxt->ancestor)
6760
247k
            return (cur);
6761
154k
        ctxt->ancestor = cur->parent;
6762
154k
    }
6763
1.29M
    cur = cur->prev;
6764
1.56M
    while (cur->last != NULL)
6765
266k
        cur = cur->last;
6766
1.29M
    return (cur);
6767
1.57M
}
6768
6769
/**
6770
 * Traversal function for the "namespace" direction
6771
 * the namespace axis contains the namespace nodes of the context node;
6772
 * the order of nodes on this axis is implementation-defined; the axis will
6773
 * be empty unless the context node is an element
6774
 *
6775
 * We keep the XML namespace node at the end of the list.
6776
 *
6777
 * @param ctxt  the XPath Parser context
6778
 * @param cur  the current attribute in the traversal
6779
 * @returns the next element following that axis
6780
 */
6781
xmlNode *
6782
1.21M
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6783
1.21M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6784
1.21M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6785
1.12M
    if (cur == NULL) {
6786
233k
        if (ctxt->context->tmpNsList != NULL)
6787
3.85k
      xmlFree(ctxt->context->tmpNsList);
6788
233k
  ctxt->context->tmpNsNr = 0;
6789
233k
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6790
233k
                             &ctxt->context->tmpNsList) < 0) {
6791
5
            xmlXPathPErrMemory(ctxt);
6792
5
            return(NULL);
6793
5
        }
6794
233k
        if (ctxt->context->tmpNsList != NULL) {
6795
867k
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6796
664k
                ctxt->context->tmpNsNr++;
6797
664k
            }
6798
203k
        }
6799
233k
  return((xmlNodePtr) xmlXPathXMLNamespace);
6800
233k
    }
6801
887k
    if (ctxt->context->tmpNsNr > 0) {
6802
661k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6803
661k
    } else {
6804
225k
  if (ctxt->context->tmpNsList != NULL)
6805
198k
      xmlFree(ctxt->context->tmpNsList);
6806
225k
  ctxt->context->tmpNsList = NULL;
6807
225k
  return(NULL);
6808
225k
    }
6809
887k
}
6810
6811
/**
6812
 * Traversal function for the "attribute" direction
6813
 * TODO: support DTD inherited default attributes
6814
 *
6815
 * @param ctxt  the XPath Parser context
6816
 * @param cur  the current attribute in the traversal
6817
 * @returns the next element following that axis
6818
 */
6819
xmlNode *
6820
928k
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6821
928k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6822
928k
    if (ctxt->context->node == NULL)
6823
0
  return(NULL);
6824
928k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6825
295k
  return(NULL);
6826
632k
    if (cur == NULL) {
6827
584k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6828
0
      return(NULL);
6829
584k
        return((xmlNodePtr)ctxt->context->node->properties);
6830
584k
    }
6831
48.8k
    return((xmlNodePtr)cur->next);
6832
632k
}
6833
6834
/************************************************************************
6835
 *                  *
6836
 *    NodeTest Functions          *
6837
 *                  *
6838
 ************************************************************************/
6839
6840
#define IS_FUNCTION     200
6841
6842
6843
/************************************************************************
6844
 *                  *
6845
 *    Implicit tree core function library     *
6846
 *                  *
6847
 ************************************************************************/
6848
6849
/**
6850
 * Initialize the context to the root of the document
6851
 *
6852
 * @param ctxt  the XPath Parser context
6853
 */
6854
void
6855
1.20M
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6856
1.20M
    if ((ctxt == NULL) || (ctxt->context == NULL))
6857
0
  return;
6858
1.20M
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6859
1.20M
                                            (xmlNodePtr) ctxt->context->doc));
6860
1.20M
}
6861
6862
/************************************************************************
6863
 *                  *
6864
 *    The explicit core function library      *
6865
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6866
 *                  *
6867
 ************************************************************************/
6868
6869
6870
/**
6871
 * Implement the last() XPath function
6872
 *    number last()
6873
 * The last function returns the number of nodes in the context node list.
6874
 *
6875
 * @param ctxt  the XPath Parser context
6876
 * @param nargs  the number of arguments
6877
 */
6878
void
6879
16.8k
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6880
50.4k
    CHECK_ARITY(0);
6881
50.4k
    if (ctxt->context->contextSize >= 0) {
6882
16.8k
  xmlXPathValuePush(ctxt,
6883
16.8k
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6884
16.8k
    } else {
6885
1
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6886
0
    }
6887
50.4k
}
6888
6889
/**
6890
 * Implement the position() XPath function
6891
 *    number position()
6892
 * The position function returns the position of the context node in the
6893
 * context node list. The first position is 1, and so the last position
6894
 * will be equal to last().
6895
 *
6896
 * @param ctxt  the XPath Parser context
6897
 * @param nargs  the number of arguments
6898
 */
6899
void
6900
25.6k
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6901
76.7k
    CHECK_ARITY(0);
6902
76.7k
    if (ctxt->context->proximityPosition >= 0) {
6903
25.5k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6904
25.5k
            (double) ctxt->context->proximityPosition));
6905
25.5k
    } else {
6906
1
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6907
0
    }
6908
76.7k
}
6909
6910
/**
6911
 * Implement the count() XPath function
6912
 *    number count(node-set)
6913
 *
6914
 * @param ctxt  the XPath Parser context
6915
 * @param nargs  the number of arguments
6916
 */
6917
void
6918
2.00k
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6919
2.00k
    xmlXPathObjectPtr cur;
6920
6921
5.87k
    CHECK_ARITY(1);
6922
5.87k
    if ((ctxt->value == NULL) ||
6923
1.93k
  ((ctxt->value->type != XPATH_NODESET) &&
6924
1.93k
   (ctxt->value->type != XPATH_XSLT_TREE)))
6925
1.89k
  XP_ERROR(XPATH_INVALID_TYPE);
6926
1.89k
    cur = xmlXPathValuePop(ctxt);
6927
6928
1.89k
    if ((cur == NULL) || (cur->nodesetval == NULL))
6929
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6930
1.89k
    else
6931
1.89k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6932
1.89k
      (double) cur->nodesetval->nodeNr));
6933
1.89k
    xmlXPathReleaseObject(ctxt->context, cur);
6934
1.89k
}
6935
6936
/**
6937
 * Selects elements by their unique ID.
6938
 *
6939
 * @param doc  the document
6940
 * @param ids  a whitespace separated list of IDs
6941
 * @returns a node-set of selected elements.
6942
 */
6943
static xmlNodeSetPtr
6944
1.85M
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6945
1.85M
    xmlNodeSetPtr ret;
6946
1.85M
    const xmlChar *cur = ids;
6947
1.85M
    xmlChar *ID;
6948
1.85M
    xmlAttrPtr attr;
6949
1.85M
    xmlNodePtr elem = NULL;
6950
6951
1.85M
    if (ids == NULL) return(NULL);
6952
6953
1.85M
    ret = xmlXPathNodeSetCreate(NULL);
6954
1.85M
    if (ret == NULL)
6955
32
        return(ret);
6956
6957
1.85M
    while (IS_BLANK_CH(*cur)) cur++;
6958
14.3M
    while (*cur != 0) {
6959
95.6M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6960
83.1M
      cur++;
6961
6962
12.4M
        ID = xmlStrndup(ids, cur - ids);
6963
12.4M
  if (ID == NULL) {
6964
73
            xmlXPathFreeNodeSet(ret);
6965
73
            return(NULL);
6966
73
        }
6967
        /*
6968
         * We used to check the fact that the value passed
6969
         * was an NCName, but this generated much troubles for
6970
         * me and Aleksey Sanin, people blatantly violated that
6971
         * constraint, like Visa3D spec.
6972
         * if (xmlValidateNCName(ID, 1) == 0)
6973
         */
6974
12.4M
        attr = xmlGetID(doc, ID);
6975
12.4M
        xmlFree(ID);
6976
12.4M
        if (attr != NULL) {
6977
95.9k
            if (attr->type == XML_ATTRIBUTE_NODE)
6978
95.9k
                elem = attr->parent;
6979
0
            else if (attr->type == XML_ELEMENT_NODE)
6980
0
                elem = (xmlNodePtr) attr;
6981
0
            else
6982
0
                elem = NULL;
6983
95.9k
            if (elem != NULL) {
6984
95.9k
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
6985
13
                    xmlXPathFreeNodeSet(ret);
6986
13
                    return(NULL);
6987
13
                }
6988
95.9k
            }
6989
95.9k
        }
6990
6991
12.5M
  while (IS_BLANK_CH(*cur)) cur++;
6992
12.4M
  ids = cur;
6993
12.4M
    }
6994
1.85M
    return(ret);
6995
1.85M
}
6996
6997
/**
6998
 * Implement the id() XPath function
6999
 *    node-set id(object)
7000
 * The id function selects elements by their unique ID
7001
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7002
 * then the result is the union of the result of applying id to the
7003
 * string value of each of the nodes in the argument node-set. When the
7004
 * argument to id is of any other type, the argument is converted to a
7005
 * string as if by a call to the string function; the string is split
7006
 * into a whitespace-separated list of tokens (whitespace is any sequence
7007
 * of characters matching the production S); the result is a node-set
7008
 * containing the elements in the same document as the context node that
7009
 * have a unique ID equal to any of the tokens in the list.
7010
 *
7011
 * @param ctxt  the XPath Parser context
7012
 * @param nargs  the number of arguments
7013
 */
7014
void
7015
52.4k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7016
52.4k
    xmlChar *tokens;
7017
52.4k
    xmlNodeSetPtr ret;
7018
52.4k
    xmlXPathObjectPtr obj;
7019
7020
157k
    CHECK_ARITY(1);
7021
157k
    obj = xmlXPathValuePop(ctxt);
7022
157k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7023
52.3k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7024
27.1k
  xmlNodeSetPtr ns;
7025
27.1k
  int i;
7026
7027
27.1k
  ret = xmlXPathNodeSetCreate(NULL);
7028
27.1k
        if (ret == NULL)
7029
12
            xmlXPathPErrMemory(ctxt);
7030
7031
27.1k
  if (obj->nodesetval != NULL) {
7032
1.85M
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7033
1.82M
    tokens =
7034
1.82M
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7035
1.82M
                if (tokens == NULL)
7036
20
                    xmlXPathPErrMemory(ctxt);
7037
1.82M
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7038
1.82M
                if (ns == NULL)
7039
91
                    xmlXPathPErrMemory(ctxt);
7040
1.82M
    ret = xmlXPathNodeSetMerge(ret, ns);
7041
1.82M
                if (ret == NULL)
7042
5
                    xmlXPathPErrMemory(ctxt);
7043
1.82M
    xmlXPathFreeNodeSet(ns);
7044
1.82M
    if (tokens != NULL)
7045
1.82M
        xmlFree(tokens);
7046
1.82M
      }
7047
27.1k
  }
7048
27.1k
  xmlXPathReleaseObject(ctxt->context, obj);
7049
27.1k
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7050
27.1k
  return;
7051
27.1k
    }
7052
25.2k
    tokens = xmlXPathCastToString(obj);
7053
25.2k
    if (tokens == NULL)
7054
25
        xmlXPathPErrMemory(ctxt);
7055
25.2k
    xmlXPathReleaseObject(ctxt->context, obj);
7056
25.2k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7057
25.2k
    if (ret == NULL)
7058
72
        xmlXPathPErrMemory(ctxt);
7059
25.2k
    xmlFree(tokens);
7060
25.2k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7061
25.2k
}
7062
7063
/**
7064
 * Implement the local-name() XPath function
7065
 *    string local-name(node-set?)
7066
 * The local-name function returns a string containing the local part
7067
 * of the name of the node in the argument node-set that is first in
7068
 * document order. If the node-set is empty or the first node has no
7069
 * name, an empty string is returned. If the argument is omitted it
7070
 * defaults to the context node.
7071
 *
7072
 * @param ctxt  the XPath Parser context
7073
 * @param nargs  the number of arguments
7074
 */
7075
void
7076
14.1k
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7077
14.1k
    xmlXPathObjectPtr cur;
7078
7079
14.1k
    if (ctxt == NULL) return;
7080
7081
14.1k
    if (nargs == 0) {
7082
1.50k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7083
1.50k
  nargs = 1;
7084
1.50k
    }
7085
7086
42.5k
    CHECK_ARITY(1);
7087
42.5k
    if ((ctxt->value == NULL) ||
7088
14.1k
  ((ctxt->value->type != XPATH_NODESET) &&
7089
14.1k
   (ctxt->value->type != XPATH_XSLT_TREE)))
7090
14.1k
  XP_ERROR(XPATH_INVALID_TYPE);
7091
14.1k
    cur = xmlXPathValuePop(ctxt);
7092
7093
14.1k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7094
580
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7095
13.5k
    } else {
7096
13.5k
  int i = 0; /* Should be first in document order !!!!! */
7097
13.5k
  switch (cur->nodesetval->nodeTab[i]->type) {
7098
596
  case XML_ELEMENT_NODE:
7099
790
  case XML_ATTRIBUTE_NODE:
7100
1.24k
  case XML_PI_NODE:
7101
1.24k
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7102
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7103
1.24k
      else
7104
1.24k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7105
1.24k
      cur->nodesetval->nodeTab[i]->name));
7106
1.24k
      break;
7107
4.79k
  case XML_NAMESPACE_DECL:
7108
4.79k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7109
4.79k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7110
4.79k
      break;
7111
7.54k
  default:
7112
7.54k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7113
13.5k
  }
7114
13.5k
    }
7115
14.1k
    xmlXPathReleaseObject(ctxt->context, cur);
7116
14.1k
}
7117
7118
/**
7119
 * Implement the namespace-uri() XPath function
7120
 *    string namespace-uri(node-set?)
7121
 * The namespace-uri function returns a string containing the
7122
 * namespace URI of the expanded name of the node in the argument
7123
 * node-set that is first in document order. If the node-set is empty,
7124
 * the first node has no name, or the expanded name has no namespace
7125
 * URI, an empty string is returned. If the argument is omitted it
7126
 * defaults to the context node.
7127
 *
7128
 * @param ctxt  the XPath Parser context
7129
 * @param nargs  the number of arguments
7130
 */
7131
void
7132
2.07k
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7133
2.07k
    xmlXPathObjectPtr cur;
7134
7135
2.07k
    if (ctxt == NULL) return;
7136
7137
2.07k
    if (nargs == 0) {
7138
1.20k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7139
1.20k
  nargs = 1;
7140
1.20k
    }
7141
6.21k
    CHECK_ARITY(1);
7142
6.21k
    if ((ctxt->value == NULL) ||
7143
2.07k
  ((ctxt->value->type != XPATH_NODESET) &&
7144
2.07k
   (ctxt->value->type != XPATH_XSLT_TREE)))
7145
2.06k
  XP_ERROR(XPATH_INVALID_TYPE);
7146
2.06k
    cur = xmlXPathValuePop(ctxt);
7147
7148
2.06k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7149
628
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7150
1.44k
    } else {
7151
1.44k
  int i = 0; /* Should be first in document order !!!!! */
7152
1.44k
  switch (cur->nodesetval->nodeTab[i]->type) {
7153
927
  case XML_ELEMENT_NODE:
7154
927
  case XML_ATTRIBUTE_NODE:
7155
927
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7156
728
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7157
199
      else
7158
199
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7159
199
        cur->nodesetval->nodeTab[i]->ns->href));
7160
927
      break;
7161
513
  default:
7162
513
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7163
1.44k
  }
7164
1.44k
    }
7165
2.06k
    xmlXPathReleaseObject(ctxt->context, cur);
7166
2.06k
}
7167
7168
/**
7169
 * Implement the name() XPath function
7170
 *    string name(node-set?)
7171
 * The name function returns a string containing a QName representing
7172
 * the name of the node in the argument node-set that is first in document
7173
 * order. The QName must represent the name with respect to the namespace
7174
 * declarations in effect on the node whose name is being represented.
7175
 * Typically, this will be the form in which the name occurred in the XML
7176
 * source. This need not be the case if there are namespace declarations
7177
 * in effect on the node that associate multiple prefixes with the same
7178
 * namespace. However, an implementation may include information about
7179
 * the original prefix in its representation of nodes; in this case, an
7180
 * implementation can ensure that the returned string is always the same
7181
 * as the QName used in the XML source. If the argument it omitted it
7182
 * defaults to the context node.
7183
 * Libxml keep the original prefix so the "real qualified name" used is
7184
 * returned.
7185
 *
7186
 * @param ctxt  the XPath Parser context
7187
 * @param nargs  the number of arguments
7188
 */
7189
static void
7190
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7191
52.9k
{
7192
52.9k
    xmlXPathObjectPtr cur;
7193
7194
52.9k
    if (nargs == 0) {
7195
49.1k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7196
49.1k
        nargs = 1;
7197
49.1k
    }
7198
7199
158k
    CHECK_ARITY(1);
7200
158k
    if ((ctxt->value == NULL) ||
7201
52.8k
        ((ctxt->value->type != XPATH_NODESET) &&
7202
52.8k
         (ctxt->value->type != XPATH_XSLT_TREE)))
7203
52.8k
        XP_ERROR(XPATH_INVALID_TYPE);
7204
52.8k
    cur = xmlXPathValuePop(ctxt);
7205
7206
52.8k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7207
2.51k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7208
50.3k
    } else {
7209
50.3k
        int i = 0;              /* Should be first in document order !!!!! */
7210
7211
50.3k
        switch (cur->nodesetval->nodeTab[i]->type) {
7212
38.2k
            case XML_ELEMENT_NODE:
7213
38.2k
            case XML_ATTRIBUTE_NODE:
7214
38.2k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7215
0
        xmlXPathValuePush(ctxt,
7216
0
      xmlXPathCacheNewCString(ctxt, ""));
7217
38.2k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7218
38.2k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7219
37.7k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7220
37.7k
          cur->nodesetval->nodeTab[i]->name));
7221
37.7k
    } else {
7222
542
        xmlChar *fullname;
7223
7224
542
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7225
542
             cur->nodesetval->nodeTab[i]->ns->prefix,
7226
542
             NULL, 0);
7227
542
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7228
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7229
542
        if (fullname == NULL)
7230
3
                        xmlXPathPErrMemory(ctxt);
7231
542
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7232
542
                }
7233
38.2k
                break;
7234
12.0k
            default:
7235
12.0k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7236
12.0k
        cur->nodesetval->nodeTab[i]));
7237
12.0k
                xmlXPathLocalNameFunction(ctxt, 1);
7238
50.3k
        }
7239
50.3k
    }
7240
52.8k
    xmlXPathReleaseObject(ctxt->context, cur);
7241
52.8k
}
7242
7243
7244
/**
7245
 * Implement the string() XPath function
7246
 *    string string(object?)
7247
 * The string function converts an object to a string as follows:
7248
 *    - A node-set is converted to a string by returning the value of
7249
 *      the node in the node-set that is first in document order.
7250
 *      If the node-set is empty, an empty string is returned.
7251
 *    - A number is converted to a string as follows
7252
 *      + NaN is converted to the string NaN
7253
 *      + positive zero is converted to the string 0
7254
 *      + negative zero is converted to the string 0
7255
 *      + positive infinity is converted to the string Infinity
7256
 *      + negative infinity is converted to the string -Infinity
7257
 *      + if the number is an integer, the number is represented in
7258
 *        decimal form as a Number with no decimal point and no leading
7259
 *        zeros, preceded by a minus sign (-) if the number is negative
7260
 *      + otherwise, the number is represented in decimal form as a
7261
 *        Number including a decimal point with at least one digit
7262
 *        before the decimal point and at least one digit after the
7263
 *        decimal point, preceded by a minus sign (-) if the number
7264
 *        is negative; there must be no leading zeros before the decimal
7265
 *        point apart possibly from the one required digit immediately
7266
 *        before the decimal point; beyond the one required digit
7267
 *        after the decimal point there must be as many, but only as
7268
 *        many, more digits as are needed to uniquely distinguish the
7269
 *        number from all other IEEE 754 numeric values.
7270
 *    - The boolean false value is converted to the string false.
7271
 *      The boolean true value is converted to the string true.
7272
 *
7273
 * If the argument is omitted, it defaults to a node-set with the
7274
 * context node as its only member.
7275
 *
7276
 * @param ctxt  the XPath Parser context
7277
 * @param nargs  the number of arguments
7278
 */
7279
void
7280
147k
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7281
147k
    xmlXPathObjectPtr cur;
7282
147k
    xmlChar *stringval;
7283
7284
147k
    if (ctxt == NULL) return;
7285
147k
    if (nargs == 0) {
7286
1.92k
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7287
1.92k
        if (stringval == NULL)
7288
5
            xmlXPathPErrMemory(ctxt);
7289
1.92k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7290
1.92k
  return;
7291
1.92k
    }
7292
7293
580k
    CHECK_ARITY(1);
7294
580k
    cur = xmlXPathValuePop(ctxt);
7295
580k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7296
145k
    if (cur->type != XPATH_STRING) {
7297
144k
        stringval = xmlXPathCastToString(cur);
7298
144k
        if (stringval == NULL)
7299
60
            xmlXPathPErrMemory(ctxt);
7300
144k
        xmlXPathReleaseObject(ctxt->context, cur);
7301
144k
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7302
144k
    }
7303
145k
    xmlXPathValuePush(ctxt, cur);
7304
145k
}
7305
7306
/**
7307
 * Implement the string-length() XPath function
7308
 *    number string-length(string?)
7309
 * The string-length returns the number of characters in the string
7310
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7311
 * the context node converted to a string, in other words the value
7312
 * of the context node.
7313
 *
7314
 * @param ctxt  the XPath Parser context
7315
 * @param nargs  the number of arguments
7316
 */
7317
void
7318
3.21k
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7319
3.21k
    xmlXPathObjectPtr cur;
7320
7321
3.21k
    if (nargs == 0) {
7322
1.08k
        if ((ctxt == NULL) || (ctxt->context == NULL))
7323
0
      return;
7324
1.08k
  if (ctxt->context->node == NULL) {
7325
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7326
1.08k
  } else {
7327
1.08k
      xmlChar *content;
7328
7329
1.08k
      content = xmlXPathCastNodeToString(ctxt->context->node);
7330
1.08k
            if (content == NULL)
7331
2
                xmlXPathPErrMemory(ctxt);
7332
1.08k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7333
1.08k
    xmlUTF8Strlen(content)));
7334
1.08k
      xmlFree(content);
7335
1.08k
  }
7336
1.08k
  return;
7337
1.08k
    }
7338
8.51k
    CHECK_ARITY(1);
7339
8.51k
    CAST_TO_STRING;
7340
8.51k
    CHECK_TYPE(XPATH_STRING);
7341
2.12k
    cur = xmlXPathValuePop(ctxt);
7342
2.12k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7343
2.12k
  xmlUTF8Strlen(cur->stringval)));
7344
2.12k
    xmlXPathReleaseObject(ctxt->context, cur);
7345
2.12k
}
7346
7347
/**
7348
 * Implement the concat() XPath function
7349
 *    string concat(string, string, string*)
7350
 * The concat function returns the concatenation of its arguments.
7351
 *
7352
 * @param ctxt  the XPath Parser context
7353
 * @param nargs  the number of arguments
7354
 */
7355
void
7356
5.15k
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7357
5.15k
    xmlXPathObjectPtr cur, newobj;
7358
5.15k
    xmlChar *tmp;
7359
7360
5.15k
    if (ctxt == NULL) return;
7361
5.15k
    if (nargs < 2) {
7362
9
  CHECK_ARITY(2);
7363
9
    }
7364
7365
5.14k
    CAST_TO_STRING;
7366
5.14k
    cur = xmlXPathValuePop(ctxt);
7367
5.14k
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7368
4
  xmlXPathReleaseObject(ctxt->context, cur);
7369
4
  return;
7370
4
    }
7371
5.13k
    nargs--;
7372
7373
30.1k
    while (nargs > 0) {
7374
25.0k
  CAST_TO_STRING;
7375
25.0k
  newobj = xmlXPathValuePop(ctxt);
7376
25.0k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7377
5
      xmlXPathReleaseObject(ctxt->context, newobj);
7378
5
      xmlXPathReleaseObject(ctxt->context, cur);
7379
5
      XP_ERROR(XPATH_INVALID_TYPE);
7380
0
  }
7381
25.0k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7382
25.0k
        if (tmp == NULL)
7383
2
            xmlXPathPErrMemory(ctxt);
7384
25.0k
  newobj->stringval = cur->stringval;
7385
25.0k
  cur->stringval = tmp;
7386
25.0k
  xmlXPathReleaseObject(ctxt->context, newobj);
7387
25.0k
  nargs--;
7388
25.0k
    }
7389
5.13k
    xmlXPathValuePush(ctxt, cur);
7390
5.13k
}
7391
7392
/**
7393
 * Implement the contains() XPath function
7394
 *    boolean contains(string, string)
7395
 * The contains function returns true if the first argument string
7396
 * contains the second argument string, and otherwise returns false.
7397
 *
7398
 * @param ctxt  the XPath Parser context
7399
 * @param nargs  the number of arguments
7400
 */
7401
void
7402
1.18k
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7403
1.18k
    xmlXPathObjectPtr hay, needle;
7404
7405
3.29k
    CHECK_ARITY(2);
7406
3.29k
    CAST_TO_STRING;
7407
3.29k
    CHECK_TYPE(XPATH_STRING);
7408
1.05k
    needle = xmlXPathValuePop(ctxt);
7409
1.05k
    CAST_TO_STRING;
7410
1.05k
    hay = xmlXPathValuePop(ctxt);
7411
7412
1.05k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7413
4
  xmlXPathReleaseObject(ctxt->context, hay);
7414
4
  xmlXPathReleaseObject(ctxt->context, needle);
7415
4
  XP_ERROR(XPATH_INVALID_TYPE);
7416
0
    }
7417
1.04k
    if (xmlStrstr(hay->stringval, needle->stringval))
7418
560
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7419
489
    else
7420
489
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7421
1.04k
    xmlXPathReleaseObject(ctxt->context, hay);
7422
1.04k
    xmlXPathReleaseObject(ctxt->context, needle);
7423
1.04k
}
7424
7425
/**
7426
 * Implement the starts-with() XPath function
7427
 *    boolean starts-with(string, string)
7428
 * The starts-with function returns true if the first argument string
7429
 * starts with the second argument string, and otherwise returns false.
7430
 *
7431
 * @param ctxt  the XPath Parser context
7432
 * @param nargs  the number of arguments
7433
 */
7434
void
7435
1.67k
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7436
1.67k
    xmlXPathObjectPtr hay, needle;
7437
1.67k
    int n;
7438
7439
4.93k
    CHECK_ARITY(2);
7440
4.93k
    CAST_TO_STRING;
7441
4.93k
    CHECK_TYPE(XPATH_STRING);
7442
1.62k
    needle = xmlXPathValuePop(ctxt);
7443
1.62k
    CAST_TO_STRING;
7444
1.62k
    hay = xmlXPathValuePop(ctxt);
7445
7446
1.62k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7447
5
  xmlXPathReleaseObject(ctxt->context, hay);
7448
5
  xmlXPathReleaseObject(ctxt->context, needle);
7449
5
  XP_ERROR(XPATH_INVALID_TYPE);
7450
0
    }
7451
1.62k
    n = xmlStrlen(needle->stringval);
7452
1.62k
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7453
459
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7454
1.16k
    else
7455
1.16k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7456
1.62k
    xmlXPathReleaseObject(ctxt->context, hay);
7457
1.62k
    xmlXPathReleaseObject(ctxt->context, needle);
7458
1.62k
}
7459
7460
/**
7461
 * Implement the substring() XPath function
7462
 *    string substring(string, number, number?)
7463
 * The substring function returns the substring of the first argument
7464
 * starting at the position specified in the second argument with
7465
 * length specified in the third argument. For example,
7466
 * substring("12345",2,3) returns "234". If the third argument is not
7467
 * specified, it returns the substring starting at the position specified
7468
 * in the second argument and continuing to the end of the string. For
7469
 * example, substring("12345",2) returns "2345".  More precisely, each
7470
 * character in the string (see [3.6 Strings]) is considered to have a
7471
 * numeric position: the position of the first character is 1, the position
7472
 * of the second character is 2 and so on. The returned substring contains
7473
 * those characters for which the position of the character is greater than
7474
 * or equal to the second argument and, if the third argument is specified,
7475
 * less than the sum of the second and third arguments; the comparisons
7476
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7477
 *  - substring("12345", 1.5, 2.6) returns "234"
7478
 *  - substring("12345", 0, 3) returns "12"
7479
 *  - substring("12345", 0 div 0, 3) returns ""
7480
 *  - substring("12345", 1, 0 div 0) returns ""
7481
 *  - substring("12345", -42, 1 div 0) returns "12345"
7482
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
7483
 *
7484
 * @param ctxt  the XPath Parser context
7485
 * @param nargs  the number of arguments
7486
 */
7487
void
7488
7.83k
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7489
7.83k
    xmlXPathObjectPtr str, start, len;
7490
7.83k
    double le=0, in;
7491
7.83k
    int i = 1, j = INT_MAX;
7492
7493
7.83k
    if (nargs < 2) {
7494
42
  CHECK_ARITY(2);
7495
42
    }
7496
7.79k
    if (nargs > 3) {
7497
14
  CHECK_ARITY(3);
7498
14
    }
7499
    /*
7500
     * take care of possible last (position) argument
7501
    */
7502
7.77k
    if (nargs == 3) {
7503
2.25k
  CAST_TO_NUMBER;
7504
2.25k
  CHECK_TYPE(XPATH_NUMBER);
7505
2.25k
  len = xmlXPathValuePop(ctxt);
7506
2.25k
  le = len->floatval;
7507
2.25k
  xmlXPathReleaseObject(ctxt->context, len);
7508
2.25k
    }
7509
7510
7.77k
    CAST_TO_NUMBER;
7511
7.77k
    CHECK_TYPE(XPATH_NUMBER);
7512
7.77k
    start = xmlXPathValuePop(ctxt);
7513
7.77k
    in = start->floatval;
7514
7.77k
    xmlXPathReleaseObject(ctxt->context, start);
7515
7.77k
    CAST_TO_STRING;
7516
7.77k
    CHECK_TYPE(XPATH_STRING);
7517
7.77k
    str = xmlXPathValuePop(ctxt);
7518
7519
7.77k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7520
1.95k
        i = INT_MAX;
7521
5.81k
    } else if (in >= 1.0) {
7522
4.19k
        i = (int)in;
7523
4.19k
        if (in - floor(in) >= 0.5)
7524
606
            i += 1;
7525
4.19k
    }
7526
7527
7.77k
    if (nargs == 3) {
7528
2.25k
        double rin, rle, end;
7529
7530
2.25k
        rin = floor(in);
7531
2.25k
        if (in - rin >= 0.5)
7532
460
            rin += 1.0;
7533
7534
2.25k
        rle = floor(le);
7535
2.25k
        if (le - rle >= 0.5)
7536
542
            rle += 1.0;
7537
7538
2.25k
        end = rin + rle;
7539
2.25k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7540
714
            j = 1;
7541
1.54k
        } else if (end < INT_MAX) {
7542
1.03k
            j = (int)end;
7543
1.03k
        }
7544
2.25k
    }
7545
7546
7.77k
    i -= 1;
7547
7.77k
    j -= 1;
7548
7549
7.77k
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7550
3.17k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7551
3.17k
        if (ret == NULL)
7552
3
            xmlXPathPErrMemory(ctxt);
7553
3.17k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7554
3.17k
  xmlFree(ret);
7555
4.59k
    } else {
7556
4.59k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7557
4.59k
    }
7558
7559
7.77k
    xmlXPathReleaseObject(ctxt->context, str);
7560
7.77k
}
7561
7562
/**
7563
 * Implement the substring-before() XPath function
7564
 *    string substring-before(string, string)
7565
 * The substring-before function returns the substring of the first
7566
 * argument string that precedes the first occurrence of the second
7567
 * argument string in the first argument string, or the empty string
7568
 * if the first argument string does not contain the second argument
7569
 * string. For example, substring-before("1999/04/01","/") returns 1999.
7570
 *
7571
 * @param ctxt  the XPath Parser context
7572
 * @param nargs  the number of arguments
7573
 */
7574
void
7575
3.01k
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7576
3.01k
    xmlXPathObjectPtr str = NULL;
7577
3.01k
    xmlXPathObjectPtr find = NULL;
7578
3.01k
    const xmlChar *point;
7579
3.01k
    xmlChar *result;
7580
7581
9.02k
    CHECK_ARITY(2);
7582
9.02k
    CAST_TO_STRING;
7583
9.02k
    find = xmlXPathValuePop(ctxt);
7584
9.02k
    CAST_TO_STRING;
7585
9.02k
    str = xmlXPathValuePop(ctxt);
7586
9.02k
    if (ctxt->error != 0)
7587
2
        goto error;
7588
7589
3.00k
    point = xmlStrstr(str->stringval, find->stringval);
7590
3.00k
    if (point == NULL) {
7591
1.55k
        result = xmlStrdup(BAD_CAST "");
7592
1.55k
    } else {
7593
1.45k
        result = xmlStrndup(str->stringval, point - str->stringval);
7594
1.45k
    }
7595
3.00k
    if (result == NULL) {
7596
1
        xmlXPathPErrMemory(ctxt);
7597
1
        goto error;
7598
1
    }
7599
3.00k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7600
7601
3.00k
error:
7602
3.00k
    xmlXPathReleaseObject(ctxt->context, str);
7603
3.00k
    xmlXPathReleaseObject(ctxt->context, find);
7604
3.00k
}
7605
7606
/**
7607
 * Implement the substring-after() XPath function
7608
 *    string substring-after(string, string)
7609
 * The substring-after function returns the substring of the first
7610
 * argument string that follows the first occurrence of the second
7611
 * argument string in the first argument string, or the empty string
7612
 * if the first argument string does not contain the second argument
7613
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7614
 * and substring-after("1999/04/01","19") returns 99/04/01.
7615
 *
7616
 * @param ctxt  the XPath Parser context
7617
 * @param nargs  the number of arguments
7618
 */
7619
void
7620
3.15k
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7621
3.15k
    xmlXPathObjectPtr str = NULL;
7622
3.15k
    xmlXPathObjectPtr find = NULL;
7623
3.15k
    const xmlChar *point;
7624
3.15k
    xmlChar *result;
7625
7626
9.38k
    CHECK_ARITY(2);
7627
9.38k
    CAST_TO_STRING;
7628
9.38k
    find = xmlXPathValuePop(ctxt);
7629
9.38k
    CAST_TO_STRING;
7630
9.38k
    str = xmlXPathValuePop(ctxt);
7631
9.38k
    if (ctxt->error != 0)
7632
6
        goto error;
7633
7634
3.10k
    point = xmlStrstr(str->stringval, find->stringval);
7635
3.10k
    if (point == NULL) {
7636
1.50k
        result = xmlStrdup(BAD_CAST "");
7637
1.59k
    } else {
7638
1.59k
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7639
1.59k
    }
7640
3.10k
    if (result == NULL) {
7641
2
        xmlXPathPErrMemory(ctxt);
7642
2
        goto error;
7643
2
    }
7644
3.10k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7645
7646
3.11k
error:
7647
3.11k
    xmlXPathReleaseObject(ctxt->context, str);
7648
3.11k
    xmlXPathReleaseObject(ctxt->context, find);
7649
3.11k
}
7650
7651
/**
7652
 * Implement the normalize-space() XPath function
7653
 *    string normalize-space(string?)
7654
 * The normalize-space function returns the argument string with white
7655
 * space normalized by stripping leading and trailing whitespace
7656
 * and replacing sequences of whitespace characters by a single
7657
 * space. Whitespace characters are the same allowed by the S production
7658
 * in XML. If the argument is omitted, it defaults to the context
7659
 * node converted to a string, in other words the value of the context node.
7660
 *
7661
 * @param ctxt  the XPath Parser context
7662
 * @param nargs  the number of arguments
7663
 */
7664
void
7665
12.3k
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7666
12.3k
    xmlChar *source, *target;
7667
12.3k
    int blank;
7668
7669
12.3k
    if (ctxt == NULL) return;
7670
12.3k
    if (nargs == 0) {
7671
        /* Use current context node */
7672
10.8k
        source = xmlXPathCastNodeToString(ctxt->context->node);
7673
10.8k
        if (source == NULL)
7674
4
            xmlXPathPErrMemory(ctxt);
7675
10.8k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7676
10.8k
        nargs = 1;
7677
10.8k
    }
7678
7679
36.8k
    CHECK_ARITY(1);
7680
36.8k
    CAST_TO_STRING;
7681
36.8k
    CHECK_TYPE(XPATH_STRING);
7682
12.2k
    source = ctxt->value->stringval;
7683
12.2k
    if (source == NULL)
7684
5
        return;
7685
12.2k
    target = source;
7686
7687
    /* Skip leading whitespaces */
7688
12.2k
    while (IS_BLANK_CH(*source))
7689
2.00k
        source++;
7690
7691
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7692
12.2k
    blank = 0;
7693
173k
    while (*source) {
7694
160k
        if (IS_BLANK_CH(*source)) {
7695
23.0k
      blank = 1;
7696
137k
        } else {
7697
137k
            if (blank) {
7698
7.10k
                *target++ = 0x20;
7699
7.10k
                blank = 0;
7700
7.10k
            }
7701
137k
            *target++ = *source;
7702
137k
        }
7703
160k
        source++;
7704
160k
    }
7705
12.2k
    *target = 0;
7706
12.2k
}
7707
7708
/**
7709
 * Implement the translate() XPath function
7710
 *    string translate(string, string, string)
7711
 * The translate function returns the first argument string with
7712
 * occurrences of characters in the second argument string replaced
7713
 * by the character at the corresponding position in the third argument
7714
 * string. For example, translate("bar","abc","ABC") returns the string
7715
 * BAr. If there is a character in the second argument string with no
7716
 * character at a corresponding position in the third argument string
7717
 * (because the second argument string is longer than the third argument
7718
 * string), then occurrences of that character in the first argument
7719
 * string are removed. For example,
7720
 * translate("--aaa--","abc-","ABC") returns "AAA".
7721
 * If a character occurs more than once in second
7722
 * argument string, then the first occurrence determines the replacement
7723
 * character. If the third argument string is longer than the second
7724
 * argument string, then excess characters are ignored.
7725
 *
7726
 * @param ctxt  the XPath Parser context
7727
 * @param nargs  the number of arguments
7728
 */
7729
void
7730
7.30k
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7731
7.30k
    xmlXPathObjectPtr str = NULL;
7732
7.30k
    xmlXPathObjectPtr from = NULL;
7733
7.30k
    xmlXPathObjectPtr to = NULL;
7734
7.30k
    xmlBufPtr target;
7735
7.30k
    int offset, max;
7736
7.30k
    int ch;
7737
7.30k
    const xmlChar *point;
7738
7.30k
    xmlChar *cptr, *content;
7739
7740
21.8k
    CHECK_ARITY(3);
7741
7742
21.8k
    CAST_TO_STRING;
7743
21.8k
    to = xmlXPathValuePop(ctxt);
7744
21.8k
    CAST_TO_STRING;
7745
21.8k
    from = xmlXPathValuePop(ctxt);
7746
21.8k
    CAST_TO_STRING;
7747
21.8k
    str = xmlXPathValuePop(ctxt);
7748
21.8k
    if (ctxt->error != 0)
7749
5
        goto error;
7750
7751
    /*
7752
     * Account for quadratic runtime
7753
     */
7754
7.25k
    if (ctxt->context->opLimit != 0) {
7755
4.23k
        unsigned long f1 = xmlStrlen(from->stringval);
7756
4.23k
        unsigned long f2 = xmlStrlen(str->stringval);
7757
7758
4.23k
        if ((f1 > 0) && (f2 > 0)) {
7759
3.09k
            unsigned long p;
7760
7761
3.09k
            f1 = f1 / 10 + 1;
7762
3.09k
            f2 = f2 / 10 + 1;
7763
3.09k
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7764
3.09k
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7765
30
                goto error;
7766
3.09k
        }
7767
4.23k
    }
7768
7769
7.22k
    target = xmlBufCreate(50);
7770
7.22k
    if (target == NULL) {
7771
2
        xmlXPathPErrMemory(ctxt);
7772
2
        goto error;
7773
2
    }
7774
7775
7.22k
    max = xmlUTF8Strlen(to->stringval);
7776
4.96M
    for (cptr = str->stringval; (ch=*cptr); ) {
7777
4.96M
        offset = xmlUTF8Strloc(from->stringval, cptr);
7778
4.96M
        if (offset >= 0) {
7779
285k
            if (offset < max) {
7780
199k
                point = xmlUTF8Strpos(to->stringval, offset);
7781
199k
                if (point)
7782
199k
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7783
199k
            }
7784
285k
        } else
7785
4.67M
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7786
7787
        /* Step to next character in input */
7788
4.96M
        cptr++;
7789
4.96M
        if ( ch & 0x80 ) {
7790
            /* if not simple ascii, verify proper format */
7791
317k
            if ( (ch & 0xc0) != 0xc0 ) {
7792
0
                xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7793
0
                break;
7794
0
            }
7795
            /* then skip over remaining bytes for this char */
7796
950k
            while ( (ch <<= 1) & 0x80 )
7797
633k
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7798
1
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7799
1
                    break;
7800
1
                }
7801
317k
            if (ch & 0x80) /* must have had error encountered */
7802
1
                break;
7803
317k
        }
7804
4.96M
    }
7805
7806
7.22k
    content = xmlBufDetach(target);
7807
7.22k
    if (content == NULL)
7808
11
        xmlXPathPErrMemory(ctxt);
7809
7.21k
    else
7810
7.21k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7811
7.22k
    xmlBufFree(target);
7812
7.26k
error:
7813
7.26k
    xmlXPathReleaseObject(ctxt->context, str);
7814
7.26k
    xmlXPathReleaseObject(ctxt->context, from);
7815
7.26k
    xmlXPathReleaseObject(ctxt->context, to);
7816
7.26k
}
7817
7818
/**
7819
 * Implement the boolean() XPath function
7820
 *    boolean boolean(object)
7821
 * The boolean function converts its argument to a boolean as follows:
7822
 *    - a number is true if and only if it is neither positive or
7823
 *      negative zero nor NaN
7824
 *    - a node-set is true if and only if it is non-empty
7825
 *    - a string is true if and only if its length is non-zero
7826
 *
7827
 * @param ctxt  the XPath Parser context
7828
 * @param nargs  the number of arguments
7829
 */
7830
void
7831
167k
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7832
167k
    xmlXPathObjectPtr cur;
7833
7834
503k
    CHECK_ARITY(1);
7835
503k
    cur = xmlXPathValuePop(ctxt);
7836
503k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7837
167k
    if (cur->type != XPATH_BOOLEAN) {
7838
144k
        int boolval = xmlXPathCastToBoolean(cur);
7839
7840
144k
        xmlXPathReleaseObject(ctxt->context, cur);
7841
144k
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7842
144k
    }
7843
167k
    xmlXPathValuePush(ctxt, cur);
7844
167k
}
7845
7846
/**
7847
 * Implement the not() XPath function
7848
 *    boolean not(boolean)
7849
 * The not function returns true if its argument is false,
7850
 * and false otherwise.
7851
 *
7852
 * @param ctxt  the XPath Parser context
7853
 * @param nargs  the number of arguments
7854
 */
7855
void
7856
2.06k
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7857
6.12k
    CHECK_ARITY(1);
7858
6.12k
    CAST_TO_BOOLEAN;
7859
6.12k
    CHECK_TYPE(XPATH_BOOLEAN);
7860
2.02k
    ctxt->value->boolval = ! ctxt->value->boolval;
7861
2.02k
}
7862
7863
/**
7864
 * Implement the true() XPath function
7865
 *    boolean true()
7866
 *
7867
 * @param ctxt  the XPath Parser context
7868
 * @param nargs  the number of arguments
7869
 */
7870
void
7871
1.45k
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7872
4.29k
    CHECK_ARITY(0);
7873
4.29k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7874
4.29k
}
7875
7876
/**
7877
 * Implement the false() XPath function
7878
 *    boolean false()
7879
 *
7880
 * @param ctxt  the XPath Parser context
7881
 * @param nargs  the number of arguments
7882
 */
7883
void
7884
933
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7885
2.72k
    CHECK_ARITY(0);
7886
2.72k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7887
2.72k
}
7888
7889
/**
7890
 * Implement the lang() XPath function
7891
 *    boolean lang(string)
7892
 * The lang function returns true or false depending on whether the
7893
 * language of the context node as specified by xml:lang attributes
7894
 * is the same as or is a sublanguage of the language specified by
7895
 * the argument string. The language of the context node is determined
7896
 * by the value of the xml:lang attribute on the context node, or, if
7897
 * the context node has no xml:lang attribute, by the value of the
7898
 * xml:lang attribute on the nearest ancestor of the context node that
7899
 * has an xml:lang attribute. If there is no such attribute, then
7900
 * lang returns false. If there is such an attribute, then lang returns
7901
 * true if the attribute value is equal to the argument ignoring case,
7902
 * or if there is some suffix starting with - such that the attribute
7903
 * value is equal to the argument ignoring that suffix of the attribute
7904
 * value and ignoring case.
7905
 *
7906
 * @param ctxt  the XPath Parser context
7907
 * @param nargs  the number of arguments
7908
 */
7909
void
7910
80.5k
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7911
80.5k
    xmlXPathObjectPtr val;
7912
80.5k
    xmlNodePtr cur;
7913
80.5k
    xmlChar *theLang;
7914
80.5k
    const xmlChar *lang;
7915
80.5k
    int ret = 0;
7916
80.5k
    int i;
7917
7918
241k
    CHECK_ARITY(1);
7919
241k
    CAST_TO_STRING;
7920
241k
    CHECK_TYPE(XPATH_STRING);
7921
80.5k
    val = xmlXPathValuePop(ctxt);
7922
80.5k
    lang = val->stringval;
7923
80.5k
    cur = ctxt->context->node;
7924
618k
    while (cur != NULL) {
7925
540k
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7926
540k
                                &theLang) < 0)
7927
2
            xmlXPathPErrMemory(ctxt);
7928
540k
        if (theLang != NULL)
7929
2.52k
            break;
7930
537k
        cur = cur->parent;
7931
537k
    }
7932
80.5k
    if ((theLang != NULL) && (lang != NULL)) {
7933
7.99k
        for (i = 0;lang[i] != 0;i++)
7934
6.29k
            if (toupper(lang[i]) != toupper(theLang[i]))
7935
821
                goto not_equal;
7936
1.70k
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7937
1.26k
            ret = 1;
7938
1.70k
    }
7939
80.5k
not_equal:
7940
80.5k
    if (theLang != NULL)
7941
2.52k
  xmlFree((void *)theLang);
7942
7943
80.5k
    xmlXPathReleaseObject(ctxt->context, val);
7944
80.5k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7945
80.5k
}
7946
7947
/**
7948
 * Implement the number() XPath function
7949
 *    number number(object?)
7950
 *
7951
 * @param ctxt  the XPath Parser context
7952
 * @param nargs  the number of arguments
7953
 */
7954
void
7955
2.28M
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7956
2.28M
    xmlXPathObjectPtr cur;
7957
2.28M
    double res;
7958
7959
2.28M
    if (ctxt == NULL) return;
7960
2.28M
    if (nargs == 0) {
7961
2.42k
  if (ctxt->context->node == NULL) {
7962
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7963
2.42k
  } else {
7964
2.42k
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7965
2.42k
            if (content == NULL)
7966
1
                xmlXPathPErrMemory(ctxt);
7967
7968
2.42k
      res = xmlXPathStringEvalNumber(content);
7969
2.42k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
7970
2.42k
      xmlFree(content);
7971
2.42k
  }
7972
2.42k
  return;
7973
2.42k
    }
7974
7975
9.14M
    CHECK_ARITY(1);
7976
9.14M
    cur = xmlXPathValuePop(ctxt);
7977
9.14M
    if (cur->type != XPATH_NUMBER) {
7978
2.28M
        double floatval;
7979
7980
2.28M
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
7981
2.28M
        xmlXPathReleaseObject(ctxt->context, cur);
7982
2.28M
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
7983
2.28M
    }
7984
9.14M
    xmlXPathValuePush(ctxt, cur);
7985
9.14M
}
7986
7987
/**
7988
 * Implement the sum() XPath function
7989
 *    number sum(node-set)
7990
 * The sum function returns the sum of the values of the nodes in
7991
 * the argument node-set.
7992
 *
7993
 * @param ctxt  the XPath Parser context
7994
 * @param nargs  the number of arguments
7995
 */
7996
void
7997
25.8k
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
7998
25.8k
    xmlXPathObjectPtr cur;
7999
25.8k
    int i;
8000
25.8k
    double res = 0.0;
8001
8002
77.3k
    CHECK_ARITY(1);
8003
77.3k
    if ((ctxt->value == NULL) ||
8004
25.7k
  ((ctxt->value->type != XPATH_NODESET) &&
8005
25.7k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8006
25.7k
  XP_ERROR(XPATH_INVALID_TYPE);
8007
25.7k
    cur = xmlXPathValuePop(ctxt);
8008
8009
25.7k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8010
4.49M
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8011
4.46M
      res += xmlXPathNodeToNumberInternal(ctxt,
8012
4.46M
                                                cur->nodesetval->nodeTab[i]);
8013
4.46M
  }
8014
24.3k
    }
8015
25.7k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8016
25.7k
    xmlXPathReleaseObject(ctxt->context, cur);
8017
25.7k
}
8018
8019
/**
8020
 * Implement the floor() XPath function
8021
 *    number floor(number)
8022
 * The floor function returns the largest (closest to positive infinity)
8023
 * number that is not greater than the argument and that is an integer.
8024
 *
8025
 * @param ctxt  the XPath Parser context
8026
 * @param nargs  the number of arguments
8027
 */
8028
void
8029
1.74k
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
5.15k
    CHECK_ARITY(1);
8031
5.15k
    CAST_TO_NUMBER;
8032
5.15k
    CHECK_TYPE(XPATH_NUMBER);
8033
8034
1.70k
    ctxt->value->floatval = floor(ctxt->value->floatval);
8035
1.70k
}
8036
8037
/**
8038
 * Implement the ceiling() XPath function
8039
 *    number ceiling(number)
8040
 * The ceiling function returns the smallest (closest to negative infinity)
8041
 * number that is not less than the argument and that is an integer.
8042
 *
8043
 * @param ctxt  the XPath Parser context
8044
 * @param nargs  the number of arguments
8045
 */
8046
void
8047
1.45k
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8048
4.28k
    CHECK_ARITY(1);
8049
4.28k
    CAST_TO_NUMBER;
8050
4.28k
    CHECK_TYPE(XPATH_NUMBER);
8051
8052
#ifdef _AIX
8053
    /* Work around buggy ceil() function on AIX */
8054
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8055
#else
8056
1.41k
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8057
1.41k
#endif
8058
1.41k
}
8059
8060
/**
8061
 * Implement the round() XPath function
8062
 *    number round(number)
8063
 * The round function returns the number that is closest to the
8064
 * argument and that is an integer. If there are two such numbers,
8065
 * then the one that is closest to positive infinity is returned.
8066
 *
8067
 * @param ctxt  the XPath Parser context
8068
 * @param nargs  the number of arguments
8069
 */
8070
void
8071
2.32k
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8072
2.32k
    double f;
8073
8074
6.89k
    CHECK_ARITY(1);
8075
6.89k
    CAST_TO_NUMBER;
8076
6.89k
    CHECK_TYPE(XPATH_NUMBER);
8077
8078
2.28k
    f = ctxt->value->floatval;
8079
8080
2.28k
    if ((f >= -0.5) && (f < 0.5)) {
8081
        /* Handles negative zero. */
8082
721
        ctxt->value->floatval *= 0.0;
8083
721
    }
8084
1.56k
    else {
8085
1.56k
        double rounded = floor(f);
8086
1.56k
        if (f - rounded >= 0.5)
8087
492
            rounded += 1.0;
8088
1.56k
        ctxt->value->floatval = rounded;
8089
1.56k
    }
8090
2.28k
}
8091
8092
/************************************************************************
8093
 *                  *
8094
 *      The Parser          *
8095
 *                  *
8096
 ************************************************************************/
8097
8098
/*
8099
 * a few forward declarations since we use a recursive call based
8100
 * implementation.
8101
 */
8102
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8103
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8104
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8105
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8106
8107
/**
8108
 * Parse an XML non-colonized name.
8109
 *
8110
 * @param ctxt  the XPath Parser context
8111
 * @returns the nc name or NULL
8112
 */
8113
8114
xmlChar *
8115
2.36M
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8116
2.36M
    const xmlChar *end;
8117
2.36M
    xmlChar *ret;
8118
8119
2.36M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8120
8121
2.36M
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8122
2.36M
    if (end == NULL) {
8123
17
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8124
0
    }
8125
2.36M
    if (end == ctxt->cur)
8126
37.6k
        return(NULL);
8127
8128
2.32M
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8129
2.32M
    if (ret == NULL)
8130
96
        xmlXPathPErrMemory(ctxt);
8131
2.32M
    ctxt->cur = end;
8132
2.32M
    return(ret);
8133
2.36M
}
8134
8135
8136
/**
8137
 * Parse an XML qualified name
8138
 *
8139
 * @param ctxt  the XPath Parser context
8140
 * @param prefix  a xmlChar **
8141
 * @returns the function returns the local part, and prefix is updated
8142
 *   to get the Prefix if any.
8143
 */
8144
8145
static xmlChar *
8146
53.3k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8147
53.3k
    xmlChar *ret = NULL;
8148
8149
53.3k
    *prefix = NULL;
8150
53.3k
    ret = xmlXPathParseNCName(ctxt);
8151
53.3k
    if (ret && CUR == ':') {
8152
17.1k
        *prefix = ret;
8153
17.1k
  NEXT;
8154
17.1k
  ret = xmlXPathParseNCName(ctxt);
8155
17.1k
    }
8156
53.3k
    return(ret);
8157
53.3k
}
8158
8159
/**
8160
 * parse an XML name
8161
 *
8162
 * @param ctxt  the XPath Parser context
8163
 * @returns the name or NULL
8164
 */
8165
8166
xmlChar *
8167
71.3k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8168
71.3k
    const xmlChar *end;
8169
71.3k
    xmlChar *ret;
8170
8171
71.3k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8172
8173
71.3k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8174
71.3k
    if (end == NULL) {
8175
38
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8176
0
    }
8177
71.3k
    if (end == ctxt->cur)
8178
22.9k
        return(NULL);
8179
8180
48.3k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8181
48.3k
    if (ret == NULL)
8182
45
        xmlXPathPErrMemory(ctxt);
8183
48.3k
    ctxt->cur = end;
8184
48.3k
    return(ret);
8185
71.3k
}
8186
8187
77.1k
#define MAX_FRAC 20
8188
8189
/**
8190
 *  [30a]  Float  ::= Number ('e' Digits?)?
8191
 *
8192
 *  [30]   Number ::=   Digits ('.' Digits?)?
8193
 *                    | '.' Digits
8194
 *  [31]   Digits ::=   [0-9]+
8195
 *
8196
 * Compile a Number in the string
8197
 * In complement of the Number expression, this function also handles
8198
 * negative values : '-' Number.
8199
 *
8200
 * @param str  A string to scan
8201
 * @returns the double value.
8202
 */
8203
double
8204
7.28M
xmlXPathStringEvalNumber(const xmlChar *str) {
8205
7.28M
    const xmlChar *cur = str;
8206
7.28M
    double ret;
8207
7.28M
    int ok = 0;
8208
7.28M
    int isneg = 0;
8209
7.28M
    int exponent = 0;
8210
7.28M
    int is_exponent_negative = 0;
8211
7.28M
#ifdef __GNUC__
8212
7.28M
    unsigned long tmp = 0;
8213
7.28M
    double temp;
8214
7.28M
#endif
8215
7.28M
    if (cur == NULL) return(0);
8216
7.28M
    while (IS_BLANK_CH(*cur)) cur++;
8217
7.28M
    if (*cur == '-') {
8218
73.7k
  isneg = 1;
8219
73.7k
  cur++;
8220
73.7k
    }
8221
7.28M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8222
7.13M
        return(xmlXPathNAN);
8223
7.13M
    }
8224
8225
153k
#ifdef __GNUC__
8226
    /*
8227
     * tmp/temp is a workaround against a gcc compiler bug
8228
     * http://veillard.com/gcc.bug
8229
     */
8230
153k
    ret = 0;
8231
677k
    while ((*cur >= '0') && (*cur <= '9')) {
8232
524k
  ret = ret * 10;
8233
524k
  tmp = (*cur - '0');
8234
524k
  ok = 1;
8235
524k
  cur++;
8236
524k
  temp = (double) tmp;
8237
524k
  ret = ret + temp;
8238
524k
    }
8239
#else
8240
    ret = 0;
8241
    while ((*cur >= '0') && (*cur <= '9')) {
8242
  ret = ret * 10 + (*cur - '0');
8243
  ok = 1;
8244
  cur++;
8245
    }
8246
#endif
8247
8248
153k
    if (*cur == '.') {
8249
72.1k
  int v, frac = 0, max;
8250
72.1k
  double fraction = 0;
8251
8252
72.1k
        cur++;
8253
72.1k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8254
13.8k
      return(xmlXPathNAN);
8255
13.8k
  }
8256
64.6k
        while (*cur == '0') {
8257
6.31k
      frac = frac + 1;
8258
6.31k
      cur++;
8259
6.31k
        }
8260
58.3k
        max = frac + MAX_FRAC;
8261
163k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8262
104k
      v = (*cur - '0');
8263
104k
      fraction = fraction * 10 + v;
8264
104k
      frac = frac + 1;
8265
104k
      cur++;
8266
104k
  }
8267
58.3k
  fraction /= pow(10.0, frac);
8268
58.3k
  ret = ret + fraction;
8269
59.7k
  while ((*cur >= '0') && (*cur <= '9'))
8270
1.40k
      cur++;
8271
58.3k
    }
8272
139k
    if ((*cur == 'e') || (*cur == 'E')) {
8273
29.7k
      cur++;
8274
29.7k
      if (*cur == '-') {
8275
15.3k
  is_exponent_negative = 1;
8276
15.3k
  cur++;
8277
15.3k
      } else if (*cur == '+') {
8278
1.40k
        cur++;
8279
1.40k
      }
8280
135k
      while ((*cur >= '0') && (*cur <= '9')) {
8281
105k
        if (exponent < 1000000)
8282
98.6k
    exponent = exponent * 10 + (*cur - '0');
8283
105k
  cur++;
8284
105k
      }
8285
29.7k
    }
8286
152k
    while (IS_BLANK_CH(*cur)) cur++;
8287
139k
    if (*cur != 0) return(xmlXPathNAN);
8288
65.4k
    if (isneg) ret = -ret;
8289
65.4k
    if (is_exponent_negative) exponent = -exponent;
8290
65.4k
    ret *= pow(10.0, (double)exponent);
8291
65.4k
    return(ret);
8292
139k
}
8293
8294
/**
8295
 *  [30]   Number ::=   Digits ('.' Digits?)?
8296
 *                    | '.' Digits
8297
 *  [31]   Digits ::=   [0-9]+
8298
 *
8299
 * Compile a Number, then push it on the stack
8300
 *
8301
 * @param ctxt  the XPath Parser context
8302
 */
8303
static void
8304
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8305
168k
{
8306
168k
    double ret = 0.0;
8307
168k
    int ok = 0;
8308
168k
    int exponent = 0;
8309
168k
    int is_exponent_negative = 0;
8310
168k
    xmlXPathObjectPtr num;
8311
168k
#ifdef __GNUC__
8312
168k
    unsigned long tmp = 0;
8313
168k
    double temp;
8314
168k
#endif
8315
8316
168k
    CHECK_ERROR;
8317
168k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8318
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8319
0
    }
8320
168k
#ifdef __GNUC__
8321
    /*
8322
     * tmp/temp is a workaround against a gcc compiler bug
8323
     * http://veillard.com/gcc.bug
8324
     */
8325
168k
    ret = 0;
8326
610k
    while ((CUR >= '0') && (CUR <= '9')) {
8327
441k
  ret = ret * 10;
8328
441k
  tmp = (CUR - '0');
8329
441k
        ok = 1;
8330
441k
        NEXT;
8331
441k
  temp = (double) tmp;
8332
441k
  ret = ret + temp;
8333
441k
    }
8334
#else
8335
    ret = 0;
8336
    while ((CUR >= '0') && (CUR <= '9')) {
8337
  ret = ret * 10 + (CUR - '0');
8338
  ok = 1;
8339
  NEXT;
8340
    }
8341
#endif
8342
168k
    if (CUR == '.') {
8343
18.7k
  int v, frac = 0, max;
8344
18.7k
  double fraction = 0;
8345
8346
18.7k
        NEXT;
8347
18.7k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8348
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8349
0
        }
8350
29.7k
        while (CUR == '0') {
8351
10.9k
            frac = frac + 1;
8352
10.9k
            NEXT;
8353
10.9k
        }
8354
18.7k
        max = frac + MAX_FRAC;
8355
45.7k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8356
27.0k
      v = (CUR - '0');
8357
27.0k
      fraction = fraction * 10 + v;
8358
27.0k
      frac = frac + 1;
8359
27.0k
            NEXT;
8360
27.0k
        }
8361
18.7k
        fraction /= pow(10.0, frac);
8362
18.7k
        ret = ret + fraction;
8363
20.6k
        while ((CUR >= '0') && (CUR <= '9'))
8364
1.90k
            NEXT;
8365
18.7k
    }
8366
168k
    if ((CUR == 'e') || (CUR == 'E')) {
8367
20.3k
        NEXT;
8368
20.3k
        if (CUR == '-') {
8369
12.1k
            is_exponent_negative = 1;
8370
12.1k
            NEXT;
8371
12.1k
        } else if (CUR == '+') {
8372
574
      NEXT;
8373
574
  }
8374
57.0k
        while ((CUR >= '0') && (CUR <= '9')) {
8375
36.6k
            if (exponent < 1000000)
8376
32.9k
                exponent = exponent * 10 + (CUR - '0');
8377
36.6k
            NEXT;
8378
36.6k
        }
8379
20.3k
        if (is_exponent_negative)
8380
12.1k
            exponent = -exponent;
8381
20.3k
        ret *= pow(10.0, (double) exponent);
8382
20.3k
    }
8383
168k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8384
168k
    if (num == NULL) {
8385
21
  ctxt->error = XPATH_MEMORY_ERROR;
8386
168k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8387
168k
                              NULL) == -1) {
8388
9
        xmlXPathReleaseObject(ctxt->context, num);
8389
9
    }
8390
168k
}
8391
8392
/**
8393
 * Parse a Literal
8394
 *
8395
 *  [29]   Literal ::=   '"' [^"]* '"'
8396
 *                    | "'" [^']* "'"
8397
 *
8398
 * @param ctxt  the XPath Parser context
8399
 * @returns the value found or NULL in case of error
8400
 */
8401
static xmlChar *
8402
17.7k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8403
17.7k
    const xmlChar *q;
8404
17.7k
    xmlChar *ret = NULL;
8405
17.7k
    int quote;
8406
8407
17.7k
    if (CUR == '"') {
8408
4.79k
        quote = '"';
8409
12.9k
    } else if (CUR == '\'') {
8410
12.9k
        quote = '\'';
8411
12.9k
    } else {
8412
51
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8413
0
    }
8414
8415
17.7k
    NEXT;
8416
17.7k
    q = CUR_PTR;
8417
14.4M
    while (CUR != quote) {
8418
14.4M
        int ch;
8419
14.4M
        int len = 4;
8420
8421
14.4M
        if (CUR == 0)
8422
14.4M
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8423
14.4M
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8424
14.4M
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8425
14.4M
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8426
14.4M
        CUR_PTR += len;
8427
14.4M
    }
8428
17.0k
    ret = xmlStrndup(q, CUR_PTR - q);
8429
17.0k
    if (ret == NULL)
8430
9
        xmlXPathPErrMemory(ctxt);
8431
17.0k
    NEXT;
8432
17.0k
    return(ret);
8433
17.7k
}
8434
8435
/**
8436
 * Parse a Literal and push it on the stack.
8437
 *
8438
 *  [29]   Literal ::=   '"' [^"]* '"'
8439
 *                    | "'" [^']* "'"
8440
 *
8441
 * TODO: Memory allocation could be improved.
8442
 *
8443
 * @param ctxt  the XPath Parser context
8444
 */
8445
static void
8446
17.1k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8447
17.1k
    xmlChar *ret = NULL;
8448
17.1k
    xmlXPathObjectPtr lit;
8449
8450
17.1k
    ret = xmlXPathParseLiteral(ctxt);
8451
17.1k
    if (ret == NULL)
8452
633
        return;
8453
16.5k
    lit = xmlXPathCacheNewString(ctxt, ret);
8454
16.5k
    if (lit == NULL) {
8455
11
        ctxt->error = XPATH_MEMORY_ERROR;
8456
16.5k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8457
16.5k
                              NULL) == -1) {
8458
6
        xmlXPathReleaseObject(ctxt->context, lit);
8459
6
    }
8460
16.5k
    xmlFree(ret);
8461
16.5k
}
8462
8463
/**
8464
 * Parse a VariableReference, evaluate it and push it on the stack.
8465
 *
8466
 * The variable bindings consist of a mapping from variable names
8467
 * to variable values. The value of a variable is an object, which can be
8468
 * of any of the types that are possible for the value of an expression,
8469
 * and may also be of additional types not specified here.
8470
 *
8471
 * Early evaluation is possible since:
8472
 * The variable bindings [...] used to evaluate a subexpression are
8473
 * always the same as those used to evaluate the containing expression.
8474
 *
8475
 *  [36]   VariableReference ::=   '$' QName
8476
 * @param ctxt  the XPath Parser context
8477
 */
8478
static void
8479
20.7k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8480
20.7k
    xmlChar *name;
8481
20.7k
    xmlChar *prefix;
8482
8483
20.7k
    SKIP_BLANKS;
8484
20.7k
    if (CUR != '$') {
8485
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8486
0
    }
8487
20.7k
    NEXT;
8488
20.7k
    name = xmlXPathParseQName(ctxt, &prefix);
8489
20.7k
    if (name == NULL) {
8490
14.5k
        xmlFree(prefix);
8491
14.5k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8492
0
    }
8493
6.21k
    ctxt->comp->last = -1;
8494
6.21k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8495
271
        xmlFree(prefix);
8496
271
        xmlFree(name);
8497
271
    }
8498
6.21k
    SKIP_BLANKS;
8499
6.21k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8500
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8501
0
    }
8502
6.21k
}
8503
8504
/**
8505
 * Is the name given a NodeType one.
8506
 *
8507
 *  [38]   NodeType ::=   'comment'
8508
 *                    | 'text'
8509
 *                    | 'processing-instruction'
8510
 *                    | 'node'
8511
 *
8512
 * @param name  a name string
8513
 * @returns 1 if true 0 otherwise
8514
 */
8515
int
8516
37.0k
xmlXPathIsNodeType(const xmlChar *name) {
8517
37.0k
    if (name == NULL)
8518
0
  return(0);
8519
8520
37.0k
    if (xmlStrEqual(name, BAD_CAST "node"))
8521
2.35k
  return(1);
8522
34.6k
    if (xmlStrEqual(name, BAD_CAST "text"))
8523
819
  return(1);
8524
33.8k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8525
488
  return(1);
8526
33.3k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8527
773
  return(1);
8528
32.6k
    return(0);
8529
33.3k
}
8530
8531
/**
8532
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
8533
 *  [17]   Argument ::=   Expr
8534
 *
8535
 * Compile a function call, the evaluation of all arguments are
8536
 * pushed on the stack
8537
 *
8538
 * @param ctxt  the XPath Parser context
8539
 */
8540
static void
8541
32.6k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8542
32.6k
    xmlChar *name;
8543
32.6k
    xmlChar *prefix;
8544
32.6k
    int nbargs = 0;
8545
32.6k
    int sort = 1;
8546
8547
32.6k
    name = xmlXPathParseQName(ctxt, &prefix);
8548
32.6k
    if (name == NULL) {
8549
73
  xmlFree(prefix);
8550
73
  XP_ERROR(XPATH_EXPR_ERROR);
8551
0
    }
8552
32.5k
    SKIP_BLANKS;
8553
8554
32.5k
    if (CUR != '(') {
8555
42
  xmlFree(name);
8556
42
  xmlFree(prefix);
8557
42
  XP_ERROR(XPATH_EXPR_ERROR);
8558
0
    }
8559
32.4k
    NEXT;
8560
32.4k
    SKIP_BLANKS;
8561
8562
    /*
8563
    * Optimization for count(): we don't need the node-set to be sorted.
8564
    */
8565
32.4k
    if ((prefix == NULL) && (name[0] == 'c') &&
8566
32.4k
  xmlStrEqual(name, BAD_CAST "count"))
8567
1.10k
    {
8568
1.10k
  sort = 0;
8569
1.10k
    }
8570
32.4k
    ctxt->comp->last = -1;
8571
32.4k
    if (CUR != ')') {
8572
1.40M
  while (CUR != 0) {
8573
1.40M
      int op1 = ctxt->comp->last;
8574
1.40M
      ctxt->comp->last = -1;
8575
1.40M
      xmlXPathCompileExpr(ctxt, sort);
8576
1.40M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8577
2.71k
    xmlFree(name);
8578
2.71k
    xmlFree(prefix);
8579
2.71k
    return;
8580
2.71k
      }
8581
1.39M
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8582
1.39M
      nbargs++;
8583
1.39M
      if (CUR == ')') break;
8584
1.38M
      if (CUR != ',') {
8585
318
    xmlFree(name);
8586
318
    xmlFree(prefix);
8587
318
    XP_ERROR(XPATH_EXPR_ERROR);
8588
0
      }
8589
1.38M
      NEXT;
8590
1.38M
      SKIP_BLANKS;
8591
1.38M
  }
8592
23.3k
    }
8593
29.4k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8594
6
        xmlFree(prefix);
8595
6
        xmlFree(name);
8596
6
    }
8597
29.4k
    NEXT;
8598
29.4k
    SKIP_BLANKS;
8599
29.4k
}
8600
8601
/**
8602
 *  [15]   PrimaryExpr ::=   VariableReference
8603
 *                | '(' Expr ')'
8604
 *                | Literal
8605
 *                | Number
8606
 *                | FunctionCall
8607
 *
8608
 * Compile a primary expression.
8609
 *
8610
 * @param ctxt  the XPath Parser context
8611
 */
8612
static void
8613
299k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8614
299k
    SKIP_BLANKS;
8615
299k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8616
278k
    else if (CUR == '(') {
8617
59.8k
  NEXT;
8618
59.8k
  SKIP_BLANKS;
8619
59.8k
  xmlXPathCompileExpr(ctxt, 1);
8620
59.8k
  CHECK_ERROR;
8621
56.7k
  if (CUR != ')') {
8622
164
      XP_ERROR(XPATH_EXPR_ERROR);
8623
0
  }
8624
56.5k
  NEXT;
8625
56.5k
  SKIP_BLANKS;
8626
218k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8627
168k
  xmlXPathCompNumber(ctxt);
8628
168k
    } else if ((CUR == '\'') || (CUR == '"')) {
8629
17.1k
  xmlXPathCompLiteral(ctxt);
8630
32.6k
    } else {
8631
32.6k
  xmlXPathCompFunctionCall(ctxt);
8632
32.6k
    }
8633
295k
    SKIP_BLANKS;
8634
295k
}
8635
8636
/**
8637
 *  [20]   FilterExpr ::=   PrimaryExpr
8638
 *               | FilterExpr Predicate
8639
 *
8640
 * Compile a filter expression.
8641
 * Square brackets are used to filter expressions in the same way that
8642
 * they are used in location paths. It is an error if the expression to
8643
 * be filtered does not evaluate to a node-set. The context node list
8644
 * used for evaluating the expression in square brackets is the node-set
8645
 * to be filtered listed in document order.
8646
 *
8647
 * @param ctxt  the XPath Parser context
8648
 */
8649
8650
static void
8651
299k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8652
299k
    xmlXPathCompPrimaryExpr(ctxt);
8653
299k
    CHECK_ERROR;
8654
274k
    SKIP_BLANKS;
8655
8656
309k
    while (CUR == '[') {
8657
34.5k
  xmlXPathCompPredicate(ctxt, 1);
8658
34.5k
  SKIP_BLANKS;
8659
34.5k
    }
8660
8661
8662
274k
}
8663
8664
/**
8665
 * Trickery: parse an XML name but without consuming the input flow
8666
 * Needed to avoid insanity in the parser state.
8667
 *
8668
 * @param ctxt  the XPath Parser context
8669
 * @returns the Name parsed or NULL
8670
 */
8671
8672
static xmlChar *
8673
16.1M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8674
16.1M
    const xmlChar *end;
8675
16.1M
    xmlChar *ret;
8676
8677
16.1M
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8678
16.1M
    if (end == NULL) {
8679
28
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8680
0
    }
8681
16.1M
    if (end == ctxt->cur)
8682
14.4M
        return(NULL);
8683
8684
1.76M
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8685
1.76M
    if (ret == NULL)
8686
57
        xmlXPathPErrMemory(ctxt);
8687
1.76M
    return(ret);
8688
16.1M
}
8689
8690
/**
8691
 *  [19]   PathExpr ::=   LocationPath
8692
 *               | FilterExpr
8693
 *               | FilterExpr '/' RelativeLocationPath
8694
 *               | FilterExpr '//' RelativeLocationPath
8695
 *
8696
 * Compile a path expression.
8697
 *
8698
 * @param ctxt  the XPath Parser context
8699
 */
8700
8701
static void
8702
22.9M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8703
22.9M
    int lc = 1;           /* Should we branch to LocationPath ?         */
8704
22.9M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8705
8706
22.9M
    SKIP_BLANKS;
8707
22.9M
    if ((CUR == '$') || (CUR == '(') ||
8708
22.9M
  (IS_ASCII_DIGIT(CUR)) ||
8709
22.9M
        (CUR == '\'') || (CUR == '"') ||
8710
22.9M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8711
266k
  lc = 0;
8712
22.6M
    } else if (CUR == '*') {
8713
  /* relative or absolute location path */
8714
6.21M
  lc = 1;
8715
16.4M
    } else if (CUR == '/') {
8716
  /* relative or absolute location path */
8717
171k
  lc = 1;
8718
16.2M
    } else if (CUR == '@') {
8719
  /* relative abbreviated attribute location path */
8720
9.13k
  lc = 1;
8721
16.2M
    } else if (CUR == '.') {
8722
  /* relative abbreviated attribute location path */
8723
58.2k
  lc = 1;
8724
16.1M
    } else {
8725
  /*
8726
   * Problem is finding if we have a name here whether it's:
8727
   *   - a nodetype
8728
   *   - a function call in which case it's followed by '('
8729
   *   - an axis in which case it's followed by ':'
8730
   *   - a element name
8731
   * We do an a priori analysis here rather than having to
8732
   * maintain parsed token content through the recursive function
8733
   * calls. This looks uglier but makes the code easier to
8734
   * read/write/debug.
8735
   */
8736
16.1M
  SKIP_BLANKS;
8737
16.1M
  name = xmlXPathScanName(ctxt);
8738
16.1M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8739
10.3k
      lc = 1;
8740
10.3k
      xmlFree(name);
8741
16.1M
  } else if (name != NULL) {
8742
1.75M
      int len =xmlStrlen(name);
8743
8744
8745
2.32M
      while (NXT(len) != 0) {
8746
2.32M
    if (NXT(len) == '/') {
8747
        /* element name */
8748
39.0k
        lc = 1;
8749
39.0k
        break;
8750
2.28M
    } else if (IS_BLANK_CH(NXT(len))) {
8751
        /* ignore blanks */
8752
572k
        ;
8753
1.70M
    } else if (NXT(len) == ':') {
8754
860
        lc = 1;
8755
860
        break;
8756
1.70M
    } else if ((NXT(len) == '(')) {
8757
        /* Node Type or Function */
8758
37.0k
        if (xmlXPathIsNodeType(name)) {
8759
4.43k
      lc = 1;
8760
32.6k
        } else {
8761
32.6k
      lc = 0;
8762
32.6k
        }
8763
37.0k
                    break;
8764
1.67M
    } else if ((NXT(len) == '[')) {
8765
        /* element name */
8766
6.38k
        lc = 1;
8767
6.38k
        break;
8768
1.66M
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8769
1.66M
         (NXT(len) == '=')) {
8770
135k
        lc = 1;
8771
135k
        break;
8772
1.52M
    } else {
8773
1.52M
        lc = 1;
8774
1.52M
        break;
8775
1.52M
    }
8776
572k
    len++;
8777
572k
      }
8778
1.75M
      if (NXT(len) == 0) {
8779
    /* element name */
8780
4.39k
    lc = 1;
8781
4.39k
      }
8782
1.75M
      xmlFree(name);
8783
14.4M
  } else {
8784
      /* make sure all cases are covered explicitly */
8785
14.4M
      XP_ERROR(XPATH_EXPR_ERROR);
8786
0
  }
8787
16.1M
    }
8788
8789
8.48M
    if (lc) {
8790
8.18M
  if (CUR == '/') {
8791
171k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8792
8.01M
  } else {
8793
8.01M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8794
8.01M
  }
8795
8.18M
  xmlXPathCompLocationPath(ctxt);
8796
8.18M
    } else {
8797
299k
  xmlXPathCompFilterExpr(ctxt);
8798
299k
  CHECK_ERROR;
8799
272k
  if ((CUR == '/') && (NXT(1) == '/')) {
8800
4.23k
      SKIP(2);
8801
4.23k
      SKIP_BLANKS;
8802
8803
4.23k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8804
4.23k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8805
8806
4.23k
      xmlXPathCompRelativeLocationPath(ctxt);
8807
268k
  } else if (CUR == '/') {
8808
7.31k
      xmlXPathCompRelativeLocationPath(ctxt);
8809
7.31k
  }
8810
272k
    }
8811
8.45M
    SKIP_BLANKS;
8812
8.45M
}
8813
8814
/**
8815
 *  [18]   UnionExpr ::=   PathExpr
8816
 *               | UnionExpr '|' PathExpr
8817
 *
8818
 * Compile an union expression.
8819
 *
8820
 * @param ctxt  the XPath Parser context
8821
 */
8822
8823
static void
8824
8.30M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8825
8.30M
    xmlXPathCompPathExpr(ctxt);
8826
8.30M
    CHECK_ERROR;
8827
8.28M
    SKIP_BLANKS;
8828
22.8M
    while (CUR == '|') {
8829
14.6M
  int op1 = ctxt->comp->last;
8830
14.6M
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8831
8832
14.6M
  NEXT;
8833
14.6M
  SKIP_BLANKS;
8834
14.6M
  xmlXPathCompPathExpr(ctxt);
8835
8836
14.6M
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8837
8838
14.6M
  SKIP_BLANKS;
8839
14.6M
    }
8840
8.28M
}
8841
8842
/**
8843
 *  [27]   UnaryExpr ::=   UnionExpr
8844
 *                   | '-' UnaryExpr
8845
 *
8846
 * Compile an unary expression.
8847
 *
8848
 * @param ctxt  the XPath Parser context
8849
 */
8850
8851
static void
8852
8.30M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8853
8.30M
    int minus = 0;
8854
8.30M
    int found = 0;
8855
8856
8.30M
    SKIP_BLANKS;
8857
8.90M
    while (CUR == '-') {
8858
600k
        minus = 1 - minus;
8859
600k
  found = 1;
8860
600k
  NEXT;
8861
600k
  SKIP_BLANKS;
8862
600k
    }
8863
8864
8.30M
    xmlXPathCompUnionExpr(ctxt);
8865
8.30M
    CHECK_ERROR;
8866
8.27M
    if (found) {
8867
220k
  if (minus)
8868
139k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8869
80.7k
  else
8870
80.7k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8871
220k
    }
8872
8.27M
}
8873
8874
/**
8875
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
8876
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
8877
 *                   | MultiplicativeExpr 'div' UnaryExpr
8878
 *                   | MultiplicativeExpr 'mod' UnaryExpr
8879
 *  [34]   MultiplyOperator ::=   '*'
8880
 *
8881
 * Compile an Additive expression.
8882
 *
8883
 * @param ctxt  the XPath Parser context
8884
 */
8885
8886
static void
8887
2.07M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8888
2.07M
    xmlXPathCompUnaryExpr(ctxt);
8889
2.07M
    CHECK_ERROR;
8890
2.05M
    SKIP_BLANKS;
8891
8.27M
    while ((CUR == '*') ||
8892
8.27M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8893
8.27M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8894
6.23M
  int op = -1;
8895
6.23M
  int op1 = ctxt->comp->last;
8896
8897
6.23M
        if (CUR == '*') {
8898
6.22M
      op = 0;
8899
6.22M
      NEXT;
8900
6.22M
  } else if (CUR == 'd') {
8901
2.28k
      op = 1;
8902
2.28k
      SKIP(3);
8903
2.28k
  } else if (CUR == 'm') {
8904
1.25k
      op = 2;
8905
1.25k
      SKIP(3);
8906
1.25k
  }
8907
6.23M
  SKIP_BLANKS;
8908
6.23M
        xmlXPathCompUnaryExpr(ctxt);
8909
6.23M
  CHECK_ERROR;
8910
6.22M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8911
6.22M
  SKIP_BLANKS;
8912
6.22M
    }
8913
2.05M
}
8914
8915
/**
8916
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
8917
 *                   | AdditiveExpr '+' MultiplicativeExpr
8918
 *                   | AdditiveExpr '-' MultiplicativeExpr
8919
 *
8920
 * Compile an Additive expression.
8921
 *
8922
 * @param ctxt  the XPath Parser context
8923
 */
8924
8925
static void
8926
1.86M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8927
8928
1.86M
    xmlXPathCompMultiplicativeExpr(ctxt);
8929
1.86M
    CHECK_ERROR;
8930
1.83M
    SKIP_BLANKS;
8931
2.04M
    while ((CUR == '+') || (CUR == '-')) {
8932
213k
  int plus;
8933
213k
  int op1 = ctxt->comp->last;
8934
8935
213k
        if (CUR == '+') plus = 1;
8936
190k
  else plus = 0;
8937
213k
  NEXT;
8938
213k
  SKIP_BLANKS;
8939
213k
        xmlXPathCompMultiplicativeExpr(ctxt);
8940
213k
  CHECK_ERROR;
8941
210k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8942
210k
  SKIP_BLANKS;
8943
210k
    }
8944
1.83M
}
8945
8946
/**
8947
 *  [24]   RelationalExpr ::=   AdditiveExpr
8948
 *                 | RelationalExpr '<' AdditiveExpr
8949
 *                 | RelationalExpr '>' AdditiveExpr
8950
 *                 | RelationalExpr '<=' AdditiveExpr
8951
 *                 | RelationalExpr '>=' AdditiveExpr
8952
 *
8953
 *  A <= B > C is allowed ? Answer from James, yes with
8954
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8955
 *  which is basically what got implemented.
8956
 *
8957
 * Compile a Relational expression, then push the result
8958
 * on the stack
8959
 *
8960
 * @param ctxt  the XPath Parser context
8961
 */
8962
8963
static void
8964
1.70M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8965
1.70M
    xmlXPathCompAdditiveExpr(ctxt);
8966
1.70M
    CHECK_ERROR;
8967
1.68M
    SKIP_BLANKS;
8968
1.83M
    while ((CUR == '<') || (CUR == '>')) {
8969
153k
  int inf, strict;
8970
153k
  int op1 = ctxt->comp->last;
8971
8972
153k
        if (CUR == '<') inf = 1;
8973
128k
  else inf = 0;
8974
153k
  if (NXT(1) == '=') strict = 0;
8975
121k
  else strict = 1;
8976
153k
  NEXT;
8977
153k
  if (!strict) NEXT;
8978
153k
  SKIP_BLANKS;
8979
153k
        xmlXPathCompAdditiveExpr(ctxt);
8980
153k
  CHECK_ERROR;
8981
150k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
8982
150k
  SKIP_BLANKS;
8983
150k
    }
8984
1.68M
}
8985
8986
/**
8987
 *  [23]   EqualityExpr ::=   RelationalExpr
8988
 *                 | EqualityExpr '=' RelationalExpr
8989
 *                 | EqualityExpr '!=' RelationalExpr
8990
 *
8991
 *  A != B != C is allowed ? Answer from James, yes with
8992
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
8993
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
8994
 *  which is basically what got implemented.
8995
 *
8996
 * Compile an Equality expression.
8997
 *
8998
 * @param ctxt  the XPath Parser context
8999
 */
9000
static void
9001
1.59M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9002
1.59M
    xmlXPathCompRelationalExpr(ctxt);
9003
1.59M
    CHECK_ERROR;
9004
1.57M
    SKIP_BLANKS;
9005
1.68M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9006
111k
  int eq;
9007
111k
  int op1 = ctxt->comp->last;
9008
9009
111k
        if (CUR == '=') eq = 1;
9010
13.5k
  else eq = 0;
9011
111k
  NEXT;
9012
111k
  if (!eq) NEXT;
9013
111k
  SKIP_BLANKS;
9014
111k
        xmlXPathCompRelationalExpr(ctxt);
9015
111k
  CHECK_ERROR;
9016
107k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9017
107k
  SKIP_BLANKS;
9018
107k
    }
9019
1.57M
}
9020
9021
/**
9022
 *  [22]   AndExpr ::=   EqualityExpr
9023
 *                 | AndExpr 'and' EqualityExpr
9024
 *
9025
 * Compile an AND expression.
9026
 *
9027
 * @param ctxt  the XPath Parser context
9028
 */
9029
static void
9030
1.59M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9031
1.59M
    xmlXPathCompEqualityExpr(ctxt);
9032
1.59M
    CHECK_ERROR;
9033
1.56M
    SKIP_BLANKS;
9034
1.57M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9035
2.74k
  int op1 = ctxt->comp->last;
9036
2.74k
        SKIP(3);
9037
2.74k
  SKIP_BLANKS;
9038
2.74k
        xmlXPathCompEqualityExpr(ctxt);
9039
2.74k
  CHECK_ERROR;
9040
2.46k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9041
2.46k
  SKIP_BLANKS;
9042
2.46k
    }
9043
1.56M
}
9044
9045
/**
9046
 *  [14]   Expr ::=   OrExpr
9047
 *  [21]   OrExpr ::=   AndExpr
9048
 *                 | OrExpr 'or' AndExpr
9049
 *
9050
 * Parse and compile an expression
9051
 *
9052
 * @param ctxt  the XPath Parser context
9053
 * @param sort  whether to sort the resulting node set
9054
 */
9055
static void
9056
1.58M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9057
1.58M
    xmlXPathContextPtr xpctxt = ctxt->context;
9058
9059
1.58M
    if (xpctxt != NULL) {
9060
1.58M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9061
1.58M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9062
        /*
9063
         * Parsing a single '(' pushes about 10 functions on the call stack
9064
         * before recursing!
9065
         */
9066
1.58M
        xpctxt->depth += 10;
9067
1.58M
    }
9068
9069
1.58M
    xmlXPathCompAndExpr(ctxt);
9070
1.58M
    CHECK_ERROR;
9071
1.56M
    SKIP_BLANKS;
9072
1.56M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9073
7.82k
  int op1 = ctxt->comp->last;
9074
7.82k
        SKIP(2);
9075
7.82k
  SKIP_BLANKS;
9076
7.82k
        xmlXPathCompAndExpr(ctxt);
9077
7.82k
  CHECK_ERROR;
9078
6.82k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9079
6.82k
  SKIP_BLANKS;
9080
6.82k
    }
9081
1.56M
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9082
  /* more ops could be optimized too */
9083
  /*
9084
  * This is the main place to eliminate sorting for
9085
  * operations which don't require a sorted node-set.
9086
  * E.g. count().
9087
  */
9088
1.49M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9089
1.49M
    }
9090
9091
1.56M
    if (xpctxt != NULL)
9092
1.56M
        xpctxt->depth -= 10;
9093
1.56M
}
9094
9095
/**
9096
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
9097
 *  [9]   PredicateExpr ::=   Expr
9098
 *
9099
 * Compile a predicate expression
9100
 *
9101
 * @param ctxt  the XPath Parser context
9102
 * @param filter  act as a filter
9103
 */
9104
static void
9105
81.0k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9106
81.0k
    int op1 = ctxt->comp->last;
9107
9108
81.0k
    SKIP_BLANKS;
9109
81.0k
    if (CUR != '[') {
9110
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9111
0
    }
9112
81.0k
    NEXT;
9113
81.0k
    SKIP_BLANKS;
9114
9115
81.0k
    ctxt->comp->last = -1;
9116
    /*
9117
    * This call to xmlXPathCompileExpr() will deactivate sorting
9118
    * of the predicate result.
9119
    * TODO: Sorting is still activated for filters, since I'm not
9120
    *  sure if needed. Normally sorting should not be needed, since
9121
    *  a filter can only diminish the number of items in a sequence,
9122
    *  but won't change its order; so if the initial sequence is sorted,
9123
    *  subsequent sorting is not needed.
9124
    */
9125
81.0k
    if (! filter)
9126
46.4k
  xmlXPathCompileExpr(ctxt, 0);
9127
34.5k
    else
9128
34.5k
  xmlXPathCompileExpr(ctxt, 1);
9129
81.0k
    CHECK_ERROR;
9130
9131
67.2k
    if (CUR != ']') {
9132
800
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9133
0
    }
9134
9135
66.4k
    if (filter)
9136
30.9k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9137
35.4k
    else
9138
35.4k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9139
9140
66.4k
    NEXT;
9141
66.4k
    SKIP_BLANKS;
9142
66.4k
}
9143
9144
/**
9145
 * ```
9146
 * [7] NodeTest ::=   NameTest
9147
 *        | NodeType '(' ')'
9148
 *        | 'processing-instruction' '(' Literal ')'
9149
 *
9150
 * [37] NameTest ::=  '*'
9151
 *        | NCName ':' '*'
9152
 *        | QName
9153
 * [38] NodeType ::= 'comment'
9154
 *       | 'text'
9155
 *       | 'processing-instruction'
9156
 *       | 'node'
9157
 * ```
9158
 *
9159
 * @param ctxt  the XPath Parser context
9160
 * @param test  pointer to a xmlXPathTestVal
9161
 * @param type  pointer to a xmlXPathTypeVal
9162
 * @param prefix  placeholder for a possible name prefix
9163
 * @param name  current name token (optional)
9164
 * @returns the name found and updates `test`, `type` and `prefix` appropriately
9165
 */
9166
static xmlChar *
9167
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9168
               xmlXPathTypeVal *type, xmlChar **prefix,
9169
8.61M
         xmlChar *name) {
9170
8.61M
    int blanks;
9171
9172
8.61M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9173
0
  return(NULL);
9174
0
    }
9175
8.61M
    *type = (xmlXPathTypeVal) 0;
9176
8.61M
    *test = (xmlXPathTestVal) 0;
9177
8.61M
    *prefix = NULL;
9178
8.61M
    SKIP_BLANKS;
9179
9180
8.61M
    if ((name == NULL) && (CUR == '*')) {
9181
  /*
9182
   * All elements
9183
   */
9184
6.40M
  NEXT;
9185
6.40M
  *test = NODE_TEST_ALL;
9186
6.40M
  return(NULL);
9187
6.40M
    }
9188
9189
2.20M
    if (name == NULL)
9190
27.5k
  name = xmlXPathParseNCName(ctxt);
9191
2.20M
    if (name == NULL) {
9192
1.45k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9193
0
    }
9194
9195
2.20M
    blanks = IS_BLANK_CH(CUR);
9196
2.20M
    SKIP_BLANKS;
9197
2.20M
    if (CUR == '(') {
9198
15.2k
  NEXT;
9199
  /*
9200
   * NodeType or PI search
9201
   */
9202
15.2k
  if (xmlStrEqual(name, BAD_CAST "comment"))
9203
866
      *type = NODE_TYPE_COMMENT;
9204
14.3k
  else if (xmlStrEqual(name, BAD_CAST "node"))
9205
10.6k
      *type = NODE_TYPE_NODE;
9206
3.74k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9207
1.16k
      *type = NODE_TYPE_PI;
9208
2.57k
  else if (xmlStrEqual(name, BAD_CAST "text"))
9209
2.35k
      *type = NODE_TYPE_TEXT;
9210
226
  else {
9211
226
      if (name != NULL)
9212
226
    xmlFree(name);
9213
226
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9214
0
  }
9215
9216
15.0k
  *test = NODE_TEST_TYPE;
9217
9218
15.0k
  SKIP_BLANKS;
9219
15.0k
  if (*type == NODE_TYPE_PI) {
9220
      /*
9221
       * Specific case: search a PI by name.
9222
       */
9223
1.16k
      if (name != NULL)
9224
1.16k
    xmlFree(name);
9225
1.16k
      name = NULL;
9226
1.16k
      if (CUR != ')') {
9227
615
    name = xmlXPathParseLiteral(ctxt);
9228
615
    *test = NODE_TEST_PI;
9229
615
    SKIP_BLANKS;
9230
615
      }
9231
1.16k
  }
9232
15.0k
  if (CUR != ')') {
9233
359
      if (name != NULL)
9234
269
    xmlFree(name);
9235
359
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9236
0
  }
9237
14.6k
  NEXT;
9238
14.6k
  return(name);
9239
15.0k
    }
9240
2.19M
    *test = NODE_TEST_NAME;
9241
2.19M
    if ((!blanks) && (CUR == ':')) {
9242
26.6k
  NEXT;
9243
9244
  /*
9245
   * Since currently the parser context don't have a
9246
   * namespace list associated:
9247
   * The namespace name for this prefix can be computed
9248
   * only at evaluation time. The compilation is done
9249
   * outside of any context.
9250
   */
9251
26.6k
  *prefix = name;
9252
9253
26.6k
  if (CUR == '*') {
9254
      /*
9255
       * All elements
9256
       */
9257
1.89k
      NEXT;
9258
1.89k
      *test = NODE_TEST_ALL;
9259
1.89k
      return(NULL);
9260
1.89k
  }
9261
9262
24.7k
  name = xmlXPathParseNCName(ctxt);
9263
24.7k
  if (name == NULL) {
9264
313
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9265
0
  }
9266
24.7k
    }
9267
2.18M
    return(name);
9268
2.19M
}
9269
9270
/**
9271
 * [6] AxisName ::=   'ancestor'
9272
 *                  | 'ancestor-or-self'
9273
 *                  | 'attribute'
9274
 *                  | 'child'
9275
 *                  | 'descendant'
9276
 *                  | 'descendant-or-self'
9277
 *                  | 'following'
9278
 *                  | 'following-sibling'
9279
 *                  | 'namespace'
9280
 *                  | 'parent'
9281
 *                  | 'preceding'
9282
 *                  | 'preceding-sibling'
9283
 *                  | 'self'
9284
 *
9285
 * @param name  a preparsed name token
9286
 * @returns the axis or 0
9287
 */
9288
static xmlXPathAxisVal
9289
2.21M
xmlXPathIsAxisName(const xmlChar *name) {
9290
2.21M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9291
2.21M
    switch (name[0]) {
9292
67.0k
  case 'a':
9293
67.0k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9294
2.94k
    ret = AXIS_ANCESTOR;
9295
67.0k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9296
1.70k
    ret = AXIS_ANCESTOR_OR_SELF;
9297
67.0k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9298
1.28k
    ret = AXIS_ATTRIBUTE;
9299
67.0k
      break;
9300
371k
  case 'c':
9301
371k
      if (xmlStrEqual(name, BAD_CAST "child"))
9302
976
    ret = AXIS_CHILD;
9303
371k
      break;
9304
13.1k
  case 'd':
9305
13.1k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9306
6.05k
    ret = AXIS_DESCENDANT;
9307
13.1k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9308
1.41k
    ret = AXIS_DESCENDANT_OR_SELF;
9309
13.1k
      break;
9310
17.9k
  case 'f':
9311
17.9k
      if (xmlStrEqual(name, BAD_CAST "following"))
9312
6.29k
    ret = AXIS_FOLLOWING;
9313
17.9k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9314
496
    ret = AXIS_FOLLOWING_SIBLING;
9315
17.9k
      break;
9316
59.2k
  case 'n':
9317
59.2k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9318
2.52k
    ret = AXIS_NAMESPACE;
9319
59.2k
      break;
9320
42.2k
  case 'p':
9321
42.2k
      if (xmlStrEqual(name, BAD_CAST "parent"))
9322
981
    ret = AXIS_PARENT;
9323
42.2k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9324
1.25k
    ret = AXIS_PRECEDING;
9325
42.2k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9326
3.31k
    ret = AXIS_PRECEDING_SIBLING;
9327
42.2k
      break;
9328
12.6k
  case 's':
9329
12.6k
      if (xmlStrEqual(name, BAD_CAST "self"))
9330
3.37k
    ret = AXIS_SELF;
9331
12.6k
      break;
9332
2.21M
    }
9333
2.21M
    return(ret);
9334
2.21M
}
9335
9336
/**
9337
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
9338
 *                  | AbbreviatedStep
9339
 *
9340
 * [12] AbbreviatedStep ::=   '.' | '..'
9341
 *
9342
 * [5] AxisSpecifier ::= AxisName '::'
9343
 *                  | AbbreviatedAxisSpecifier
9344
 *
9345
 * [13] AbbreviatedAxisSpecifier ::= '@'?
9346
 *
9347
 * Modified for XPtr range support as:
9348
 *
9349
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9350
 *                     | AbbreviatedStep
9351
 *                     | 'range-to' '(' Expr ')' Predicate*
9352
 *
9353
 * Compile one step in a Location Path
9354
 *
9355
 * @param ctxt  the XPath Parser context
9356
 */
9357
static void
9358
9.04M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9359
9.04M
    SKIP_BLANKS;
9360
9.04M
    if ((CUR == '.') && (NXT(1) == '.')) {
9361
13.7k
  SKIP(2);
9362
13.7k
  SKIP_BLANKS;
9363
13.7k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9364
13.7k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9365
9.02M
    } else if (CUR == '.') {
9366
388k
  NEXT;
9367
388k
  SKIP_BLANKS;
9368
8.63M
    } else {
9369
8.63M
  xmlChar *name = NULL;
9370
8.63M
  xmlChar *prefix = NULL;
9371
8.63M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9372
8.63M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9373
8.63M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9374
8.63M
  int op1;
9375
9376
8.63M
  if (CUR == '*') {
9377
6.39M
      axis = AXIS_CHILD;
9378
6.39M
  } else {
9379
2.24M
      if (name == NULL)
9380
2.24M
    name = xmlXPathParseNCName(ctxt);
9381
2.24M
      if (name != NULL) {
9382
2.21M
    axis = xmlXPathIsAxisName(name);
9383
2.21M
    if (axis != 0) {
9384
32.6k
        SKIP_BLANKS;
9385
32.6k
        if ((CUR == ':') && (NXT(1) == ':')) {
9386
19.0k
      SKIP(2);
9387
19.0k
      xmlFree(name);
9388
19.0k
      name = NULL;
9389
19.0k
        } else {
9390
      /* an element name can conflict with an axis one :-\ */
9391
13.5k
      axis = AXIS_CHILD;
9392
13.5k
        }
9393
2.18M
    } else {
9394
2.18M
        axis = AXIS_CHILD;
9395
2.18M
    }
9396
2.21M
      } else if (CUR == '@') {
9397
17.8k
    NEXT;
9398
17.8k
    axis = AXIS_ATTRIBUTE;
9399
17.8k
      } else {
9400
3.46k
    axis = AXIS_CHILD;
9401
3.46k
      }
9402
2.24M
  }
9403
9404
8.63M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9405
22.4k
            xmlFree(name);
9406
22.4k
            return;
9407
22.4k
        }
9408
9409
8.61M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9410
8.61M
  if (test == 0)
9411
1.68k
      return;
9412
9413
8.61M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9414
8.61M
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9415
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9416
0
    xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9417
0
                               "Undefined namespace prefix: %s\n", prefix);
9418
0
      }
9419
0
  }
9420
9421
8.61M
  op1 = ctxt->comp->last;
9422
8.61M
  ctxt->comp->last = -1;
9423
9424
8.61M
  SKIP_BLANKS;
9425
8.66M
  while (CUR == '[') {
9426
46.4k
      xmlXPathCompPredicate(ctxt, 0);
9427
46.4k
  }
9428
9429
8.61M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9430
8.61M
                           test, type, (void *)prefix, (void *)name) == -1) {
9431
119
            xmlFree(prefix);
9432
119
            xmlFree(name);
9433
119
        }
9434
8.61M
    }
9435
9.04M
}
9436
9437
/**
9438
 *  [3]   RelativeLocationPath ::=   Step
9439
 *                     | RelativeLocationPath '/' Step
9440
 *                     | AbbreviatedRelativeLocationPath
9441
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
9442
 *
9443
 * Compile a relative location path.
9444
 *
9445
 * @param ctxt  the XPath Parser context
9446
 */
9447
static void
9448
xmlXPathCompRelativeLocationPath
9449
8.17M
(xmlXPathParserContextPtr ctxt) {
9450
8.17M
    SKIP_BLANKS;
9451
8.17M
    if ((CUR == '/') && (NXT(1) == '/')) {
9452
7.28k
  SKIP(2);
9453
7.28k
  SKIP_BLANKS;
9454
7.28k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9455
7.28k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9456
8.16M
    } else if (CUR == '/') {
9457
18.7k
      NEXT;
9458
18.7k
  SKIP_BLANKS;
9459
18.7k
    }
9460
8.17M
    xmlXPathCompStep(ctxt);
9461
8.17M
    CHECK_ERROR;
9462
8.14M
    SKIP_BLANKS;
9463
9.01M
    while (CUR == '/') {
9464
870k
  if ((CUR == '/') && (NXT(1) == '/')) {
9465
93.1k
      SKIP(2);
9466
93.1k
      SKIP_BLANKS;
9467
93.1k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9468
93.1k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9469
93.1k
      xmlXPathCompStep(ctxt);
9470
776k
  } else if (CUR == '/') {
9471
776k
      NEXT;
9472
776k
      SKIP_BLANKS;
9473
776k
      xmlXPathCompStep(ctxt);
9474
776k
  }
9475
870k
  SKIP_BLANKS;
9476
870k
    }
9477
8.14M
}
9478
9479
/**
9480
 *  [1]   LocationPath ::=   RelativeLocationPath
9481
 *                     | AbsoluteLocationPath
9482
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
9483
 *                     | AbbreviatedAbsoluteLocationPath
9484
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
9485
 *                           '//' RelativeLocationPath
9486
 *
9487
 * Compile a location path
9488
 *
9489
 * @param ctxt  the XPath Parser context
9490
 */
9491
static void
9492
8.18M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9493
8.18M
    SKIP_BLANKS;
9494
8.18M
    if (CUR != '/') {
9495
8.01M
        xmlXPathCompRelativeLocationPath(ctxt);
9496
8.01M
    } else {
9497
344k
  while (CUR == '/') {
9498
177k
      if ((CUR == '/') && (NXT(1) == '/')) {
9499
66.3k
    SKIP(2);
9500
66.3k
    SKIP_BLANKS;
9501
66.3k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9502
66.3k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9503
66.3k
    xmlXPathCompRelativeLocationPath(ctxt);
9504
110k
      } else if (CUR == '/') {
9505
110k
    NEXT;
9506
110k
    SKIP_BLANKS;
9507
110k
    if ((CUR != 0) &&
9508
110k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9509
109k
                     (CUR == '_') || (CUR == '.') ||
9510
109k
         (CUR == '@') || (CUR == '*')))
9511
80.1k
        xmlXPathCompRelativeLocationPath(ctxt);
9512
110k
      }
9513
177k
      CHECK_ERROR;
9514
177k
  }
9515
171k
    }
9516
8.18M
}
9517
9518
/************************************************************************
9519
 *                  *
9520
 *    XPath precompiled expression evaluation     *
9521
 *                  *
9522
 ************************************************************************/
9523
9524
static int
9525
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9526
9527
/**
9528
 * Filter a node set, keeping only nodes for which the predicate expression
9529
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
9530
 * filtered result.
9531
 *
9532
 * @param ctxt  the XPath Parser context
9533
 * @param set  the node set to filter
9534
 * @param filterOpIndex  the index of the predicate/filter op
9535
 * @param minPos  minimum position in the filtered set (1-based)
9536
 * @param maxPos  maximum position in the filtered set (1-based)
9537
 * @param hasNsNodes  true if the node set may contain namespace nodes
9538
 */
9539
static void
9540
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
9541
          xmlNodeSetPtr set,
9542
          int filterOpIndex,
9543
                      int minPos, int maxPos,
9544
          int hasNsNodes)
9545
804k
{
9546
804k
    xmlXPathContextPtr xpctxt;
9547
804k
    xmlNodePtr oldnode;
9548
804k
    xmlDocPtr olddoc;
9549
804k
    xmlXPathStepOpPtr filterOp;
9550
804k
    int oldcs, oldpp;
9551
804k
    int i, j, pos;
9552
9553
804k
    if ((set == NULL) || (set->nodeNr == 0))
9554
81.8k
        return;
9555
9556
    /*
9557
    * Check if the node set contains a sufficient number of nodes for
9558
    * the requested range.
9559
    */
9560
722k
    if (set->nodeNr < minPos) {
9561
4.12k
        xmlXPathNodeSetClear(set, hasNsNodes);
9562
4.12k
        return;
9563
4.12k
    }
9564
9565
718k
    xpctxt = ctxt->context;
9566
718k
    oldnode = xpctxt->node;
9567
718k
    olddoc = xpctxt->doc;
9568
718k
    oldcs = xpctxt->contextSize;
9569
718k
    oldpp = xpctxt->proximityPosition;
9570
718k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9571
9572
718k
    xpctxt->contextSize = set->nodeNr;
9573
9574
3.94M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9575
3.56M
        xmlNodePtr node = set->nodeTab[i];
9576
3.56M
        int res;
9577
9578
3.56M
        xpctxt->node = node;
9579
3.56M
        xpctxt->proximityPosition = i + 1;
9580
9581
        /*
9582
        * Also set the xpath document in case things like
9583
        * key() are evaluated in the predicate.
9584
        *
9585
        * TODO: Get real doc for namespace nodes.
9586
        */
9587
3.56M
        if ((node->type != XML_NAMESPACE_DECL) &&
9588
3.56M
            (node->doc != NULL))
9589
3.31M
            xpctxt->doc = node->doc;
9590
9591
3.56M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9592
9593
3.56M
        if (ctxt->error != XPATH_EXPRESSION_OK)
9594
4.19k
            break;
9595
3.56M
        if (res < 0) {
9596
            /* Shouldn't happen */
9597
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9598
0
            break;
9599
0
        }
9600
9601
3.56M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9602
1.88M
            if (i != j) {
9603
28.9k
                set->nodeTab[j] = node;
9604
28.9k
                set->nodeTab[i] = NULL;
9605
28.9k
            }
9606
9607
1.88M
            j += 1;
9608
1.88M
        } else {
9609
            /* Remove the entry from the initial node set. */
9610
1.67M
            set->nodeTab[i] = NULL;
9611
1.67M
            if (node->type == XML_NAMESPACE_DECL)
9612
129k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9613
1.67M
        }
9614
9615
3.56M
        if (res != 0) {
9616
1.93M
            if (pos == maxPos) {
9617
332k
                i += 1;
9618
332k
                break;
9619
332k
            }
9620
9621
1.60M
            pos += 1;
9622
1.60M
        }
9623
3.56M
    }
9624
9625
    /* Free remaining nodes. */
9626
718k
    if (hasNsNodes) {
9627
320k
        for (; i < set->nodeNr; i++) {
9628
149k
            xmlNodePtr node = set->nodeTab[i];
9629
149k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9630
21.0k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9631
149k
        }
9632
171k
    }
9633
9634
718k
    set->nodeNr = j;
9635
9636
    /* If too many elements were removed, shrink table to preserve memory. */
9637
718k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9638
718k
        (set->nodeNr < set->nodeMax / 2)) {
9639
56.9k
        xmlNodePtr *tmp;
9640
56.9k
        int nodeMax = set->nodeNr;
9641
9642
56.9k
        if (nodeMax < XML_NODESET_DEFAULT)
9643
52.6k
            nodeMax = XML_NODESET_DEFAULT;
9644
56.9k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9645
56.9k
                nodeMax * sizeof(xmlNodePtr));
9646
56.9k
        if (tmp == NULL) {
9647
4
            xmlXPathPErrMemory(ctxt);
9648
56.9k
        } else {
9649
56.9k
            set->nodeTab = tmp;
9650
56.9k
            set->nodeMax = nodeMax;
9651
56.9k
        }
9652
56.9k
    }
9653
9654
718k
    xpctxt->node = oldnode;
9655
718k
    xpctxt->doc = olddoc;
9656
718k
    xpctxt->contextSize = oldcs;
9657
718k
    xpctxt->proximityPosition = oldpp;
9658
718k
}
9659
9660
/**
9661
 * Filter a node set, keeping only nodes for which the sequence of predicate
9662
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
9663
 * in the filtered result.
9664
 *
9665
 * @param ctxt  the XPath Parser context
9666
 * @param op  the predicate op
9667
 * @param set  the node set to filter
9668
 * @param minPos  minimum position in the filtered set (1-based)
9669
 * @param maxPos  maximum position in the filtered set (1-based)
9670
 * @param hasNsNodes  true if the node set may contain namespace nodes
9671
 */
9672
static void
9673
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
9674
          xmlXPathStepOpPtr op,
9675
          xmlNodeSetPtr set,
9676
                            int minPos, int maxPos,
9677
          int hasNsNodes)
9678
573k
{
9679
573k
    if (op->ch1 != -1) {
9680
15.0k
  xmlXPathCompExprPtr comp = ctxt->comp;
9681
  /*
9682
  * Process inner predicates first.
9683
  */
9684
15.0k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9685
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9686
0
  }
9687
15.0k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9688
15.0k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9689
15.0k
        ctxt->context->depth += 1;
9690
15.0k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9691
15.0k
                                    1, set->nodeNr, hasNsNodes);
9692
15.0k
        ctxt->context->depth -= 1;
9693
15.0k
  CHECK_ERROR;
9694
15.0k
    }
9695
9696
570k
    if (op->ch2 != -1)
9697
570k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9698
570k
}
9699
9700
static int
9701
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9702
          xmlXPathStepOpPtr op,
9703
          int *maxPos)
9704
206k
{
9705
9706
206k
    xmlXPathStepOpPtr exprOp;
9707
9708
    /*
9709
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
9710
    */
9711
9712
    /*
9713
    * If not -1, then ch1 will point to:
9714
    * 1) For predicates (XPATH_OP_PREDICATE):
9715
    *    - an inner predicate operator
9716
    * 2) For filters (XPATH_OP_FILTER):
9717
    *    - an inner filter operator OR
9718
    *    - an expression selecting the node set.
9719
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
9720
    */
9721
206k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9722
0
  return(0);
9723
9724
206k
    if (op->ch2 != -1) {
9725
206k
  exprOp = &ctxt->comp->steps[op->ch2];
9726
206k
    } else
9727
0
  return(0);
9728
9729
206k
    if ((exprOp != NULL) &&
9730
206k
  (exprOp->op == XPATH_OP_VALUE) &&
9731
206k
  (exprOp->value4 != NULL) &&
9732
206k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9733
44.0k
    {
9734
44.0k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
9735
9736
  /*
9737
  * We have a "[n]" predicate here.
9738
  * TODO: Unfortunately this simplistic test here is not
9739
  * able to detect a position() predicate in compound
9740
  * expressions like "[@attr = 'a" and position() = 1],
9741
  * and even not the usage of position() in
9742
  * "[position() = 1]"; thus - obviously - a position-range,
9743
  * like it "[position() < 5]", is also not detected.
9744
  * Maybe we could rewrite the AST to ease the optimization.
9745
  */
9746
9747
44.0k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9748
42.0k
      *maxPos = (int) floatval;
9749
42.0k
            if (floatval == (double) *maxPos)
9750
39.5k
                return(1);
9751
42.0k
        }
9752
44.0k
    }
9753
167k
    return(0);
9754
206k
}
9755
9756
static int
9757
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9758
                           xmlXPathStepOpPtr op,
9759
         xmlNodePtr * first, xmlNodePtr * last,
9760
         int toBool)
9761
3.01M
{
9762
9763
3.01M
#define XP_TEST_HIT \
9764
46.0M
    if (hasAxisRange != 0) { \
9765
255k
  if (++pos == maxPos) { \
9766
24.7k
      if (addNode(seq, cur) < 0) \
9767
24.7k
          xmlXPathPErrMemory(ctxt); \
9768
24.7k
      goto axis_range_end; } \
9769
45.8M
    } else { \
9770
45.8M
  if (addNode(seq, cur) < 0) \
9771
45.8M
      xmlXPathPErrMemory(ctxt); \
9772
45.8M
  if (breakOnFirstHit) goto first_hit; }
9773
9774
3.01M
#define XP_TEST_HIT_NS \
9775
3.01M
    if (hasAxisRange != 0) { \
9776
15.7k
  if (++pos == maxPos) { \
9777
5.43k
      hasNsNodes = 1; \
9778
5.43k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9779
5.43k
          xmlXPathPErrMemory(ctxt); \
9780
5.43k
  goto axis_range_end; } \
9781
870k
    } else { \
9782
870k
  hasNsNodes = 1; \
9783
870k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9784
870k
      xmlXPathPErrMemory(ctxt); \
9785
870k
  if (breakOnFirstHit) goto first_hit; }
9786
9787
3.01M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9788
3.01M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9789
3.01M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9790
3.01M
    const xmlChar *prefix = op->value4;
9791
3.01M
    const xmlChar *name = op->value5;
9792
3.01M
    const xmlChar *URI = NULL;
9793
9794
3.01M
    int total = 0, hasNsNodes = 0;
9795
    /* The popped object holding the context nodes */
9796
3.01M
    xmlXPathObjectPtr obj;
9797
    /* The set of context nodes for the node tests */
9798
3.01M
    xmlNodeSetPtr contextSeq;
9799
3.01M
    int contextIdx;
9800
3.01M
    xmlNodePtr contextNode;
9801
    /* The final resulting node set wrt to all context nodes */
9802
3.01M
    xmlNodeSetPtr outSeq;
9803
    /*
9804
    * The temporary resulting node set wrt 1 context node.
9805
    * Used to feed predicate evaluation.
9806
    */
9807
3.01M
    xmlNodeSetPtr seq;
9808
3.01M
    xmlNodePtr cur;
9809
    /* First predicate operator */
9810
3.01M
    xmlXPathStepOpPtr predOp;
9811
3.01M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9812
3.01M
    int hasPredicateRange, hasAxisRange, pos;
9813
3.01M
    int breakOnFirstHit;
9814
9815
3.01M
    xmlXPathTraversalFunction next = NULL;
9816
3.01M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9817
3.01M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9818
3.01M
    xmlNodePtr oldContextNode;
9819
3.01M
    xmlXPathContextPtr xpctxt = ctxt->context;
9820
9821
9822
3.01M
    CHECK_TYPE0(XPATH_NODESET);
9823
3.01M
    obj = xmlXPathValuePop(ctxt);
9824
    /*
9825
    * Setup namespaces.
9826
    */
9827
3.01M
    if (prefix != NULL) {
9828
46.8k
        URI = xmlXPathNsLookup(xpctxt, prefix);
9829
46.8k
        if (URI == NULL) {
9830
545
      xmlXPathReleaseObject(xpctxt, obj);
9831
545
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9832
545
                           "Undefined namespace prefix: %s\n", prefix);
9833
545
            return 0;
9834
545
  }
9835
46.8k
    }
9836
    /*
9837
    * Setup axis.
9838
    *
9839
    * MAYBE FUTURE TODO: merging optimizations:
9840
    * - If the nodes to be traversed wrt to the initial nodes and
9841
    *   the current axis cannot overlap, then we could avoid searching
9842
    *   for duplicates during the merge.
9843
    *   But the question is how/when to evaluate if they cannot overlap.
9844
    *   Example: if we know that for two initial nodes, the one is
9845
    *   not in the ancestor-or-self axis of the other, then we could safely
9846
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
9847
    *   the descendant-or-self axis.
9848
    */
9849
3.01M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9850
3.01M
    switch (axis) {
9851
28.8k
        case AXIS_ANCESTOR:
9852
28.8k
            first = NULL;
9853
28.8k
            next = xmlXPathNextAncestor;
9854
28.8k
            break;
9855
7.18k
        case AXIS_ANCESTOR_OR_SELF:
9856
7.18k
            first = NULL;
9857
7.18k
            next = xmlXPathNextAncestorOrSelf;
9858
7.18k
            break;
9859
58.6k
        case AXIS_ATTRIBUTE:
9860
58.6k
            first = NULL;
9861
58.6k
      last = NULL;
9862
58.6k
            next = xmlXPathNextAttribute;
9863
58.6k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9864
58.6k
            break;
9865
2.29M
        case AXIS_CHILD:
9866
2.29M
      last = NULL;
9867
2.29M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9868
2.29M
    (type == NODE_TYPE_NODE))
9869
2.23M
      {
9870
    /*
9871
    * Optimization if an element node type is 'element'.
9872
    */
9873
2.23M
    next = xmlXPathNextChildElement;
9874
2.23M
      } else
9875
65.3k
    next = xmlXPathNextChild;
9876
2.29M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9877
2.29M
            break;
9878
70.8k
        case AXIS_DESCENDANT:
9879
70.8k
      last = NULL;
9880
70.8k
            next = xmlXPathNextDescendant;
9881
70.8k
            break;
9882
408k
        case AXIS_DESCENDANT_OR_SELF:
9883
408k
      last = NULL;
9884
408k
            next = xmlXPathNextDescendantOrSelf;
9885
408k
            break;
9886
4.06k
        case AXIS_FOLLOWING:
9887
4.06k
      last = NULL;
9888
4.06k
            next = xmlXPathNextFollowing;
9889
4.06k
            break;
9890
2.36k
        case AXIS_FOLLOWING_SIBLING:
9891
2.36k
      last = NULL;
9892
2.36k
            next = xmlXPathNextFollowingSibling;
9893
2.36k
            break;
9894
24.9k
        case AXIS_NAMESPACE:
9895
24.9k
            first = NULL;
9896
24.9k
      last = NULL;
9897
24.9k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9898
24.9k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9899
24.9k
            break;
9900
93.7k
        case AXIS_PARENT:
9901
93.7k
            first = NULL;
9902
93.7k
            next = xmlXPathNextParent;
9903
93.7k
            break;
9904
15.3k
        case AXIS_PRECEDING:
9905
15.3k
            first = NULL;
9906
15.3k
            next = xmlXPathNextPrecedingInternal;
9907
15.3k
            break;
9908
3.75k
        case AXIS_PRECEDING_SIBLING:
9909
3.75k
            first = NULL;
9910
3.75k
            next = xmlXPathNextPrecedingSibling;
9911
3.75k
            break;
9912
4.20k
        case AXIS_SELF:
9913
4.20k
            first = NULL;
9914
4.20k
      last = NULL;
9915
4.20k
            next = xmlXPathNextSelf;
9916
4.20k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9917
4.20k
            break;
9918
3.01M
    }
9919
9920
3.01M
    if (next == NULL) {
9921
0
  xmlXPathReleaseObject(xpctxt, obj);
9922
0
        return(0);
9923
0
    }
9924
3.01M
    contextSeq = obj->nodesetval;
9925
3.01M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9926
145k
        xmlXPathValuePush(ctxt, obj);
9927
145k
        return(0);
9928
145k
    }
9929
    /*
9930
    * Predicate optimization ---------------------------------------------
9931
    * If this step has a last predicate, which contains a position(),
9932
    * then we'll optimize (although not exactly "position()", but only
9933
    * the  short-hand form, i.e., "[n]".
9934
    *
9935
    * Example - expression "/foo[parent::bar][1]":
9936
    *
9937
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
9938
    *   ROOT                               -- op->ch1
9939
    *   PREDICATE                          -- op->ch2 (predOp)
9940
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
9941
    *       SORT
9942
    *         COLLECT  'parent' 'name' 'node' bar
9943
    *           NODE
9944
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
9945
    *
9946
    */
9947
2.87M
    maxPos = 0;
9948
2.87M
    predOp = NULL;
9949
2.87M
    hasPredicateRange = 0;
9950
2.87M
    hasAxisRange = 0;
9951
2.87M
    if (op->ch2 != -1) {
9952
  /*
9953
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9954
  */
9955
206k
  predOp = &ctxt->comp->steps[op->ch2];
9956
206k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9957
39.5k
      if (predOp->ch1 != -1) {
9958
    /*
9959
    * Use the next inner predicate operator.
9960
    */
9961
4.97k
    predOp = &ctxt->comp->steps[predOp->ch1];
9962
4.97k
    hasPredicateRange = 1;
9963
34.5k
      } else {
9964
    /*
9965
    * There's no other predicate than the [n] predicate.
9966
    */
9967
34.5k
    predOp = NULL;
9968
34.5k
    hasAxisRange = 1;
9969
34.5k
      }
9970
39.5k
  }
9971
206k
    }
9972
2.87M
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
9973
    /*
9974
    * Axis traversal -----------------------------------------------------
9975
    */
9976
    /*
9977
     * 2.3 Node Tests
9978
     *  - For the attribute axis, the principal node type is attribute.
9979
     *  - For the namespace axis, the principal node type is namespace.
9980
     *  - For other axes, the principal node type is element.
9981
     *
9982
     * A node test * is true for any node of the
9983
     * principal node type. For example, child::* will
9984
     * select all element children of the context node
9985
     */
9986
2.87M
    oldContextNode = xpctxt->node;
9987
2.87M
    addNode = xmlXPathNodeSetAddUnique;
9988
2.87M
    outSeq = NULL;
9989
2.87M
    seq = NULL;
9990
2.87M
    contextNode = NULL;
9991
2.87M
    contextIdx = 0;
9992
9993
9994
11.9M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
9995
11.9M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
9996
9.14M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
9997
9998
9.14M
  if (seq == NULL) {
9999
2.98M
      seq = xmlXPathNodeSetCreate(NULL);
10000
2.98M
      if (seq == NULL) {
10001
282
                xmlXPathPErrMemory(ctxt);
10002
282
    total = 0;
10003
282
    goto error;
10004
282
      }
10005
2.98M
  }
10006
  /*
10007
  * Traverse the axis and test the nodes.
10008
  */
10009
9.14M
  pos = 0;
10010
9.14M
  cur = NULL;
10011
9.14M
  hasNsNodes = 0;
10012
64.9M
        do {
10013
64.9M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10014
162
                goto error;
10015
10016
64.9M
            cur = next(ctxt, cur);
10017
64.9M
            if (cur == NULL)
10018
9.02M
                break;
10019
10020
      /*
10021
      * QUESTION TODO: What does the "first" and "last" stuff do?
10022
      */
10023
55.8M
            if ((first != NULL) && (*first != NULL)) {
10024
915k
    if (*first == cur)
10025
19.6k
        break;
10026
895k
    if (((total % 256) == 0) &&
10027
895k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10028
895k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10029
#else
10030
        (xmlXPathCmpNodes(*first, cur) >= 0))
10031
#endif
10032
22.3k
    {
10033
22.3k
        break;
10034
22.3k
    }
10035
895k
      }
10036
55.8M
      if ((last != NULL) && (*last != NULL)) {
10037
16.1k
    if (*last == cur)
10038
2.05k
        break;
10039
14.1k
    if (((total % 256) == 0) &&
10040
14.1k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10041
14.1k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10042
#else
10043
        (xmlXPathCmpNodes(cur, *last) >= 0))
10044
#endif
10045
10.9k
    {
10046
10.9k
        break;
10047
10.9k
    }
10048
14.1k
      }
10049
10050
55.8M
            total++;
10051
10052
55.8M
      switch (test) {
10053
0
                case NODE_TEST_NONE:
10054
0
        total = 0;
10055
0
        goto error;
10056
40.1M
                case NODE_TEST_TYPE:
10057
40.1M
        if (type == NODE_TYPE_NODE) {
10058
39.9M
      switch (cur->type) {
10059
311k
          case XML_DOCUMENT_NODE:
10060
311k
          case XML_HTML_DOCUMENT_NODE:
10061
25.2M
          case XML_ELEMENT_NODE:
10062
25.2M
          case XML_ATTRIBUTE_NODE:
10063
25.7M
          case XML_PI_NODE:
10064
25.7M
          case XML_COMMENT_NODE:
10065
26.2M
          case XML_CDATA_SECTION_NODE:
10066
39.7M
          case XML_TEXT_NODE:
10067
39.7M
        XP_TEST_HIT
10068
39.7M
        break;
10069
39.7M
          case XML_NAMESPACE_DECL: {
10070
89.7k
        if (axis == AXIS_NAMESPACE) {
10071
23.4k
            XP_TEST_HIT_NS
10072
66.3k
        } else {
10073
66.3k
                              hasNsNodes = 1;
10074
66.3k
            XP_TEST_HIT
10075
66.3k
        }
10076
85.8k
        break;
10077
89.7k
                            }
10078
85.8k
          default:
10079
60.8k
        break;
10080
39.9M
      }
10081
39.9M
        } else if (cur->type == (xmlElementType) type) {
10082
95.2k
      if (cur->type == XML_NAMESPACE_DECL)
10083
0
          XP_TEST_HIT_NS
10084
95.2k
      else
10085
95.2k
          XP_TEST_HIT
10086
141k
        } else if ((type == NODE_TYPE_TEXT) &&
10087
141k
       (cur->type == XML_CDATA_SECTION_NODE))
10088
18.8k
        {
10089
18.8k
      XP_TEST_HIT
10090
18.8k
        }
10091
40.1M
        break;
10092
40.1M
                case NODE_TEST_PI:
10093
38.2k
                    if ((cur->type == XML_PI_NODE) &&
10094
38.2k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10095
819
        {
10096
819
      XP_TEST_HIT
10097
819
                    }
10098
37.8k
                    break;
10099
9.18M
                case NODE_TEST_ALL:
10100
9.18M
                    if (axis == AXIS_ATTRIBUTE) {
10101
27.8k
                        if (cur->type == XML_ATTRIBUTE_NODE)
10102
27.8k
      {
10103
27.8k
                            if (prefix == NULL)
10104
23.5k
          {
10105
23.5k
        XP_TEST_HIT
10106
23.5k
                            } else if ((cur->ns != NULL) &&
10107
4.29k
        (xmlStrEqual(URI, cur->ns->href)))
10108
2.61k
          {
10109
2.61k
        XP_TEST_HIT
10110
2.61k
                            }
10111
27.8k
                        }
10112
9.15M
                    } else if (axis == AXIS_NAMESPACE) {
10113
859k
                        if (cur->type == XML_NAMESPACE_DECL)
10114
859k
      {
10115
859k
          XP_TEST_HIT_NS
10116
859k
                        }
10117
8.29M
                    } else {
10118
8.29M
                        if (cur->type == XML_ELEMENT_NODE) {
10119
5.91M
                            if (prefix == NULL)
10120
5.89M
          {
10121
5.89M
        XP_TEST_HIT
10122
10123
5.89M
                            } else if ((cur->ns != NULL) &&
10124
23.4k
        (xmlStrEqual(URI, cur->ns->href)))
10125
2.10k
          {
10126
2.10k
        XP_TEST_HIT
10127
2.10k
                            }
10128
5.91M
                        }
10129
8.29M
                    }
10130
9.15M
                    break;
10131
9.15M
                case NODE_TEST_NS:{
10132
                        /* TODO */
10133
0
                        break;
10134
9.18M
                    }
10135
6.48M
                case NODE_TEST_NAME:
10136
6.48M
                    if (axis == AXIS_ATTRIBUTE) {
10137
9.59k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10138
0
          break;
10139
6.47M
        } else if (axis == AXIS_NAMESPACE) {
10140
12.5k
                        if (cur->type != XML_NAMESPACE_DECL)
10141
0
          break;
10142
6.46M
        } else {
10143
6.46M
            if (cur->type != XML_ELEMENT_NODE)
10144
1.22M
          break;
10145
6.46M
        }
10146
5.25M
                    switch (cur->type) {
10147
5.23M
                        case XML_ELEMENT_NODE:
10148
5.23M
                            if (xmlStrEqual(name, cur->name)) {
10149
222k
                                if (prefix == NULL) {
10150
214k
                                    if (cur->ns == NULL)
10151
204k
            {
10152
204k
          XP_TEST_HIT
10153
204k
                                    }
10154
214k
                                } else {
10155
8.20k
                                    if ((cur->ns != NULL) &&
10156
8.20k
                                        (xmlStrEqual(URI, cur->ns->href)))
10157
1.88k
            {
10158
1.88k
          XP_TEST_HIT
10159
1.88k
                                    }
10160
8.20k
                                }
10161
222k
                            }
10162
5.22M
                            break;
10163
5.22M
                        case XML_ATTRIBUTE_NODE:{
10164
9.59k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10165
10166
9.59k
                                if (xmlStrEqual(name, attr->name)) {
10167
4.87k
                                    if (prefix == NULL) {
10168
2.36k
                                        if ((attr->ns == NULL) ||
10169
2.36k
                                            (attr->ns->prefix == NULL))
10170
1.95k
          {
10171
1.95k
              XP_TEST_HIT
10172
1.95k
                                        }
10173
2.51k
                                    } else {
10174
2.51k
                                        if ((attr->ns != NULL) &&
10175
2.51k
                                            (xmlStrEqual(URI,
10176
1.90k
                attr->ns->href)))
10177
1.49k
          {
10178
1.49k
              XP_TEST_HIT
10179
1.49k
                                        }
10180
2.51k
                                    }
10181
4.87k
                                }
10182
8.09k
                                break;
10183
9.59k
                            }
10184
12.5k
                        case XML_NAMESPACE_DECL:
10185
12.5k
                            if (cur->type == XML_NAMESPACE_DECL) {
10186
12.5k
                                xmlNsPtr ns = (xmlNsPtr) cur;
10187
10188
12.5k
                                if ((ns->prefix != NULL) && (name != NULL)
10189
12.5k
                                    && (xmlStrEqual(ns->prefix, name)))
10190
3.67k
        {
10191
3.67k
            XP_TEST_HIT_NS
10192
3.67k
                                }
10193
12.5k
                            }
10194
11.2k
                            break;
10195
11.2k
                        default:
10196
0
                            break;
10197
5.25M
                    }
10198
5.24M
                    break;
10199
55.8M
      } /* switch(test) */
10200
55.8M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10201
10202
9.08M
  goto apply_predicates;
10203
10204
9.08M
axis_range_end: /* ----------------------------------------------------- */
10205
  /*
10206
  * We have a "/foo[n]", and position() = n was reached.
10207
  * Note that we can have as well "/foo/::parent::foo[1]", so
10208
  * a duplicate-aware merge is still needed.
10209
  * Merge with the result.
10210
  */
10211
30.1k
  if (outSeq == NULL) {
10212
11.9k
      outSeq = seq;
10213
11.9k
      seq = NULL;
10214
18.1k
  } else {
10215
18.1k
      outSeq = mergeAndClear(outSeq, seq);
10216
18.1k
            if (outSeq == NULL)
10217
11
                xmlXPathPErrMemory(ctxt);
10218
18.1k
        }
10219
  /*
10220
  * Break if only a true/false result was requested.
10221
  */
10222
30.1k
  if (toBool)
10223
4.52k
      break;
10224
25.6k
  continue;
10225
10226
29.0k
first_hit: /* ---------------------------------------------------------- */
10227
  /*
10228
  * Break if only a true/false result was requested and
10229
  * no predicates existed and a node test succeeded.
10230
  */
10231
29.0k
  if (outSeq == NULL) {
10232
29.0k
      outSeq = seq;
10233
29.0k
      seq = NULL;
10234
29.0k
  } else {
10235
0
      outSeq = mergeAndClear(outSeq, seq);
10236
0
            if (outSeq == NULL)
10237
0
                xmlXPathPErrMemory(ctxt);
10238
0
        }
10239
29.0k
  break;
10240
10241
9.08M
apply_predicates: /* --------------------------------------------------- */
10242
9.08M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10243
371
      goto error;
10244
10245
        /*
10246
  * Apply predicates.
10247
  */
10248
9.08M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
10249
      /*
10250
      * E.g. when we have a "/foo[some expression][n]".
10251
      */
10252
      /*
10253
      * QUESTION TODO: The old predicate evaluation took into
10254
      *  account location-sets.
10255
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
10256
      *  Do we expect such a set here?
10257
      *  All what I learned now from the evaluation semantics
10258
      *  does not indicate that a location-set will be processed
10259
      *  here, so this looks OK.
10260
      */
10261
      /*
10262
      * Iterate over all predicates, starting with the outermost
10263
      * predicate.
10264
      * TODO: Problem: we cannot execute the inner predicates first
10265
      *  since we cannot go back *up* the operator tree!
10266
      *  Options we have:
10267
      *  1) Use of recursive functions (like is it currently done
10268
      *     via xmlXPathCompOpEval())
10269
      *  2) Add a predicate evaluation information stack to the
10270
      *     context struct
10271
      *  3) Change the way the operators are linked; we need a
10272
      *     "parent" field on xmlXPathStepOp
10273
      *
10274
      * For the moment, I'll try to solve this with a recursive
10275
      * function: xmlXPathCompOpEvalPredicate().
10276
      */
10277
558k
      if (hasPredicateRange != 0)
10278
9.98k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10279
9.98k
              hasNsNodes);
10280
548k
      else
10281
548k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10282
548k
              hasNsNodes);
10283
10284
558k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10285
3.33k
    total = 0;
10286
3.33k
    goto error;
10287
3.33k
      }
10288
558k
        }
10289
10290
9.07M
        if (seq->nodeNr > 0) {
10291
      /*
10292
      * Add to result set.
10293
      */
10294
3.25M
      if (outSeq == NULL) {
10295
878k
    outSeq = seq;
10296
878k
    seq = NULL;
10297
2.37M
      } else {
10298
2.37M
    outSeq = mergeAndClear(outSeq, seq);
10299
2.37M
                if (outSeq == NULL)
10300
234
                    xmlXPathPErrMemory(ctxt);
10301
2.37M
      }
10302
10303
3.25M
            if (toBool)
10304
1.95k
                break;
10305
3.25M
  }
10306
9.07M
    }
10307
10308
2.87M
error:
10309
2.87M
    if ((obj->boolval) && (obj->user != NULL)) {
10310
  /*
10311
  * QUESTION TODO: What does this do and why?
10312
  * TODO: Do we have to do this also for the "error"
10313
  * cleanup further down?
10314
  */
10315
0
  ctxt->value->boolval = 1;
10316
0
  ctxt->value->user = obj->user;
10317
0
  obj->user = NULL;
10318
0
  obj->boolval = 0;
10319
0
    }
10320
2.87M
    xmlXPathReleaseObject(xpctxt, obj);
10321
10322
    /*
10323
    * Ensure we return at least an empty set.
10324
    */
10325
2.87M
    if (outSeq == NULL) {
10326
1.95M
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10327
1.95M
      outSeq = seq;
10328
1.95M
        } else {
10329
598
      outSeq = xmlXPathNodeSetCreate(NULL);
10330
598
            if (outSeq == NULL)
10331
5
                xmlXPathPErrMemory(ctxt);
10332
598
        }
10333
1.95M
    }
10334
2.87M
    if ((seq != NULL) && (seq != outSeq)) {
10335
114k
   xmlXPathFreeNodeSet(seq);
10336
114k
    }
10337
    /*
10338
    * Hand over the result. Better to push the set also in
10339
    * case of errors.
10340
    */
10341
2.87M
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10342
    /*
10343
    * Reset the context node.
10344
    */
10345
2.87M
    xpctxt->node = oldContextNode;
10346
    /*
10347
    * When traversing the namespace axis in "toBool" mode, it's
10348
    * possible that tmpNsList wasn't freed.
10349
    */
10350
2.87M
    if (xpctxt->tmpNsList != NULL) {
10351
936
        xmlFree(xpctxt->tmpNsList);
10352
936
        xpctxt->tmpNsList = NULL;
10353
936
    }
10354
10355
2.87M
    return(total);
10356
2.87M
}
10357
10358
static int
10359
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10360
            xmlXPathStepOpPtr op, xmlNodePtr * first);
10361
10362
/**
10363
 * Evaluate the Precompiled XPath operation searching only the first
10364
 * element in document order
10365
 *
10366
 * @param ctxt  the XPath parser context with the compiled expression
10367
 * @param op  an XPath compiled operation
10368
 * @param first  the first elem found so far
10369
 * @returns the number of examined objects.
10370
 */
10371
static int
10372
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10373
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
10374
269k
{
10375
269k
    int total = 0, cur;
10376
269k
    xmlXPathCompExprPtr comp;
10377
269k
    xmlXPathObjectPtr arg1, arg2;
10378
10379
269k
    CHECK_ERROR0;
10380
269k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10381
2
        return(0);
10382
269k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10383
269k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10384
269k
    ctxt->context->depth += 1;
10385
269k
    comp = ctxt->comp;
10386
269k
    switch (op->op) {
10387
0
        case XPATH_OP_END:
10388
0
            break;
10389
80.5k
        case XPATH_OP_UNION:
10390
80.5k
            total =
10391
80.5k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10392
80.5k
                                        first);
10393
80.5k
      CHECK_ERROR0;
10394
59.6k
            if ((ctxt->value != NULL)
10395
59.6k
                && (ctxt->value->type == XPATH_NODESET)
10396
59.6k
                && (ctxt->value->nodesetval != NULL)
10397
59.6k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10398
                /*
10399
                 * limit tree traversing to first node in the result
10400
                 */
10401
    /*
10402
    * OPTIMIZE TODO: This implicitly sorts
10403
    *  the result, even if not needed. E.g. if the argument
10404
    *  of the count() function, no sorting is needed.
10405
    * OPTIMIZE TODO: How do we know if the node-list wasn't
10406
    *  already sorted?
10407
    */
10408
44.9k
    if (ctxt->value->nodesetval->nodeNr > 1)
10409
28.2k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10410
44.9k
                *first = ctxt->value->nodesetval->nodeTab[0];
10411
44.9k
            }
10412
59.6k
            cur =
10413
59.6k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10414
59.6k
                                        first);
10415
59.6k
      CHECK_ERROR0;
10416
10417
59.4k
            arg2 = xmlXPathValuePop(ctxt);
10418
59.4k
            arg1 = xmlXPathValuePop(ctxt);
10419
59.4k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10420
59.4k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10421
128
          xmlXPathReleaseObject(ctxt->context, arg1);
10422
128
          xmlXPathReleaseObject(ctxt->context, arg2);
10423
128
                XP_ERROR0(XPATH_INVALID_TYPE);
10424
0
            }
10425
59.2k
            if ((ctxt->context->opLimit != 0) &&
10426
59.2k
                (((arg1->nodesetval != NULL) &&
10427
52.5k
                  (xmlXPathCheckOpLimit(ctxt,
10428
52.5k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10429
52.5k
                 ((arg2->nodesetval != NULL) &&
10430
52.5k
                  (xmlXPathCheckOpLimit(ctxt,
10431
52.5k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10432
14
          xmlXPathReleaseObject(ctxt->context, arg1);
10433
14
          xmlXPathReleaseObject(ctxt->context, arg2);
10434
14
                break;
10435
14
            }
10436
10437
59.2k
            if ((arg2->nodesetval != NULL) &&
10438
59.2k
                (arg2->nodesetval->nodeNr != 0)) {
10439
36.3k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10440
36.3k
                                                        arg2->nodesetval);
10441
36.3k
                if (arg1->nodesetval == NULL)
10442
10
                    xmlXPathPErrMemory(ctxt);
10443
36.3k
            }
10444
59.2k
            xmlXPathValuePush(ctxt, arg1);
10445
59.2k
      xmlXPathReleaseObject(ctxt->context, arg2);
10446
59.2k
            total += cur;
10447
59.2k
            break;
10448
7.56k
        case XPATH_OP_ROOT:
10449
7.56k
            xmlXPathRoot(ctxt);
10450
7.56k
            break;
10451
24.2k
        case XPATH_OP_NODE:
10452
24.2k
            if (op->ch1 != -1)
10453
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10454
24.2k
      CHECK_ERROR0;
10455
24.2k
            if (op->ch2 != -1)
10456
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10457
24.2k
      CHECK_ERROR0;
10458
24.2k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10459
24.2k
    ctxt->context->node));
10460
24.2k
            break;
10461
49.4k
        case XPATH_OP_COLLECT:{
10462
49.4k
                if (op->ch1 == -1)
10463
0
                    break;
10464
10465
49.4k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10466
49.4k
    CHECK_ERROR0;
10467
10468
49.2k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10469
49.2k
                break;
10470
49.4k
            }
10471
261
        case XPATH_OP_VALUE:
10472
261
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10473
261
            break;
10474
29.4k
        case XPATH_OP_SORT:
10475
29.4k
            if (op->ch1 != -1)
10476
29.4k
                total +=
10477
29.4k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10478
29.4k
                                            first);
10479
29.4k
      CHECK_ERROR0;
10480
28.7k
            if ((ctxt->value != NULL)
10481
28.7k
                && (ctxt->value->type == XPATH_NODESET)
10482
28.7k
                && (ctxt->value->nodesetval != NULL)
10483
28.7k
    && (ctxt->value->nodesetval->nodeNr > 1))
10484
15.3k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10485
28.7k
            break;
10486
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10487
74.7k
  case XPATH_OP_FILTER:
10488
74.7k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10489
74.7k
            break;
10490
0
#endif
10491
2.95k
        default:
10492
2.95k
            total += xmlXPathCompOpEval(ctxt, op);
10493
2.95k
            break;
10494
269k
    }
10495
10496
247k
    ctxt->context->depth -= 1;
10497
247k
    return(total);
10498
269k
}
10499
10500
/**
10501
 * Evaluate the Precompiled XPath operation searching only the last
10502
 * element in document order
10503
 *
10504
 * @param ctxt  the XPath parser context with the compiled expression
10505
 * @param op  an XPath compiled operation
10506
 * @param last  the last elem found so far
10507
 * @returns the number of nodes traversed
10508
 */
10509
static int
10510
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10511
                       xmlNodePtr * last)
10512
221k
{
10513
221k
    int total = 0, cur;
10514
221k
    xmlXPathCompExprPtr comp;
10515
221k
    xmlXPathObjectPtr arg1, arg2;
10516
10517
221k
    CHECK_ERROR0;
10518
221k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10519
3
        return(0);
10520
221k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10521
221k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10522
221k
    ctxt->context->depth += 1;
10523
221k
    comp = ctxt->comp;
10524
221k
    switch (op->op) {
10525
0
        case XPATH_OP_END:
10526
0
            break;
10527
70.3k
        case XPATH_OP_UNION:
10528
70.3k
            total =
10529
70.3k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10530
70.3k
      CHECK_ERROR0;
10531
64.7k
            if ((ctxt->value != NULL)
10532
64.7k
                && (ctxt->value->type == XPATH_NODESET)
10533
64.7k
                && (ctxt->value->nodesetval != NULL)
10534
64.7k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10535
                /*
10536
                 * limit tree traversing to first node in the result
10537
                 */
10538
46.6k
    if (ctxt->value->nodesetval->nodeNr > 1)
10539
36.0k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10540
46.6k
                *last =
10541
46.6k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10542
46.6k
                                                     nodesetval->nodeNr -
10543
46.6k
                                                     1];
10544
46.6k
            }
10545
64.7k
            cur =
10546
64.7k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10547
64.7k
      CHECK_ERROR0;
10548
64.5k
            if ((ctxt->value != NULL)
10549
64.5k
                && (ctxt->value->type == XPATH_NODESET)
10550
64.5k
                && (ctxt->value->nodesetval != NULL)
10551
64.5k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10552
34.3k
            }
10553
10554
64.5k
            arg2 = xmlXPathValuePop(ctxt);
10555
64.5k
            arg1 = xmlXPathValuePop(ctxt);
10556
64.5k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10557
64.5k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10558
90
          xmlXPathReleaseObject(ctxt->context, arg1);
10559
90
          xmlXPathReleaseObject(ctxt->context, arg2);
10560
90
                XP_ERROR0(XPATH_INVALID_TYPE);
10561
0
            }
10562
64.4k
            if ((ctxt->context->opLimit != 0) &&
10563
64.4k
                (((arg1->nodesetval != NULL) &&
10564
60.8k
                  (xmlXPathCheckOpLimit(ctxt,
10565
60.8k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10566
60.8k
                 ((arg2->nodesetval != NULL) &&
10567
60.8k
                  (xmlXPathCheckOpLimit(ctxt,
10568
60.8k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10569
6
          xmlXPathReleaseObject(ctxt->context, arg1);
10570
6
          xmlXPathReleaseObject(ctxt->context, arg2);
10571
6
                break;
10572
6
            }
10573
10574
64.4k
            if ((arg2->nodesetval != NULL) &&
10575
64.4k
                (arg2->nodesetval->nodeNr != 0)) {
10576
34.3k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10577
34.3k
                                                        arg2->nodesetval);
10578
34.3k
                if (arg1->nodesetval == NULL)
10579
5
                    xmlXPathPErrMemory(ctxt);
10580
34.3k
            }
10581
64.4k
            xmlXPathValuePush(ctxt, arg1);
10582
64.4k
      xmlXPathReleaseObject(ctxt->context, arg2);
10583
64.4k
            total += cur;
10584
64.4k
            break;
10585
14.2k
        case XPATH_OP_ROOT:
10586
14.2k
            xmlXPathRoot(ctxt);
10587
14.2k
            break;
10588
15.2k
        case XPATH_OP_NODE:
10589
15.2k
            if (op->ch1 != -1)
10590
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10591
15.2k
      CHECK_ERROR0;
10592
15.2k
            if (op->ch2 != -1)
10593
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10594
15.2k
      CHECK_ERROR0;
10595
15.2k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10596
15.2k
    ctxt->context->node));
10597
15.2k
            break;
10598
69.5k
        case XPATH_OP_COLLECT:{
10599
69.5k
                if (op->ch1 == -1)
10600
0
                    break;
10601
10602
69.5k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10603
69.5k
    CHECK_ERROR0;
10604
10605
69.4k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10606
69.4k
                break;
10607
69.5k
            }
10608
97
        case XPATH_OP_VALUE:
10609
97
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10610
97
            break;
10611
43.9k
        case XPATH_OP_SORT:
10612
43.9k
            if (op->ch1 != -1)
10613
43.9k
                total +=
10614
43.9k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10615
43.9k
                                           last);
10616
43.9k
      CHECK_ERROR0;
10617
43.4k
            if ((ctxt->value != NULL)
10618
43.4k
                && (ctxt->value->type == XPATH_NODESET)
10619
43.4k
                && (ctxt->value->nodesetval != NULL)
10620
43.4k
    && (ctxt->value->nodesetval->nodeNr > 1))
10621
13.6k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10622
43.4k
            break;
10623
8.05k
        default:
10624
8.05k
            total += xmlXPathCompOpEval(ctxt, op);
10625
8.05k
            break;
10626
221k
    }
10627
10628
215k
    ctxt->context->depth -= 1;
10629
215k
    return (total);
10630
221k
}
10631
10632
#ifdef XP_OPTIMIZED_FILTER_FIRST
10633
static int
10634
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10635
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10636
74.7k
{
10637
74.7k
    int total = 0;
10638
74.7k
    xmlXPathCompExprPtr comp;
10639
74.7k
    xmlXPathObjectPtr obj;
10640
74.7k
    xmlNodeSetPtr set;
10641
10642
74.7k
    CHECK_ERROR0;
10643
74.7k
    comp = ctxt->comp;
10644
    /*
10645
    * Optimization for ()[last()] selection i.e. the last elem
10646
    */
10647
74.7k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10648
74.7k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10649
74.7k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10650
9.79k
  int f = comp->steps[op->ch2].ch1;
10651
10652
9.79k
  if ((f != -1) &&
10653
9.79k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10654
9.79k
      (comp->steps[f].value5 == NULL) &&
10655
9.79k
      (comp->steps[f].value == 0) &&
10656
9.79k
      (comp->steps[f].value4 != NULL) &&
10657
9.79k
      (xmlStrEqual
10658
4.56k
      (comp->steps[f].value4, BAD_CAST "last"))) {
10659
3.54k
      xmlNodePtr last = NULL;
10660
10661
3.54k
      total +=
10662
3.54k
    xmlXPathCompOpEvalLast(ctxt,
10663
3.54k
        &comp->steps[op->ch1],
10664
3.54k
        &last);
10665
3.54k
      CHECK_ERROR0;
10666
      /*
10667
      * The nodeset should be in document order,
10668
      * Keep only the last value
10669
      */
10670
3.46k
      if ((ctxt->value != NULL) &&
10671
3.46k
    (ctxt->value->type == XPATH_NODESET) &&
10672
3.46k
    (ctxt->value->nodesetval != NULL) &&
10673
3.46k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10674
3.46k
    (ctxt->value->nodesetval->nodeNr > 1)) {
10675
1.02k
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10676
1.02k
    *first = *(ctxt->value->nodesetval->nodeTab);
10677
1.02k
      }
10678
3.46k
      return (total);
10679
3.54k
  }
10680
9.79k
    }
10681
10682
71.2k
    if (op->ch1 != -1)
10683
71.2k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10684
71.2k
    CHECK_ERROR0;
10685
68.5k
    if (op->ch2 == -1)
10686
0
  return (total);
10687
68.5k
    if (ctxt->value == NULL)
10688
0
  return (total);
10689
10690
    /*
10691
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
10692
     * the stack. We have to temporarily remove the nodeset object from the
10693
     * stack to avoid freeing it prematurely.
10694
     */
10695
68.5k
    CHECK_TYPE0(XPATH_NODESET);
10696
68.5k
    obj = xmlXPathValuePop(ctxt);
10697
68.5k
    set = obj->nodesetval;
10698
68.5k
    if (set != NULL) {
10699
68.5k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10700
68.5k
        if (set->nodeNr > 0)
10701
40.6k
            *first = set->nodeTab[0];
10702
68.5k
    }
10703
68.5k
    xmlXPathValuePush(ctxt, obj);
10704
10705
68.5k
    return (total);
10706
68.5k
}
10707
#endif /* XP_OPTIMIZED_FILTER_FIRST */
10708
10709
/**
10710
 * Evaluate the Precompiled XPath operation
10711
 *
10712
 * @param ctxt  the XPath parser context with the compiled expression
10713
 * @param op  an XPath compiled operation
10714
 * @returns the number of nodes traversed
10715
 */
10716
static int
10717
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10718
11.4M
{
10719
11.4M
    int total = 0;
10720
11.4M
    int equal, ret;
10721
11.4M
    xmlXPathCompExprPtr comp;
10722
11.4M
    xmlXPathObjectPtr arg1, arg2;
10723
10724
11.4M
    CHECK_ERROR0;
10725
11.4M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10726
280
        return(0);
10727
11.4M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10728
11.4M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10729
11.4M
    ctxt->context->depth += 1;
10730
11.4M
    comp = ctxt->comp;
10731
11.4M
    switch (op->op) {
10732
0
        case XPATH_OP_END:
10733
0
            break;
10734
64.6k
        case XPATH_OP_AND:
10735
64.6k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10736
64.6k
      CHECK_ERROR0;
10737
63.7k
            xmlXPathBooleanFunction(ctxt, 1);
10738
63.7k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10739
61.1k
                break;
10740
2.58k
            arg2 = xmlXPathValuePop(ctxt);
10741
2.58k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10742
2.58k
      if (ctxt->error) {
10743
95
    xmlXPathFreeObject(arg2);
10744
95
    break;
10745
95
      }
10746
2.48k
            xmlXPathBooleanFunction(ctxt, 1);
10747
2.48k
            if (ctxt->value != NULL)
10748
2.48k
                ctxt->value->boolval &= arg2->boolval;
10749
2.48k
      xmlXPathReleaseObject(ctxt->context, arg2);
10750
2.48k
            break;
10751
29.1k
        case XPATH_OP_OR:
10752
29.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10753
29.1k
      CHECK_ERROR0;
10754
27.2k
            xmlXPathBooleanFunction(ctxt, 1);
10755
27.2k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10756
12.1k
                break;
10757
15.1k
            arg2 = xmlXPathValuePop(ctxt);
10758
15.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10759
15.1k
      if (ctxt->error) {
10760
417
    xmlXPathFreeObject(arg2);
10761
417
    break;
10762
417
      }
10763
14.7k
            xmlXPathBooleanFunction(ctxt, 1);
10764
14.7k
            if (ctxt->value != NULL)
10765
14.7k
                ctxt->value->boolval |= arg2->boolval;
10766
14.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
10767
14.7k
            break;
10768
665k
        case XPATH_OP_EQUAL:
10769
665k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10770
665k
      CHECK_ERROR0;
10771
647k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10772
647k
      CHECK_ERROR0;
10773
644k
      if (op->value)
10774
532k
    equal = xmlXPathEqualValues(ctxt);
10775
112k
      else
10776
112k
    equal = xmlXPathNotEqualValues(ctxt);
10777
644k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10778
644k
            break;
10779
364k
        case XPATH_OP_CMP:
10780
364k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10781
364k
      CHECK_ERROR0;
10782
361k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10783
361k
      CHECK_ERROR0;
10784
359k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10785
359k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10786
359k
            break;
10787
857k
        case XPATH_OP_PLUS:
10788
857k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10789
857k
      CHECK_ERROR0;
10790
849k
            if (op->ch2 != -1) {
10791
485k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10792
485k
      }
10793
849k
      CHECK_ERROR0;
10794
846k
            if (op->value == 0)
10795
376k
                xmlXPathSubValues(ctxt);
10796
470k
            else if (op->value == 1)
10797
106k
                xmlXPathAddValues(ctxt);
10798
363k
            else if (op->value == 2)
10799
248k
                xmlXPathValueFlipSign(ctxt);
10800
115k
            else if (op->value == 3) {
10801
115k
                CAST_TO_NUMBER;
10802
115k
                CHECK_TYPE0(XPATH_NUMBER);
10803
115k
            }
10804
846k
            break;
10805
846k
        case XPATH_OP_MULT:
10806
544k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10807
544k
      CHECK_ERROR0;
10808
507k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10809
507k
      CHECK_ERROR0;
10810
506k
            if (op->value == 0)
10811
492k
                xmlXPathMultValues(ctxt);
10812
13.8k
            else if (op->value == 1)
10813
10.7k
                xmlXPathDivValues(ctxt);
10814
3.11k
            else if (op->value == 2)
10815
3.11k
                xmlXPathModValues(ctxt);
10816
506k
            break;
10817
369k
        case XPATH_OP_UNION:
10818
369k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10819
369k
      CHECK_ERROR0;
10820
360k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10821
360k
      CHECK_ERROR0;
10822
10823
359k
            arg2 = xmlXPathValuePop(ctxt);
10824
359k
            arg1 = xmlXPathValuePop(ctxt);
10825
359k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10826
359k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10827
239
          xmlXPathReleaseObject(ctxt->context, arg1);
10828
239
          xmlXPathReleaseObject(ctxt->context, arg2);
10829
239
                XP_ERROR0(XPATH_INVALID_TYPE);
10830
0
            }
10831
358k
            if ((ctxt->context->opLimit != 0) &&
10832
358k
                (((arg1->nodesetval != NULL) &&
10833
319k
                  (xmlXPathCheckOpLimit(ctxt,
10834
319k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10835
319k
                 ((arg2->nodesetval != NULL) &&
10836
319k
                  (xmlXPathCheckOpLimit(ctxt,
10837
319k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10838
53
          xmlXPathReleaseObject(ctxt->context, arg1);
10839
53
          xmlXPathReleaseObject(ctxt->context, arg2);
10840
53
                break;
10841
53
            }
10842
10843
358k
      if (((arg2->nodesetval != NULL) &&
10844
358k
     (arg2->nodesetval->nodeNr != 0)))
10845
202k
      {
10846
202k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10847
202k
              arg2->nodesetval);
10848
202k
                if (arg1->nodesetval == NULL)
10849
77
                    xmlXPathPErrMemory(ctxt);
10850
202k
      }
10851
10852
358k
            xmlXPathValuePush(ctxt, arg1);
10853
358k
      xmlXPathReleaseObject(ctxt->context, arg2);
10854
358k
            break;
10855
1.18M
        case XPATH_OP_ROOT:
10856
1.18M
            xmlXPathRoot(ctxt);
10857
1.18M
            break;
10858
2.33M
        case XPATH_OP_NODE:
10859
2.33M
            if (op->ch1 != -1)
10860
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10861
2.33M
      CHECK_ERROR0;
10862
2.33M
            if (op->ch2 != -1)
10863
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10864
2.33M
      CHECK_ERROR0;
10865
2.33M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10866
2.33M
                                                    ctxt->context->node));
10867
2.33M
            break;
10868
2.66M
        case XPATH_OP_COLLECT:{
10869
2.66M
                if (op->ch1 == -1)
10870
0
                    break;
10871
10872
2.66M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10873
2.66M
    CHECK_ERROR0;
10874
10875
2.66M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10876
2.66M
                break;
10877
2.66M
            }
10878
797k
        case XPATH_OP_VALUE:
10879
797k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10880
797k
            break;
10881
445
        case XPATH_OP_VARIABLE:{
10882
445
    xmlXPathObjectPtr val;
10883
10884
445
                if (op->ch1 != -1)
10885
0
                    total +=
10886
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10887
445
                if (op->value5 == NULL) {
10888
355
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10889
355
        if (val == NULL) {
10890
355
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10891
355
                                       "Undefined variable: %s\n", op->value4);
10892
355
                        return 0;
10893
355
                    }
10894
0
                    xmlXPathValuePush(ctxt, val);
10895
90
    } else {
10896
90
                    const xmlChar *URI;
10897
10898
90
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10899
90
                    if (URI == NULL) {
10900
40
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10901
40
                                       "Undefined namespace prefix: %s\n",
10902
40
                                       op->value5);
10903
40
                        return 0;
10904
40
                    }
10905
50
        val = xmlXPathVariableLookupNS(ctxt->context,
10906
50
                                                       op->value4, URI);
10907
50
        if (val == NULL) {
10908
50
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10909
50
                                       "Undefined variable: %s:%s\n",
10910
50
                                       op->value5, op->value4);
10911
50
                        return 0;
10912
50
                    }
10913
0
                    xmlXPathValuePush(ctxt, val);
10914
0
                }
10915
0
                break;
10916
445
            }
10917
322k
        case XPATH_OP_FUNCTION:{
10918
322k
                xmlXPathFunction func;
10919
322k
                const xmlChar *oldFunc, *oldFuncURI;
10920
322k
    int i;
10921
322k
                int frame;
10922
10923
322k
                frame = ctxt->valueNr;
10924
322k
                if (op->ch1 != -1) {
10925
209k
                    total +=
10926
209k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10927
209k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10928
2.98k
                        break;
10929
209k
                }
10930
320k
    if (ctxt->valueNr < frame + op->value)
10931
320k
        XP_ERROR0(XPATH_INVALID_OPERAND);
10932
607k
    for (i = 0; i < op->value; i++) {
10933
287k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10934
287k
      XP_ERROR0(XPATH_INVALID_OPERAND);
10935
287k
                }
10936
320k
                if (op->cache != NULL)
10937
302k
                    func = op->cache;
10938
17.9k
                else {
10939
17.9k
                    const xmlChar *URI = NULL;
10940
10941
17.9k
                    if (op->value5 == NULL) {
10942
17.6k
                        func = xmlXPathFunctionLookup(ctxt->context,
10943
17.6k
                                                      op->value4);
10944
17.6k
                        if (func == NULL) {
10945
2.06k
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10946
2.06k
                                           "Unregistered function: %s\n",
10947
2.06k
                                           op->value4);
10948
2.06k
                            return 0;
10949
2.06k
                        }
10950
17.6k
                    } else {
10951
239
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10952
239
                        if (URI == NULL) {
10953
163
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10954
163
                                           "Undefined namespace prefix: %s\n",
10955
163
                                           op->value5);
10956
163
                            return 0;
10957
163
                        }
10958
76
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10959
76
                                                        op->value4, URI);
10960
76
                        if (func == NULL) {
10961
76
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10962
76
                                           "Unregistered function: %s:%s\n",
10963
76
                                           op->value5, op->value4);
10964
76
                            return 0;
10965
76
                        }
10966
76
                    }
10967
15.5k
                    op->cache = func;
10968
15.5k
                    op->cacheURI = (void *) URI;
10969
15.5k
                }
10970
317k
                oldFunc = ctxt->context->function;
10971
317k
                oldFuncURI = ctxt->context->functionURI;
10972
317k
                ctxt->context->function = op->value4;
10973
317k
                ctxt->context->functionURI = op->cacheURI;
10974
317k
                func(ctxt, op->value);
10975
317k
                ctxt->context->function = oldFunc;
10976
317k
                ctxt->context->functionURI = oldFuncURI;
10977
317k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
10978
317k
                    (ctxt->valueNr != frame + 1))
10979
317k
                    XP_ERROR0(XPATH_STACK_ERROR);
10980
317k
                break;
10981
317k
            }
10982
365k
        case XPATH_OP_ARG:
10983
365k
            if (op->ch1 != -1) {
10984
155k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10985
155k
          CHECK_ERROR0;
10986
155k
            }
10987
339k
            if (op->ch2 != -1) {
10988
339k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10989
339k
          CHECK_ERROR0;
10990
339k
      }
10991
336k
            break;
10992
336k
        case XPATH_OP_PREDICATE:
10993
306k
        case XPATH_OP_FILTER:{
10994
306k
                xmlXPathObjectPtr obj;
10995
306k
                xmlNodeSetPtr set;
10996
10997
                /*
10998
                 * Optimization for ()[1] selection i.e. the first elem
10999
                 */
11000
306k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11001
306k
#ifdef XP_OPTIMIZED_FILTER_FIRST
11002
        /*
11003
        * FILTER TODO: Can we assume that the inner processing
11004
        *  will result in an ordered list if we have an
11005
        *  XPATH_OP_FILTER?
11006
        *  What about an additional field or flag on
11007
        *  xmlXPathObject like @sorted ? This way we wouldn't need
11008
        *  to assume anything, so it would be more robust and
11009
        *  easier to optimize.
11010
        */
11011
306k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11012
306k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11013
#else
11014
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11015
#endif
11016
306k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11017
139k
                    xmlXPathObjectPtr val;
11018
11019
139k
                    val = comp->steps[op->ch2].value4;
11020
139k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11021
139k
                        (val->floatval == 1.0)) {
11022
99.7k
                        xmlNodePtr first = NULL;
11023
11024
99.7k
                        total +=
11025
99.7k
                            xmlXPathCompOpEvalFirst(ctxt,
11026
99.7k
                                                    &comp->steps[op->ch1],
11027
99.7k
                                                    &first);
11028
99.7k
      CHECK_ERROR0;
11029
                        /*
11030
                         * The nodeset should be in document order,
11031
                         * Keep only the first value
11032
                         */
11033
96.3k
                        if ((ctxt->value != NULL) &&
11034
96.3k
                            (ctxt->value->type == XPATH_NODESET) &&
11035
96.3k
                            (ctxt->value->nodesetval != NULL) &&
11036
96.3k
                            (ctxt->value->nodesetval->nodeNr > 1))
11037
14.7k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11038
14.7k
                                                        1, 1);
11039
96.3k
                        break;
11040
99.7k
                    }
11041
139k
                }
11042
                /*
11043
                 * Optimization for ()[last()] selection i.e. the last elem
11044
                 */
11045
207k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11046
207k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
207k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11048
122k
                    int f = comp->steps[op->ch2].ch1;
11049
11050
122k
                    if ((f != -1) &&
11051
122k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11052
122k
                        (comp->steps[f].value5 == NULL) &&
11053
122k
                        (comp->steps[f].value == 0) &&
11054
122k
                        (comp->steps[f].value4 != NULL) &&
11055
122k
                        (xmlStrEqual
11056
41.9k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11057
38.9k
                        xmlNodePtr last = NULL;
11058
11059
38.9k
                        total +=
11060
38.9k
                            xmlXPathCompOpEvalLast(ctxt,
11061
38.9k
                                                   &comp->steps[op->ch1],
11062
38.9k
                                                   &last);
11063
38.9k
      CHECK_ERROR0;
11064
                        /*
11065
                         * The nodeset should be in document order,
11066
                         * Keep only the last value
11067
                         */
11068
38.6k
                        if ((ctxt->value != NULL) &&
11069
38.6k
                            (ctxt->value->type == XPATH_NODESET) &&
11070
38.6k
                            (ctxt->value->nodesetval != NULL) &&
11071
38.6k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11072
38.6k
                            (ctxt->value->nodesetval->nodeNr > 1))
11073
12.4k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11074
38.6k
                        break;
11075
38.9k
                    }
11076
122k
                }
11077
    /*
11078
    * Process inner predicates first.
11079
    * Example "index[parent::book][1]":
11080
    * ...
11081
    *   PREDICATE   <-- we are here "[1]"
11082
    *     PREDICATE <-- process "[parent::book]" first
11083
    *       SORT
11084
    *         COLLECT  'parent' 'name' 'node' book
11085
    *           NODE
11086
    *     ELEM Object is a number : 1
11087
    */
11088
168k
                if (op->ch1 != -1)
11089
168k
                    total +=
11090
168k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11091
168k
    CHECK_ERROR0;
11092
165k
                if (op->ch2 == -1)
11093
0
                    break;
11094
165k
                if (ctxt->value == NULL)
11095
0
                    break;
11096
11097
                /*
11098
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
11099
                 * nodes from the stack. We have to temporarily remove the
11100
                 * nodeset object from the stack to avoid freeing it
11101
                 * prematurely.
11102
                 */
11103
165k
                CHECK_TYPE0(XPATH_NODESET);
11104
164k
                obj = xmlXPathValuePop(ctxt);
11105
164k
                set = obj->nodesetval;
11106
164k
                if (set != NULL)
11107
164k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11108
164k
                                          1, set->nodeNr, 1);
11109
164k
                xmlXPathValuePush(ctxt, obj);
11110
164k
                break;
11111
165k
            }
11112
585k
        case XPATH_OP_SORT:
11113
585k
            if (op->ch1 != -1)
11114
585k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11115
585k
      CHECK_ERROR0;
11116
571k
            if ((ctxt->value != NULL) &&
11117
571k
                (ctxt->value->type == XPATH_NODESET) &&
11118
571k
                (ctxt->value->nodesetval != NULL) &&
11119
571k
    (ctxt->value->nodesetval->nodeNr > 1))
11120
159k
      {
11121
159k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11122
159k
      }
11123
571k
            break;
11124
0
        default:
11125
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11126
0
            break;
11127
11.4M
    }
11128
11129
11.3M
    ctxt->context->depth -= 1;
11130
11.3M
    return (total);
11131
11.4M
}
11132
11133
/**
11134
 * Evaluates if the expression evaluates to true.
11135
 *
11136
 * @param ctxt  the XPath parser context
11137
 * @param op  the step operation
11138
 * @param isPredicate  whether a predicate is evaluated
11139
 * @returns 1 if true, 0 if false and -1 on API or internal errors.
11140
 */
11141
static int
11142
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
11143
          xmlXPathStepOpPtr op,
11144
          int isPredicate)
11145
3.56M
{
11146
3.56M
    xmlXPathObjectPtr resObj = NULL;
11147
11148
4.06M
start:
11149
4.06M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11150
10
        return(0);
11151
    /* comp = ctxt->comp; */
11152
4.06M
    switch (op->op) {
11153
0
        case XPATH_OP_END:
11154
0
            return (0);
11155
1.75M
  case XPATH_OP_VALUE:
11156
1.75M
      resObj = (xmlXPathObjectPtr) op->value4;
11157
1.75M
      if (isPredicate)
11158
1.75M
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11159
0
      return(xmlXPathCastToBoolean(resObj));
11160
502k
  case XPATH_OP_SORT:
11161
      /*
11162
      * We don't need sorting for boolean results. Skip this one.
11163
      */
11164
502k
            if (op->ch1 != -1) {
11165
502k
    op = &ctxt->comp->steps[op->ch1];
11166
502k
    goto start;
11167
502k
      }
11168
0
      return(0);
11169
234k
  case XPATH_OP_COLLECT:
11170
234k
      if (op->ch1 == -1)
11171
0
    return(0);
11172
11173
234k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11174
234k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11175
180
    return(-1);
11176
11177
234k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11178
234k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11179
586
    return(-1);
11180
11181
233k
      resObj = xmlXPathValuePop(ctxt);
11182
233k
      if (resObj == NULL)
11183
0
    return(-1);
11184
233k
      break;
11185
1.58M
  default:
11186
      /*
11187
      * Fallback to call xmlXPathCompOpEval().
11188
      */
11189
1.58M
      xmlXPathCompOpEval(ctxt, op);
11190
1.58M
      if (ctxt->error != XPATH_EXPRESSION_OK)
11191
3.41k
    return(-1);
11192
11193
1.57M
      resObj = xmlXPathValuePop(ctxt);
11194
1.57M
      if (resObj == NULL)
11195
0
    return(-1);
11196
1.57M
      break;
11197
4.06M
    }
11198
11199
1.81M
    if (resObj) {
11200
1.81M
  int res;
11201
11202
1.81M
  if (resObj->type == XPATH_BOOLEAN) {
11203
531k
      res = resObj->boolval;
11204
1.27M
  } else if (isPredicate) {
11205
      /*
11206
      * For predicates a result of type "number" is handled
11207
      * differently:
11208
      * SPEC XPath 1.0:
11209
      * "If the result is a number, the result will be converted
11210
      *  to true if the number is equal to the context position
11211
      *  and will be converted to false otherwise;"
11212
      */
11213
1.27M
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11214
1.27M
  } else {
11215
0
      res = xmlXPathCastToBoolean(resObj);
11216
0
  }
11217
1.81M
  xmlXPathReleaseObject(ctxt->context, resObj);
11218
1.81M
  return(res);
11219
1.81M
    }
11220
11221
0
    return(0);
11222
1.81M
}
11223
11224
#ifdef XPATH_STREAMING
11225
/**
11226
 * Evaluate the Precompiled Streamable XPath expression in the given context.
11227
 *
11228
 * @param pctxt  the XPath parser context with the compiled expression
11229
 */
11230
static int
11231
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
11232
          xmlXPathObjectPtr *resultSeq, int toBool)
11233
{
11234
    int max_depth, min_depth;
11235
    int from_root;
11236
    int ret, depth;
11237
    int eval_all_nodes;
11238
    xmlNodePtr cur = NULL, limit = NULL;
11239
    xmlStreamCtxtPtr patstream = NULL;
11240
    xmlXPathContextPtr ctxt = pctxt->context;
11241
11242
    if ((ctxt == NULL) || (comp == NULL))
11243
        return(-1);
11244
    max_depth = xmlPatternMaxDepth(comp);
11245
    if (max_depth == -1)
11246
        return(-1);
11247
    if (max_depth == -2)
11248
        max_depth = 10000;
11249
    min_depth = xmlPatternMinDepth(comp);
11250
    if (min_depth == -1)
11251
        return(-1);
11252
    from_root = xmlPatternFromRoot(comp);
11253
    if (from_root < 0)
11254
        return(-1);
11255
11256
    if (! toBool) {
11257
  if (resultSeq == NULL)
11258
      return(-1);
11259
  *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
11260
  if (*resultSeq == NULL)
11261
      return(-1);
11262
    }
11263
11264
    /*
11265
     * handle the special cases of "/" amd "." being matched
11266
     */
11267
    if (min_depth == 0) {
11268
        int res;
11269
11270
  if (from_root) {
11271
      /* Select "/" */
11272
      if (toBool)
11273
    return(1);
11274
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11275
                                           (xmlNodePtr) ctxt->doc);
11276
  } else {
11277
      /* Select "self::node()" */
11278
      if (toBool)
11279
    return(1);
11280
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11281
                                           ctxt->node);
11282
  }
11283
11284
        if (res < 0)
11285
            xmlXPathPErrMemory(pctxt);
11286
    }
11287
    if (max_depth == 0) {
11288
  return(0);
11289
    }
11290
11291
    if (from_root) {
11292
        cur = (xmlNodePtr)ctxt->doc;
11293
    } else if (ctxt->node != NULL) {
11294
        switch (ctxt->node->type) {
11295
            case XML_ELEMENT_NODE:
11296
            case XML_DOCUMENT_NODE:
11297
            case XML_DOCUMENT_FRAG_NODE:
11298
            case XML_HTML_DOCUMENT_NODE:
11299
          cur = ctxt->node;
11300
    break;
11301
            case XML_ATTRIBUTE_NODE:
11302
            case XML_TEXT_NODE:
11303
            case XML_CDATA_SECTION_NODE:
11304
            case XML_ENTITY_REF_NODE:
11305
            case XML_ENTITY_NODE:
11306
            case XML_PI_NODE:
11307
            case XML_COMMENT_NODE:
11308
            case XML_NOTATION_NODE:
11309
            case XML_DTD_NODE:
11310
            case XML_DOCUMENT_TYPE_NODE:
11311
            case XML_ELEMENT_DECL:
11312
            case XML_ATTRIBUTE_DECL:
11313
            case XML_ENTITY_DECL:
11314
            case XML_NAMESPACE_DECL:
11315
            case XML_XINCLUDE_START:
11316
            case XML_XINCLUDE_END:
11317
    break;
11318
  }
11319
  limit = cur;
11320
    }
11321
    if (cur == NULL) {
11322
        return(0);
11323
    }
11324
11325
    patstream = xmlPatternGetStreamCtxt(comp);
11326
    if (patstream == NULL) {
11327
        xmlXPathPErrMemory(pctxt);
11328
  return(-1);
11329
    }
11330
11331
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11332
11333
    if (from_root) {
11334
  ret = xmlStreamPush(patstream, NULL, NULL);
11335
  if (ret < 0) {
11336
  } else if (ret == 1) {
11337
      if (toBool)
11338
    goto return_1;
11339
      if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
11340
                xmlXPathPErrMemory(pctxt);
11341
  }
11342
    }
11343
    depth = 0;
11344
    goto scan_children;
11345
next_node:
11346
    do {
11347
        if (ctxt->opLimit != 0) {
11348
            if (ctxt->opCount >= ctxt->opLimit) {
11349
                xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
11350
                xmlFreeStreamCtxt(patstream);
11351
                return(-1);
11352
            }
11353
            ctxt->opCount++;
11354
        }
11355
11356
  switch (cur->type) {
11357
      case XML_ELEMENT_NODE:
11358
      case XML_TEXT_NODE:
11359
      case XML_CDATA_SECTION_NODE:
11360
      case XML_COMMENT_NODE:
11361
      case XML_PI_NODE:
11362
    if (cur->type == XML_ELEMENT_NODE) {
11363
        ret = xmlStreamPush(patstream, cur->name,
11364
        (cur->ns ? cur->ns->href : NULL));
11365
    } else if (eval_all_nodes)
11366
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11367
    else
11368
        break;
11369
11370
    if (ret < 0) {
11371
        xmlXPathPErrMemory(pctxt);
11372
    } else if (ret == 1) {
11373
        if (toBool)
11374
      goto return_1;
11375
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11376
                                                 cur) < 0)
11377
                        xmlXPathPErrMemory(pctxt);
11378
    }
11379
    if ((cur->children == NULL) || (depth >= max_depth)) {
11380
        ret = xmlStreamPop(patstream);
11381
        while (cur->next != NULL) {
11382
      cur = cur->next;
11383
      if ((cur->type != XML_ENTITY_DECL) &&
11384
          (cur->type != XML_DTD_NODE))
11385
          goto next_node;
11386
        }
11387
    }
11388
      default:
11389
    break;
11390
  }
11391
11392
scan_children:
11393
  if (cur->type == XML_NAMESPACE_DECL) break;
11394
  if ((cur->children != NULL) && (depth < max_depth)) {
11395
      /*
11396
       * Do not descend on entities declarations
11397
       */
11398
      if (cur->children->type != XML_ENTITY_DECL) {
11399
    cur = cur->children;
11400
    depth++;
11401
    /*
11402
     * Skip DTDs
11403
     */
11404
    if (cur->type != XML_DTD_NODE)
11405
        continue;
11406
      }
11407
  }
11408
11409
  if (cur == limit)
11410
      break;
11411
11412
  while (cur->next != NULL) {
11413
      cur = cur->next;
11414
      if ((cur->type != XML_ENTITY_DECL) &&
11415
    (cur->type != XML_DTD_NODE))
11416
    goto next_node;
11417
  }
11418
11419
  do {
11420
      cur = cur->parent;
11421
      depth--;
11422
      if ((cur == NULL) || (cur == limit) ||
11423
                (cur->type == XML_DOCUMENT_NODE))
11424
          goto done;
11425
      if (cur->type == XML_ELEMENT_NODE) {
11426
    ret = xmlStreamPop(patstream);
11427
      } else if ((eval_all_nodes) &&
11428
    ((cur->type == XML_TEXT_NODE) ||
11429
     (cur->type == XML_CDATA_SECTION_NODE) ||
11430
     (cur->type == XML_COMMENT_NODE) ||
11431
     (cur->type == XML_PI_NODE)))
11432
      {
11433
    ret = xmlStreamPop(patstream);
11434
      }
11435
      if (cur->next != NULL) {
11436
    cur = cur->next;
11437
    break;
11438
      }
11439
  } while (cur != NULL);
11440
11441
    } while ((cur != NULL) && (depth >= 0));
11442
11443
done:
11444
11445
    if (patstream)
11446
  xmlFreeStreamCtxt(patstream);
11447
    return(0);
11448
11449
return_1:
11450
    if (patstream)
11451
  xmlFreeStreamCtxt(patstream);
11452
    return(1);
11453
}
11454
#endif /* XPATH_STREAMING */
11455
11456
/**
11457
 * Evaluate the Precompiled XPath expression in the given context.
11458
 *
11459
 * @param ctxt  the XPath parser context with the compiled expression
11460
 * @param toBool  evaluate to a boolean result
11461
 */
11462
static int
11463
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
11464
35.1k
{
11465
35.1k
    xmlXPathCompExprPtr comp;
11466
35.1k
    int oldDepth;
11467
11468
35.1k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11469
0
  return(-1);
11470
11471
35.1k
    if (ctxt->valueTab == NULL) {
11472
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11473
0
        int valueMax = 1;
11474
#else
11475
        int valueMax = 10;
11476
#endif
11477
11478
  /* Allocate the value stack */
11479
0
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11480
0
  if (ctxt->valueTab == NULL) {
11481
0
      xmlXPathPErrMemory(ctxt);
11482
0
      return(-1);
11483
0
  }
11484
0
  ctxt->valueNr = 0;
11485
0
  ctxt->valueMax = valueMax;
11486
0
  ctxt->value = NULL;
11487
0
    }
11488
#ifdef XPATH_STREAMING
11489
    if (ctxt->comp->stream) {
11490
  int res;
11491
11492
  if (toBool) {
11493
      /*
11494
      * Evaluation to boolean result.
11495
      */
11496
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
11497
      if (res != -1)
11498
    return(res);
11499
  } else {
11500
      xmlXPathObjectPtr resObj = NULL;
11501
11502
      /*
11503
      * Evaluation to a sequence.
11504
      */
11505
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
11506
11507
      if ((res != -1) && (resObj != NULL)) {
11508
    xmlXPathValuePush(ctxt, resObj);
11509
    return(0);
11510
      }
11511
      if (resObj != NULL)
11512
    xmlXPathReleaseObject(ctxt->context, resObj);
11513
  }
11514
  /*
11515
  * QUESTION TODO: This falls back to normal XPath evaluation
11516
  * if res == -1. Is this intended?
11517
  */
11518
    }
11519
#endif
11520
35.1k
    comp = ctxt->comp;
11521
35.1k
    if (comp->last < 0) {
11522
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11523
0
  return(-1);
11524
0
    }
11525
35.1k
    oldDepth = ctxt->context->depth;
11526
35.1k
    if (toBool)
11527
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11528
0
      &comp->steps[comp->last], 0));
11529
35.1k
    else
11530
35.1k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11531
35.1k
    ctxt->context->depth = oldDepth;
11532
11533
35.1k
    return(0);
11534
35.1k
}
11535
11536
/************************************************************************
11537
 *                  *
11538
 *      Public interfaces       *
11539
 *                  *
11540
 ************************************************************************/
11541
11542
/**
11543
 * Evaluate a predicate result for the current node.
11544
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11545
 * the result to a boolean. If the result is a number, the result will
11546
 * be converted to true if the number is equal to the position of the
11547
 * context node in the context node list (as returned by the position
11548
 * function) and will be converted to false otherwise; if the result
11549
 * is not a number, then the result will be converted as if by a call
11550
 * to the boolean function.
11551
 *
11552
 * @param ctxt  the XPath context
11553
 * @param res  the Predicate Expression evaluation result
11554
 * @returns 1 if predicate is true, 0 otherwise
11555
 */
11556
int
11557
0
xmlXPathEvalPredicate(xmlXPathContext *ctxt, xmlXPathObject *res) {
11558
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
11559
0
    switch (res->type) {
11560
0
        case XPATH_BOOLEAN:
11561
0
      return(res->boolval);
11562
0
        case XPATH_NUMBER:
11563
0
      return(res->floatval == ctxt->proximityPosition);
11564
0
        case XPATH_NODESET:
11565
0
        case XPATH_XSLT_TREE:
11566
0
      if (res->nodesetval == NULL)
11567
0
    return(0);
11568
0
      return(res->nodesetval->nodeNr != 0);
11569
0
        case XPATH_STRING:
11570
0
      return((res->stringval != NULL) &&
11571
0
             (xmlStrlen(res->stringval) != 0));
11572
0
        default:
11573
0
      break;
11574
0
    }
11575
0
    return(0);
11576
0
}
11577
11578
/**
11579
 * Evaluate a predicate result for the current node.
11580
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11581
 * the result to a boolean. If the result is a number, the result will
11582
 * be converted to true if the number is equal to the position of the
11583
 * context node in the context node list (as returned by the position
11584
 * function) and will be converted to false otherwise; if the result
11585
 * is not a number, then the result will be converted as if by a call
11586
 * to the boolean function.
11587
 *
11588
 * @param ctxt  the XPath Parser context
11589
 * @param res  the Predicate Expression evaluation result
11590
 * @returns 1 if predicate is true, 0 otherwise
11591
 */
11592
int
11593
xmlXPathEvaluatePredicateResult(xmlXPathParserContext *ctxt,
11594
3.03M
                                xmlXPathObject *res) {
11595
3.03M
    if ((ctxt == NULL) || (res == NULL)) return(0);
11596
3.03M
    switch (res->type) {
11597
0
        case XPATH_BOOLEAN:
11598
0
      return(res->boolval);
11599
1.08M
        case XPATH_NUMBER:
11600
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
11601
      return((res->floatval == ctxt->context->proximityPosition) &&
11602
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
11603
#else
11604
1.08M
      return(res->floatval == ctxt->context->proximityPosition);
11605
0
#endif
11606
934k
        case XPATH_NODESET:
11607
934k
        case XPATH_XSLT_TREE:
11608
934k
      if (res->nodesetval == NULL)
11609
0
    return(0);
11610
934k
      return(res->nodesetval->nodeNr != 0);
11611
1.00M
        case XPATH_STRING:
11612
1.00M
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11613
0
        default:
11614
0
      break;
11615
3.03M
    }
11616
0
    return(0);
11617
3.03M
}
11618
11619
#ifdef XPATH_STREAMING
11620
/**
11621
 * Try to compile the XPath expression as a streamable subset.
11622
 *
11623
 * @param ctxt  an XPath context
11624
 * @param str  the XPath expression
11625
 * @returns the compiled expression or NULL if failed to compile.
11626
 */
11627
static xmlXPathCompExprPtr
11628
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11629
    /*
11630
     * Optimization: use streaming patterns when the XPath expression can
11631
     * be compiled to a stream lookup
11632
     */
11633
    xmlPatternPtr stream;
11634
    xmlXPathCompExprPtr comp;
11635
    xmlDictPtr dict = NULL;
11636
    const xmlChar **namespaces = NULL;
11637
    xmlNsPtr ns;
11638
    int i, j;
11639
11640
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11641
        (!xmlStrchr(str, '@'))) {
11642
  const xmlChar *tmp;
11643
        int res;
11644
11645
  /*
11646
   * We don't try to handle expressions using the verbose axis
11647
   * specifiers ("::"), just the simplified form at this point.
11648
   * Additionally, if there is no list of namespaces available and
11649
   *  there's a ":" in the expression, indicating a prefixed QName,
11650
   *  then we won't try to compile either. xmlPatterncompile() needs
11651
   *  to have a list of namespaces at compilation time in order to
11652
   *  compile prefixed name tests.
11653
   */
11654
  tmp = xmlStrchr(str, ':');
11655
  if ((tmp != NULL) &&
11656
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
11657
      return(NULL);
11658
11659
  if (ctxt != NULL) {
11660
      dict = ctxt->dict;
11661
      if (ctxt->nsNr > 0) {
11662
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
11663
    if (namespaces == NULL) {
11664
        xmlXPathErrMemory(ctxt);
11665
        return(NULL);
11666
    }
11667
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11668
        ns = ctxt->namespaces[j];
11669
        namespaces[i++] = ns->href;
11670
        namespaces[i++] = ns->prefix;
11671
    }
11672
    namespaces[i++] = NULL;
11673
    namespaces[i] = NULL;
11674
      }
11675
  }
11676
11677
  res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
11678
                                    &stream);
11679
  if (namespaces != NULL) {
11680
      xmlFree((xmlChar **)namespaces);
11681
  }
11682
        if (res < 0) {
11683
            xmlXPathErrMemory(ctxt);
11684
            return(NULL);
11685
        }
11686
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11687
      comp = xmlXPathNewCompExpr();
11688
      if (comp == NULL) {
11689
    xmlXPathErrMemory(ctxt);
11690
          xmlFreePattern(stream);
11691
    return(NULL);
11692
      }
11693
      comp->stream = stream;
11694
      comp->dict = dict;
11695
      if (comp->dict)
11696
    xmlDictReference(comp->dict);
11697
      return(comp);
11698
  }
11699
  xmlFreePattern(stream);
11700
    }
11701
    return(NULL);
11702
}
11703
#endif /* XPATH_STREAMING */
11704
11705
static void
11706
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
11707
                           xmlXPathStepOpPtr op)
11708
6.26M
{
11709
6.26M
    xmlXPathCompExprPtr comp = pctxt->comp;
11710
6.26M
    xmlXPathContextPtr ctxt;
11711
11712
    /*
11713
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11714
    * internal representation.
11715
    */
11716
11717
6.26M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11718
6.26M
        (op->ch1 != -1) &&
11719
6.26M
        (op->ch2 == -1 /* no predicate */))
11720
1.85M
    {
11721
1.85M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11722
11723
1.85M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11724
1.85M
            ((xmlXPathAxisVal) prevop->value ==
11725
85.7k
                AXIS_DESCENDANT_OR_SELF) &&
11726
1.85M
            (prevop->ch2 == -1) &&
11727
1.85M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11728
1.85M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11729
37.9k
        {
11730
            /*
11731
            * This is a "descendant-or-self::node()" without predicates.
11732
            * Try to eliminate it.
11733
            */
11734
11735
37.9k
            switch ((xmlXPathAxisVal) op->value) {
11736
20.4k
                case AXIS_CHILD:
11737
20.4k
                case AXIS_DESCENDANT:
11738
                    /*
11739
                    * Convert "descendant-or-self::node()/child::" or
11740
                    * "descendant-or-self::node()/descendant::" to
11741
                    * "descendant::"
11742
                    */
11743
20.4k
                    op->ch1   = prevop->ch1;
11744
20.4k
                    op->value = AXIS_DESCENDANT;
11745
20.4k
                    break;
11746
5
                case AXIS_SELF:
11747
4.40k
                case AXIS_DESCENDANT_OR_SELF:
11748
                    /*
11749
                    * Convert "descendant-or-self::node()/self::" or
11750
                    * "descendant-or-self::node()/descendant-or-self::" to
11751
                    * to "descendant-or-self::"
11752
                    */
11753
4.40k
                    op->ch1   = prevop->ch1;
11754
4.40k
                    op->value = AXIS_DESCENDANT_OR_SELF;
11755
4.40k
                    break;
11756
13.0k
                default:
11757
13.0k
                    break;
11758
37.9k
            }
11759
37.9k
  }
11760
1.85M
    }
11761
11762
    /* OP_VALUE has invalid ch1. */
11763
6.26M
    if (op->op == XPATH_OP_VALUE)
11764
122k
        return;
11765
11766
    /* Recurse */
11767
6.14M
    ctxt = pctxt->context;
11768
6.14M
    if (ctxt != NULL) {
11769
6.14M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11770
7.46k
            return;
11771
6.13M
        ctxt->depth += 1;
11772
6.13M
    }
11773
6.13M
    if (op->ch1 != -1)
11774
4.23M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11775
6.13M
    if (op->ch2 != -1)
11776
1.99M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11777
6.13M
    if (ctxt != NULL)
11778
6.13M
        ctxt->depth -= 1;
11779
6.13M
}
11780
11781
/**
11782
 * Compile an XPath expression
11783
 *
11784
 * @param ctxt  an XPath context
11785
 * @param str  the XPath expression
11786
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11787
 *         the caller has to free the object.
11788
 */
11789
xmlXPathCompExpr *
11790
8.58k
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11791
8.58k
    xmlXPathParserContextPtr pctxt;
11792
8.58k
    xmlXPathContextPtr tmpctxt = NULL;
11793
8.58k
    xmlXPathCompExprPtr comp;
11794
8.58k
    int oldDepth = 0;
11795
11796
8.58k
    if (str == NULL)
11797
0
        return(NULL);
11798
11799
#ifdef XPATH_STREAMING
11800
    comp = xmlXPathTryStreamCompile(ctxt, str);
11801
    if (comp != NULL)
11802
        return(comp);
11803
#endif
11804
11805
8.58k
    xmlInitParser();
11806
11807
    /*
11808
     * We need an xmlXPathContext for the depth check.
11809
     */
11810
8.58k
    if (ctxt == NULL) {
11811
0
        tmpctxt = xmlXPathNewContext(NULL);
11812
0
        if (tmpctxt == NULL)
11813
0
            return(NULL);
11814
0
        ctxt = tmpctxt;
11815
0
    }
11816
11817
8.58k
    pctxt = xmlXPathNewParserContext(str, ctxt);
11818
8.58k
    if (pctxt == NULL) {
11819
0
        if (tmpctxt != NULL)
11820
0
            xmlXPathFreeContext(tmpctxt);
11821
0
        return NULL;
11822
0
    }
11823
11824
8.58k
    oldDepth = ctxt->depth;
11825
8.58k
    xmlXPathCompileExpr(pctxt, 1);
11826
8.58k
    ctxt->depth = oldDepth;
11827
11828
8.58k
    if( pctxt->error != XPATH_EXPRESSION_OK )
11829
1.67k
    {
11830
1.67k
        xmlXPathFreeParserContext(pctxt);
11831
1.67k
        if (tmpctxt != NULL)
11832
0
            xmlXPathFreeContext(tmpctxt);
11833
1.67k
        return(NULL);
11834
1.67k
    }
11835
11836
6.90k
    if (*pctxt->cur != 0) {
11837
  /*
11838
   * aleksey: in some cases this line prints *second* error message
11839
   * (see bug #78858) and probably this should be fixed.
11840
   * However, we are not sure that all error messages are printed
11841
   * out in other places. It's not critical so we leave it as-is for now
11842
   */
11843
397
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11844
397
  comp = NULL;
11845
6.51k
    } else {
11846
6.51k
  comp = pctxt->comp;
11847
6.51k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11848
6.40k
            if (ctxt != NULL)
11849
6.40k
                oldDepth = ctxt->depth;
11850
6.40k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11851
6.40k
            if (ctxt != NULL)
11852
6.40k
                ctxt->depth = oldDepth;
11853
6.40k
  }
11854
6.51k
  pctxt->comp = NULL;
11855
6.51k
    }
11856
6.90k
    xmlXPathFreeParserContext(pctxt);
11857
6.90k
    if (tmpctxt != NULL)
11858
0
        xmlXPathFreeContext(tmpctxt);
11859
11860
6.90k
    if (comp != NULL) {
11861
6.51k
  comp->expr = xmlStrdup(str);
11862
6.51k
    }
11863
6.90k
    return(comp);
11864
8.58k
}
11865
11866
/**
11867
 * Compile an XPath expression
11868
 *
11869
 * @param str  the XPath expression
11870
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11871
 *         the caller has to free the object.
11872
 */
11873
xmlXPathCompExpr *
11874
0
xmlXPathCompile(const xmlChar *str) {
11875
0
    return(xmlXPathCtxtCompile(NULL, str));
11876
0
}
11877
11878
/**
11879
 * Evaluate the Precompiled XPath expression in the given context.
11880
 * The caller has to free `resObj`.
11881
 *
11882
 * @param comp  the compiled XPath expression
11883
 * @param ctxt  the XPath context
11884
 * @param resObjPtr  the resulting XPath object or NULL
11885
 * @param toBool  1 if only a boolean result is requested
11886
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11887
 *         the caller has to free the object.
11888
 */
11889
static int
11890
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
11891
           xmlXPathContextPtr ctxt,
11892
           xmlXPathObjectPtr *resObjPtr,
11893
           int toBool)
11894
6.51k
{
11895
6.51k
    xmlXPathParserContextPtr pctxt;
11896
6.51k
    xmlXPathObjectPtr resObj = NULL;
11897
6.51k
    int res;
11898
11899
6.51k
    if (comp == NULL)
11900
0
  return(-1);
11901
6.51k
    xmlInitParser();
11902
11903
6.51k
    xmlResetError(&ctxt->lastError);
11904
11905
6.51k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11906
6.51k
    if (pctxt == NULL)
11907
0
        return(-1);
11908
6.51k
    res = xmlXPathRunEval(pctxt, toBool);
11909
11910
6.51k
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11911
5.29k
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11912
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11913
5.29k
        else if (!toBool)
11914
5.29k
            resObj = xmlXPathValuePop(pctxt);
11915
5.29k
    }
11916
11917
6.51k
    if (resObjPtr)
11918
6.51k
        *resObjPtr = resObj;
11919
0
    else
11920
0
        xmlXPathReleaseObject(ctxt, resObj);
11921
11922
6.51k
    pctxt->comp = NULL;
11923
6.51k
    xmlXPathFreeParserContext(pctxt);
11924
11925
6.51k
    return(res);
11926
6.51k
}
11927
11928
/**
11929
 * Evaluate the Precompiled XPath expression in the given context.
11930
 *
11931
 * @param comp  the compiled XPath expression
11932
 * @param ctx  the XPath context
11933
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11934
 *         the caller has to free the object.
11935
 */
11936
xmlXPathObject *
11937
xmlXPathCompiledEval(xmlXPathCompExpr *comp, xmlXPathContext *ctx)
11938
6.51k
{
11939
6.51k
    xmlXPathObjectPtr res = NULL;
11940
11941
6.51k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11942
6.51k
    return(res);
11943
6.51k
}
11944
11945
/**
11946
 * Applies the XPath boolean() function on the result of the given
11947
 * compiled expression.
11948
 *
11949
 * @param comp  the compiled XPath expression
11950
 * @param ctxt  the XPath context
11951
 * @returns 1 if the expression evaluated to true, 0 if to false and
11952
 *         -1 in API and internal errors.
11953
 */
11954
int
11955
xmlXPathCompiledEvalToBoolean(xmlXPathCompExpr *comp,
11956
            xmlXPathContext *ctxt)
11957
0
{
11958
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
11959
0
}
11960
11961
/**
11962
 * Parse and evaluate an XPath expression in the given context,
11963
 * then push the result on the context stack
11964
 *
11965
 * @deprecated Internal function, don't use.
11966
 *
11967
 * @param ctxt  the XPath Parser context
11968
 */
11969
void
11970
36.1k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
11971
#ifdef XPATH_STREAMING
11972
    xmlXPathCompExprPtr comp;
11973
#endif
11974
36.1k
    int oldDepth = 0;
11975
11976
36.1k
    if ((ctxt == NULL) || (ctxt->context == NULL))
11977
0
        return;
11978
36.1k
    if (ctxt->context->lastError.code != 0)
11979
398
        return;
11980
11981
#ifdef XPATH_STREAMING
11982
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11983
    if ((comp == NULL) &&
11984
        (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
11985
        xmlXPathPErrMemory(ctxt);
11986
        return;
11987
    }
11988
    if (comp != NULL) {
11989
        if (ctxt->comp != NULL)
11990
      xmlXPathFreeCompExpr(ctxt->comp);
11991
        ctxt->comp = comp;
11992
    } else
11993
#endif
11994
35.7k
    {
11995
35.7k
        if (ctxt->context != NULL)
11996
35.7k
            oldDepth = ctxt->context->depth;
11997
35.7k
  xmlXPathCompileExpr(ctxt, 1);
11998
35.7k
        if (ctxt->context != NULL)
11999
35.7k
            ctxt->context->depth = oldDepth;
12000
35.7k
        CHECK_ERROR;
12001
12002
        /* Check for trailing characters. */
12003
29.7k
        if (*ctxt->cur != 0)
12004
28.5k
            XP_ERROR(XPATH_EXPR_ERROR);
12005
12006
28.5k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12007
28.3k
            if (ctxt->context != NULL)
12008
28.3k
                oldDepth = ctxt->context->depth;
12009
28.3k
      xmlXPathOptimizeExpression(ctxt,
12010
28.3k
    &ctxt->comp->steps[ctxt->comp->last]);
12011
28.3k
            if (ctxt->context != NULL)
12012
28.3k
                ctxt->context->depth = oldDepth;
12013
28.3k
        }
12014
28.5k
    }
12015
12016
0
    xmlXPathRunEval(ctxt, 0);
12017
28.5k
}
12018
12019
/**
12020
 * Evaluate the XPath Location Path in the given context.
12021
 *
12022
 * @param str  the XPath expression
12023
 * @param ctx  the XPath context
12024
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12025
 *         the caller has to free the object.
12026
 */
12027
xmlXPathObject *
12028
0
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
12029
0
    xmlXPathParserContextPtr ctxt;
12030
0
    xmlXPathObjectPtr res;
12031
12032
0
    if (ctx == NULL)
12033
0
        return(NULL);
12034
12035
0
    xmlInitParser();
12036
12037
0
    xmlResetError(&ctx->lastError);
12038
12039
0
    ctxt = xmlXPathNewParserContext(str, ctx);
12040
0
    if (ctxt == NULL)
12041
0
        return NULL;
12042
0
    xmlXPathEvalExpr(ctxt);
12043
12044
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12045
0
  res = NULL;
12046
0
    } else if (ctxt->valueNr != 1) {
12047
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12048
0
  res = NULL;
12049
0
    } else {
12050
0
  res = xmlXPathValuePop(ctxt);
12051
0
    }
12052
12053
0
    xmlXPathFreeParserContext(ctxt);
12054
0
    return(res);
12055
0
}
12056
12057
/**
12058
 * Sets 'node' as the context node. The node must be in the same
12059
 * document as that associated with the context.
12060
 *
12061
 * @param node  the node to to use as the context node
12062
 * @param ctx  the XPath context
12063
 * @returns -1 in case of error or 0 if successful
12064
 */
12065
int
12066
0
xmlXPathSetContextNode(xmlNode *node, xmlXPathContext *ctx) {
12067
0
    if ((node == NULL) || (ctx == NULL))
12068
0
        return(-1);
12069
12070
0
    if (node->doc == ctx->doc) {
12071
0
        ctx->node = node;
12072
0
  return(0);
12073
0
    }
12074
0
    return(-1);
12075
0
}
12076
12077
/**
12078
 * Evaluate the XPath Location Path in the given context. The node 'node'
12079
 * is set as the context node. The context node is not restored.
12080
 *
12081
 * @param node  the node to to use as the context node
12082
 * @param str  the XPath expression
12083
 * @param ctx  the XPath context
12084
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12085
 *         the caller has to free the object.
12086
 */
12087
xmlXPathObject *
12088
0
xmlXPathNodeEval(xmlNode *node, const xmlChar *str, xmlXPathContext *ctx) {
12089
0
    if (str == NULL)
12090
0
        return(NULL);
12091
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
12092
0
        return(NULL);
12093
0
    return(xmlXPathEval(str, ctx));
12094
0
}
12095
12096
/**
12097
 * Alias for #xmlXPathEval.
12098
 *
12099
 * @param str  the XPath expression
12100
 * @param ctxt  the XPath context
12101
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12102
 *         the caller has to free the object.
12103
 */
12104
xmlXPathObject *
12105
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContext *ctxt) {
12106
0
    return(xmlXPathEval(str, ctxt));
12107
0
}
12108
12109
/**
12110
 * Registers all default XPath functions in this context
12111
 *
12112
 * @deprecated No-op since 2.14.0.
12113
 *
12114
 * @param ctxt  the XPath context
12115
 */
12116
void
12117
xmlXPathRegisterAllFunctions(xmlXPathContext *ctxt ATTRIBUTE_UNUSED)
12118
0
{
12119
0
}
12120
12121
#endif /* LIBXML_XPATH_ENABLED */