Coverage Report

Created: 2026-01-10 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxml2/xpath.c
Line
Count
Source
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
47.8k
#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
307
#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
2.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
4.73M
#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
56
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
5.58k
#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
3.93k
xmlXPathSFComputeHash(const xmlChar *name) {
187
3.93k
    unsigned hashValue = 5381;
188
3.93k
    const xmlChar *ptr;
189
190
29.6k
    for (ptr = name; *ptr; ptr++)
191
25.7k
        hashValue = hashValue * 33 + *ptr;
192
193
3.93k
    return(hashValue);
194
3.93k
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
2
xmlInitXPathInternal(void) {
202
2
    size_t i;
203
204
2
#if defined(NAN) && defined(INFINITY)
205
2
    xmlXPathNAN = NAN;
206
2
    xmlXPathPINF = INFINITY;
207
2
    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
130
    for (i = 0; i < SF_HASH_SIZE; i++)
221
128
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
56
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
54
        const char *name = xmlXPathStandardFunctions[i].name;
225
54
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
68
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
14
            bucketIndex += 1;
229
14
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
14
        }
232
233
54
        xmlXPathSFHash[bucketIndex] = i;
234
54
    }
235
2
}
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
857k
xmlXPathIsNaN(double val) {
251
857k
#ifdef isnan
252
857k
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
857k
}
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
69.4k
xmlXPathIsInf(double val) {
266
69.4k
#ifdef isinf
267
69.4k
    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
69.4k
}
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
20.9M
#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
18.6M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
18.6M
    int depth1, depth2;
311
18.6M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
18.6M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
18.6M
    xmlNodePtr cur, root;
314
18.6M
    XML_INTPTR_T l1, l2;
315
316
18.6M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
18.6M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
18.6M
    switch (node1->type) {
326
11.8M
  case XML_ELEMENT_NODE:
327
11.8M
      if (node2->type == XML_ELEMENT_NODE) {
328
5.81M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
0
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
0
        (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
5.81M
        goto turtle_comparison;
340
5.81M
      }
341
6.06M
      break;
342
6.06M
  case XML_ATTRIBUTE_NODE:
343
4.33k
      precedence1 = 1; /* element is owner */
344
4.33k
      miscNode1 = node1;
345
4.33k
      node1 = node1->parent;
346
4.33k
      misc = 1;
347
4.33k
      break;
348
6.43M
  case XML_TEXT_NODE:
349
6.43M
  case XML_CDATA_SECTION_NODE:
350
6.44M
  case XML_COMMENT_NODE:
351
6.44M
  case XML_PI_NODE: {
352
6.44M
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
6.44M
      if (node1->prev != NULL) {
357
6.17M
    do {
358
6.17M
        node1 = node1->prev;
359
6.17M
        if (node1->type == XML_ELEMENT_NODE) {
360
6.14M
      precedence1 = 3; /* element in prev-sibl axis */
361
6.14M
      break;
362
6.14M
        }
363
30.2k
        if (node1->prev == NULL) {
364
3.11k
      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
3.11k
      node1 = node1->parent;
370
3.11k
      break;
371
3.11k
        }
372
30.2k
    } while (1);
373
6.14M
      } else {
374
294k
    precedence1 = 2; /* element is parent */
375
294k
    node1 = node1->parent;
376
294k
      }
377
6.44M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
6.44M
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
6.44M
    node1 = miscNode1;
383
6.44M
    precedence1 = 0;
384
6.44M
      } else
385
0
    misc = 1;
386
6.44M
  }
387
6.44M
      break;
388
238k
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
238k
      return(1);
393
80.3k
  default:
394
80.3k
      break;
395
18.6M
    }
396
12.5M
    switch (node2->type) {
397
5.07M
  case XML_ELEMENT_NODE:
398
5.07M
      break;
399
4.55k
  case XML_ATTRIBUTE_NODE:
400
4.55k
      precedence2 = 1; /* element is owner */
401
4.55k
      miscNode2 = node2;
402
4.55k
      node2 = node2->parent;
403
4.55k
      misc = 1;
404
4.55k
      break;
405
7.04M
  case XML_TEXT_NODE:
406
7.04M
  case XML_CDATA_SECTION_NODE:
407
7.04M
  case XML_COMMENT_NODE:
408
7.04M
  case XML_PI_NODE: {
409
7.04M
      miscNode2 = node2;
410
7.04M
      if (node2->prev != NULL) {
411
6.41M
    do {
412
6.41M
        node2 = node2->prev;
413
6.41M
        if (node2->type == XML_ELEMENT_NODE) {
414
6.38M
      precedence2 = 3; /* element in prev-sibl axis */
415
6.38M
      break;
416
6.38M
        }
417
28.9k
        if (node2->prev == NULL) {
418
3.11k
      precedence2 = 2; /* element is parent */
419
3.11k
      node2 = node2->parent;
420
3.11k
      break;
421
3.11k
        }
422
28.9k
    } while (1);
423
6.39M
      } else {
424
658k
    precedence2 = 2; /* element is parent */
425
658k
    node2 = node2->parent;
426
658k
      }
427
7.04M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
7.04M
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
7.04M
      {
430
7.04M
    node2 = miscNode2;
431
7.04M
    precedence2 = 0;
432
7.04M
      } else
433
0
    misc = 1;
434
7.04M
  }
435
7.04M
      break;
436
3.01k
  case XML_NAMESPACE_DECL:
437
3.01k
      return(1);
438
456k
  default:
439
456k
      break;
440
12.5M
    }
441
12.5M
    if (misc) {
442
7.93k
  if (node1 == node2) {
443
1.43k
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
692
    cur = miscNode2->prev;
449
900
    while (cur != NULL) {
450
640
        if (cur == miscNode1)
451
432
      return(1);
452
208
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
208
        cur = cur->prev;
455
208
    }
456
260
    return (-1);
457
746
      } 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
746
    if (precedence1 < precedence2)
464
393
        return(1);
465
353
    else
466
353
        return(-1);
467
746
      }
468
1.43k
  }
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
6.49k
  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
6.49k
  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
6.49k
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
12.5M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
6.06M
  (node2->type == XML_ELEMENT_NODE) &&
501
5.84k
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
0
  (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
18.4M
turtle_comparison:
514
515
18.4M
    if (node1 == node2->prev)
516
7.38M
  return(1);
517
11.0M
    if (node1 == node2->next)
518
391k
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
70.9M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
62.0M
  if (cur->parent == node1)
524
1.71M
      return(1);
525
60.3M
  depth2++;
526
60.3M
    }
527
8.91M
    root = cur;
528
68.8M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
63.3M
  if (cur->parent == node2)
530
3.41M
      return(-1);
531
59.9M
  depth1++;
532
59.9M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
5.50M
    if (root != cur) {
537
0
  return(-2);
538
0
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
17.8M
    while (depth1 > depth2) {
543
12.3M
  depth1--;
544
12.3M
  node1 = node1->parent;
545
12.3M
    }
546
7.06M
    while (depth2 > depth1) {
547
1.56M
  depth2--;
548
1.56M
  node2 = node2->parent;
549
1.56M
    }
550
5.57M
    while (node1->parent != node2->parent) {
551
74.3k
  node1 = node1->parent;
552
74.3k
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
74.3k
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
74.3k
    }
557
    /*
558
     * Find who's first.
559
     */
560
5.50M
    if (node1 == node2->prev)
561
117k
  return(1);
562
5.38M
    if (node1 == node2->next)
563
2.42M
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
2.95M
    if ((node1->type == XML_ELEMENT_NODE) &&
568
2.32M
  (node2->type == XML_ELEMENT_NODE) &&
569
1.65M
  (0 > XML_NODE_SORT_VALUE(node1)) &&
570
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
571
0
  (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
63.1M
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
61.2M
  if (cur == node2)
583
1.01M
      return(1);
584
1.94M
    return(-1); /* assume there is no sibling list corruption */
585
2.95M
}
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
2.94M
#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
18.6M
    {
607
18.6M
        int res = xmlXPathCmpNodesExt(x, y);
608
18.6M
        return res == -2 ? res : -res;
609
18.6M
    }
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
18.6M
#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
460
    { 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
23.1k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
23.1k
       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
3.10k
{
678
3.10k
    if (ctxt == NULL)
679
0
        return;
680
3.10k
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
3.10k
                        &ctxt->lastError);
682
3.10k
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
1.71k
{
692
1.71k
    if (ctxt == NULL)
693
0
        return;
694
1.71k
    ctxt->error = XPATH_MEMORY_ERROR;
695
1.71k
    xmlXPathErrMemory(ctxt->context);
696
1.71k
}
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
23.1k
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
23.1k
    va_list ap;
709
23.1k
    xmlStructuredErrorFunc schannel = NULL;
710
23.1k
    xmlGenericErrorFunc channel = NULL;
711
23.1k
    void *data = NULL;
712
23.1k
    xmlNodePtr node = NULL;
713
23.1k
    int res;
714
715
23.1k
    if (ctxt == NULL)
716
0
        return;
717
23.1k
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
23.1k
    if (ctxt->error != 0)
721
6.67k
        return;
722
723
16.5k
    ctxt->error = code;
724
725
16.5k
    if (ctxt->context != NULL) {
726
16.5k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
16.5k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
16.5k
        xmlResetError(err);
734
735
16.5k
        err->domain = XML_FROM_XPATH;
736
16.5k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
16.5k
        err->level = XML_ERR_ERROR;
738
16.5k
        if (ctxt->base != NULL) {
739
16.5k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
16.5k
            if (err->str1 == NULL) {
741
97
                xmlXPathPErrMemory(ctxt);
742
97
                return;
743
97
            }
744
16.5k
        }
745
16.4k
        err->int1 = ctxt->cur - ctxt->base;
746
16.4k
        err->node = ctxt->context->debugNode;
747
748
16.4k
        schannel = ctxt->context->error;
749
16.4k
        data = ctxt->context->userData;
750
16.4k
        node = ctxt->context->debugNode;
751
16.4k
    }
752
753
16.4k
    if (schannel == NULL) {
754
16.4k
        channel = xmlGenericError;
755
16.4k
        data = xmlGenericErrorContext;
756
16.4k
    }
757
758
16.4k
    va_start(ap, fmt);
759
16.4k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
16.4k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
16.4k
                         XML_ERR_ERROR, NULL, 0,
762
16.4k
                         (const char *) ctxt->base, NULL, NULL,
763
16.4k
                         ctxt->cur - ctxt->base, 0,
764
16.4k
                         fmt, ap);
765
16.4k
    va_end(ap);
766
16.4k
    if (res < 0)
767
244
        xmlXPathPErrMemory(ctxt);
768
16.4k
}
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
22.7k
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
22.7k
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
22.7k
}
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
0
              int line ATTRIBUTE_UNUSED, int no) {
792
0
    xmlXPathErr(ctxt, no);
793
0
}
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
38.9M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
38.9M
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
38.9M
    if ((opCount > xpctxt->opLimit) ||
807
38.9M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
74
        xpctxt->opCount = xpctxt->opLimit;
809
74
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
74
        return(-1);
811
74
    }
812
813
38.9M
    xpctxt->opCount += opCount;
814
38.9M
    return(0);
815
38.9M
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
38.6M
    ((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
26.1k
xmlXPathNewCompExpr(void) {
941
26.1k
    xmlXPathCompExprPtr cur;
942
943
26.1k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
26.1k
    if (cur == NULL)
945
215
  return(NULL);
946
25.8k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
25.8k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
25.8k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
25.8k
    cur->nbStep = 0;
953
25.8k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
25.8k
                                     sizeof(xmlXPathStepOp));
955
25.8k
    if (cur->steps == NULL) {
956
77
  xmlFree(cur);
957
77
  return(NULL);
958
77
    }
959
25.8k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
25.8k
    cur->last = -1;
961
25.8k
    return(cur);
962
25.8k
}
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
25.8k
{
972
25.8k
    xmlXPathStepOpPtr op;
973
25.8k
    int i;
974
975
25.8k
    if (comp == NULL)
976
0
        return;
977
25.8k
    if (comp->dict == NULL) {
978
458k
  for (i = 0; i < comp->nbStep; i++) {
979
432k
      op = &comp->steps[i];
980
432k
      if (op->value4 != NULL) {
981
22.4k
    if (op->op == XPATH_OP_VALUE)
982
13.9k
        xmlXPathFreeObject(op->value4);
983
8.51k
    else
984
8.51k
        xmlFree(op->value4);
985
22.4k
      }
986
432k
      if (op->value5 != NULL)
987
59.2k
    xmlFree(op->value5);
988
432k
  }
989
25.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
25.8k
    if (comp->steps != NULL) {
1000
25.8k
        xmlFree(comp->steps);
1001
25.8k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
25.8k
    if (comp->expr != NULL) {
1008
0
        xmlFree(comp->expr);
1009
0
    }
1010
1011
25.8k
    xmlFree(comp);
1012
25.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
432k
   int value2, int value3, void *value4, void *value5) {
1032
432k
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
432k
    if (comp->nbStep >= comp->maxStep) {
1034
47.8k
  xmlXPathStepOp *real;
1035
47.8k
        int newSize;
1036
1037
47.8k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
47.8k
                                  10, XPATH_MAX_STEPS);
1039
47.8k
        if (newSize < 0) {
1040
0
      xmlXPathPErrMemory(ctxt);
1041
0
      return(-1);
1042
0
        }
1043
47.8k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
47.8k
  if (real == NULL) {
1045
21
      xmlXPathPErrMemory(ctxt);
1046
21
      return(-1);
1047
21
  }
1048
47.8k
  comp->steps = real;
1049
47.8k
  comp->maxStep = newSize;
1050
47.8k
    }
1051
432k
    comp->last = comp->nbStep;
1052
432k
    comp->steps[comp->nbStep].ch1 = ch1;
1053
432k
    comp->steps[comp->nbStep].ch2 = ch2;
1054
432k
    comp->steps[comp->nbStep].op = op;
1055
432k
    comp->steps[comp->nbStep].value = value;
1056
432k
    comp->steps[comp->nbStep].value2 = value2;
1057
432k
    comp->steps[comp->nbStep].value3 = value3;
1058
432k
    if ((comp->dict != NULL) &&
1059
0
        ((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
432k
    } else {
1074
432k
  comp->steps[comp->nbStep].value4 = value4;
1075
432k
  comp->steps[comp->nbStep].value5 = value5;
1076
432k
    }
1077
432k
    comp->steps[comp->nbStep].cache = NULL;
1078
432k
    return(comp->nbStep++);
1079
432k
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
84.6k
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
84.6k
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
42.0k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
42.0k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
143k
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
143k
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
47.0k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
47.0k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
115k
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
115k
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
115k
      (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
26.1k
{
1516
26.1k
    xmlXPathContextCachePtr ret;
1517
1518
26.1k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
26.1k
    if (ret == NULL)
1520
630
  return(NULL);
1521
25.5k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
25.5k
    ret->maxNodeset = 100;
1523
25.5k
    ret->maxMisc = 100;
1524
25.5k
    return(ret);
1525
26.1k
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
12.8k
{
1530
46.0k
    while (list != NULL) {
1531
33.2k
        xmlXPathObjectPtr next;
1532
1533
33.2k
        next = (void *) list->stringval;
1534
1535
33.2k
  if (list->nodesetval != NULL) {
1536
23.4k
      if (list->nodesetval->nodeTab != NULL)
1537
20.8k
    xmlFree(list->nodesetval->nodeTab);
1538
23.4k
      xmlFree(list->nodesetval);
1539
23.4k
  }
1540
33.2k
  xmlFree(list);
1541
1542
33.2k
        list = next;
1543
33.2k
    }
1544
12.8k
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
25.5k
{
1549
25.5k
    if (cache == NULL)
1550
0
  return;
1551
25.5k
    if (cache->nodesetObjs)
1552
7.96k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
25.5k
    if (cache->miscObjs)
1554
4.84k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
25.5k
    xmlFree(cache);
1556
25.5k
}
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
26.1k
{
1582
26.1k
    if (ctxt == NULL)
1583
0
  return(-1);
1584
26.1k
    if (active) {
1585
26.1k
  xmlXPathContextCachePtr cache;
1586
1587
26.1k
  if (ctxt->cache == NULL) {
1588
26.1k
      ctxt->cache = xmlXPathNewCache();
1589
26.1k
      if (ctxt->cache == NULL) {
1590
630
                xmlXPathErrMemory(ctxt);
1591
630
    return(-1);
1592
630
            }
1593
26.1k
  }
1594
25.5k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
25.5k
  if (options == 0) {
1596
25.5k
      if (value < 0)
1597
0
    value = 100;
1598
25.5k
      cache->maxNodeset = value;
1599
25.5k
      cache->maxMisc = value;
1600
25.5k
  }
1601
25.5k
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
25.5k
    return(0);
1606
26.1k
}
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
1.19M
{
1621
1.19M
    xmlXPathObjectPtr ret;
1622
1.19M
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
1.19M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
965k
  xmlXPathContextCachePtr cache =
1626
965k
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
965k
  if (cache->miscObjs != NULL) {
1629
931k
      ret = cache->miscObjs;
1630
931k
            cache->miscObjs = (void *) ret->stringval;
1631
931k
            cache->numMisc -= 1;
1632
931k
            ret->stringval = NULL;
1633
931k
      ret->type = XPATH_NODESET;
1634
931k
      ret->nodesetval = val;
1635
931k
      return(ret);
1636
931k
  }
1637
965k
    }
1638
1639
264k
    ret = xmlXPathWrapNodeSet(val);
1640
264k
    if (ret == NULL)
1641
75
        xmlXPathPErrMemory(pctxt);
1642
264k
    return(ret);
1643
1.19M
}
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
56.4k
{
1656
56.4k
    xmlXPathObjectPtr ret;
1657
56.4k
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
56.4k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
35.7k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
35.7k
  if (cache->miscObjs != NULL) {
1663
32.3k
      ret = cache->miscObjs;
1664
32.3k
            cache->miscObjs = (void *) ret->stringval;
1665
32.3k
            cache->numMisc -= 1;
1666
32.3k
      ret->type = XPATH_STRING;
1667
32.3k
      ret->stringval = val;
1668
32.3k
      return(ret);
1669
32.3k
  }
1670
35.7k
    }
1671
1672
24.0k
    ret = xmlXPathWrapString(val);
1673
24.0k
    if (ret == NULL)
1674
29
        xmlXPathPErrMemory(pctxt);
1675
24.0k
    return(ret);
1676
56.4k
}
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
1.38M
{
1690
1.38M
    xmlXPathObjectPtr ret;
1691
1.38M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
1.38M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
1.14M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
1.14M
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
1.12M
      ret = cache->nodesetObjs;
1701
1.12M
            cache->nodesetObjs = (void *) ret->stringval;
1702
1.12M
            cache->numNodeset -= 1;
1703
1.12M
            ret->stringval = NULL;
1704
1.12M
      ret->type = XPATH_NODESET;
1705
1.12M
      ret->boolval = 0;
1706
1.12M
      if (val) {
1707
1.12M
    if ((ret->nodesetval->nodeMax == 0) ||
1708
1.11M
        (val->type == XML_NAMESPACE_DECL))
1709
137k
    {
1710
137k
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
13
                        xmlXPathPErrMemory(pctxt);
1712
990k
    } else {
1713
990k
        ret->nodesetval->nodeTab[0] = val;
1714
990k
        ret->nodesetval->nodeNr = 1;
1715
990k
    }
1716
1.12M
      }
1717
1.12M
      return(ret);
1718
1.12M
  } else if (cache->miscObjs != NULL) {
1719
8.49k
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
8.49k
      set = xmlXPathNodeSetCreate(val);
1725
8.49k
      if (set == NULL) {
1726
3
                xmlXPathPErrMemory(pctxt);
1727
3
    return(NULL);
1728
3
      }
1729
1730
8.48k
      ret = cache->miscObjs;
1731
8.48k
            cache->miscObjs = (void *) ret->stringval;
1732
8.48k
            cache->numMisc -= 1;
1733
8.48k
            ret->stringval = NULL;
1734
8.48k
      ret->type = XPATH_NODESET;
1735
8.48k
      ret->boolval = 0;
1736
8.48k
      ret->nodesetval = set;
1737
8.48k
      return(ret);
1738
8.49k
  }
1739
1.14M
    }
1740
249k
    ret = xmlXPathNewNodeSet(val);
1741
249k
    if (ret == NULL)
1742
89
        xmlXPathPErrMemory(pctxt);
1743
249k
    return(ret);
1744
1.38M
}
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
619k
{
1757
619k
    xmlXPathObjectPtr ret;
1758
619k
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
619k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
52.4k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
52.4k
  if (cache->miscObjs != NULL) {
1764
47.7k
            xmlChar *copy;
1765
1766
47.7k
            if (val == NULL)
1767
284
                val = BAD_CAST "";
1768
47.7k
            copy = xmlStrdup(val);
1769
47.7k
            if (copy == NULL) {
1770
13
                xmlXPathPErrMemory(pctxt);
1771
13
                return(NULL);
1772
13
            }
1773
1774
47.7k
      ret = cache->miscObjs;
1775
47.7k
            cache->miscObjs = (void *) ret->stringval;
1776
47.7k
            cache->numMisc -= 1;
1777
47.7k
      ret->type = XPATH_STRING;
1778
47.7k
            ret->stringval = copy;
1779
47.7k
      return(ret);
1780
47.7k
  }
1781
52.4k
    }
1782
1783
572k
    ret = xmlXPathNewString(val);
1784
572k
    if (ret == NULL)
1785
7
        xmlXPathPErrMemory(pctxt);
1786
572k
    return(ret);
1787
619k
}
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
7.66k
{
1800
7.66k
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
7.66k
}
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
574k
{
1814
574k
    xmlXPathObjectPtr ret;
1815
574k
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
574k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
459k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
459k
  if (cache->miscObjs != NULL) {
1821
258k
      ret = cache->miscObjs;
1822
258k
            cache->miscObjs = (void *) ret->stringval;
1823
258k
            cache->numMisc -= 1;
1824
258k
            ret->stringval = NULL;
1825
258k
      ret->type = XPATH_BOOLEAN;
1826
258k
      ret->boolval = (val != 0);
1827
258k
      return(ret);
1828
258k
  }
1829
459k
    }
1830
1831
315k
    ret = xmlXPathNewBoolean(val);
1832
315k
    if (ret == NULL)
1833
16
        xmlXPathPErrMemory(pctxt);
1834
315k
    return(ret);
1835
574k
}
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.13M
{
1848
2.13M
    xmlXPathObjectPtr ret;
1849
2.13M
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
2.13M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
1.00M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
1.00M
  if (cache->miscObjs != NULL) {
1855
795k
      ret = cache->miscObjs;
1856
795k
            cache->miscObjs = (void *) ret->stringval;
1857
795k
            cache->numMisc -= 1;
1858
795k
            ret->stringval = NULL;
1859
795k
      ret->type = XPATH_NUMBER;
1860
795k
      ret->floatval = val;
1861
795k
      return(ret);
1862
795k
  }
1863
1.00M
    }
1864
1865
1.34M
    ret = xmlXPathNewFloat(val);
1866
1.34M
    if (ret == NULL)
1867
58
        xmlXPathPErrMemory(pctxt);
1868
1.34M
    return(ret);
1869
2.13M
}
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.10M
{
1882
1.10M
    xmlXPathObjectPtr ret;
1883
1.10M
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
1.10M
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
1.10M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
532k
  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
17.1k
      case XPATH_STRING:
1901
17.1k
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
515k
      case XPATH_NUMBER:
1905
515k
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
532k
  }
1909
532k
    }
1910
568k
    ret = xmlXPathObjectCopy(val);
1911
568k
    if (ret == NULL)
1912
0
        xmlXPathPErrMemory(pctxt);
1913
568k
    return(ret);
1914
1.10M
}
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
1.37M
                             xmlXPathObjectPtr val) {
1932
1.37M
    double ret = 0.0;
1933
1934
1.37M
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
1.37M
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
85.9k
    case XPATH_NODESET:
1941
85.9k
    case XPATH_XSLT_TREE: {
1942
85.9k
        xmlChar *str;
1943
1944
85.9k
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
85.9k
        if (str == NULL) {
1946
34
            xmlXPathPErrMemory(ctxt);
1947
34
            ret = xmlXPathNAN;
1948
85.8k
        } else {
1949
85.8k
      ret = xmlXPathCastStringToNumber(str);
1950
85.8k
            xmlFree(str);
1951
85.8k
        }
1952
85.9k
  break;
1953
85.9k
    }
1954
1.14M
    case XPATH_STRING:
1955
1.14M
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
1.14M
  break;
1957
136k
    case XPATH_NUMBER:
1958
136k
  ret = val->floatval;
1959
136k
  break;
1960
6.67k
    case XPATH_BOOLEAN:
1961
6.67k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
6.67k
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
1.37M
    }
1968
1.37M
    return(ret);
1969
1.37M
}
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
7.84M
{
1980
7.84M
    xmlXPathObjectPtr ret;
1981
1982
7.84M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
22.9k
        return (NULL);
1984
1985
7.82M
    ctxt->valueNr--;
1986
7.82M
    if (ctxt->valueNr > 0)
1987
2.16M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
5.66M
    else
1989
5.66M
        ctxt->value = NULL;
1990
7.82M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
7.82M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
7.82M
    return (ret);
1993
7.84M
}
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
7.83M
{
2008
7.83M
    if (ctxt == NULL) return(-1);
2009
7.83M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
315
        xmlXPathPErrMemory(ctxt);
2014
315
        return(-1);
2015
315
    }
2016
7.83M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
307
        xmlXPathObjectPtr *tmp;
2018
307
        int newSize;
2019
2020
307
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
307
                                  10, XPATH_MAX_STACK_DEPTH);
2022
307
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
307
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
307
        if (tmp == NULL) {
2029
3
            xmlXPathPErrMemory(ctxt);
2030
3
            xmlXPathFreeObject(value);
2031
3
            return (-1);
2032
3
        }
2033
304
  ctxt->valueTab = tmp;
2034
304
        ctxt->valueMax = newSize;
2035
304
    }
2036
7.83M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
7.83M
    ctxt->value = value;
2038
7.83M
    return (ctxt->valueNr++);
2039
7.83M
}
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
3.80M
#define CUR (*ctxt->cur)
2194
27.4k
#define SKIP(val) ctxt->cur += (val)
2195
475k
#define NXT(val) ctxt->cur[(val)]
2196
16.9k
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
1.94M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
1.43M
#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
2.74k
#define UPPER_DOUBLE 1E9
2213
1.76k
#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
1.65k
#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
6.20k
{
2230
6.20k
    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
6.20k
    default:
2240
6.20k
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
6.20k
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
6.20k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
5.23k
                   (number == (int) number)) {
2248
3.46k
      char work[30];
2249
3.46k
      char *ptr, *cur;
2250
3.46k
      int value = (int) number;
2251
2252
3.46k
            ptr = &buffer[0];
2253
3.46k
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
3.46k
      } else {
2256
3.46k
    snprintf(work, 29, "%d", value);
2257
3.46k
    cur = &work[0];
2258
9.43k
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
5.97k
        *ptr++ = *cur++;
2260
5.97k
    }
2261
3.46k
      }
2262
3.46k
      if (ptr - buffer < buffersize) {
2263
3.46k
    *ptr = 0;
2264
3.46k
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
3.46k
  } 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
2.74k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
2.74k
      int integer_place, fraction_place;
2280
2.74k
      char *ptr;
2281
2.74k
      char *after_fraction;
2282
2.74k
      double absolute_value;
2283
2.74k
      int size;
2284
2285
2.74k
      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
2.74k
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
1.76k
      (absolute_value < LOWER_DOUBLE)) &&
2294
1.65k
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
1.65k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
1.65k
    fraction_place = DBL_DIG - 1;
2298
1.65k
    size = snprintf(work, sizeof(work),"%*.*e",
2299
1.65k
       integer_place, fraction_place, number);
2300
8.71k
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
1.65k
      }
2303
1.09k
      else {
2304
    /* Use regular notation */
2305
1.09k
    if (absolute_value > 0.0) {
2306
1.09k
        integer_place = (int)log10(absolute_value);
2307
1.09k
        if (integer_place > 0)
2308
217
            fraction_place = DBL_DIG - integer_place - 1;
2309
875
        else
2310
875
            fraction_place = DBL_DIG - integer_place;
2311
1.09k
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
1.09k
    size = snprintf(work, sizeof(work), "%0.*f",
2315
1.09k
        fraction_place, number);
2316
1.09k
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
3.71k
      while (work[0] == ' ') {
2320
20.4k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
973
    size--;
2322
973
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
2.74k
      after_fraction = work + size;
2326
2.74k
      ptr = after_fraction;
2327
35.6k
      while (*(--ptr) == '0')
2328
32.8k
    ;
2329
2.74k
      if (*ptr != '.')
2330
1.75k
          ptr++;
2331
9.80k
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
2.74k
      size = strlen(work) + 1;
2335
2.74k
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
2.74k
      memmove(buffer, work, size);
2340
2.74k
  }
2341
6.20k
  break;
2342
6.20k
    }
2343
6.20k
}
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
0
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
0
    XML_INTPTR_T count = 0;
2366
0
    xmlNodePtr cur;
2367
2368
0
    if (doc == NULL)
2369
0
  return(-1);
2370
0
    cur = doc->children;
2371
0
    while (cur != NULL) {
2372
0
  if (cur->type == XML_ELEMENT_NODE) {
2373
0
            count += 1;
2374
0
            cur->content = XML_INT_TO_PTR(-count);
2375
0
      if (cur->children != NULL) {
2376
0
    cur = cur->children;
2377
0
    continue;
2378
0
      }
2379
0
  }
2380
0
  if (cur->next != NULL) {
2381
0
      cur = cur->next;
2382
0
      continue;
2383
0
  }
2384
0
  do {
2385
0
      cur = cur->parent;
2386
0
      if (cur == NULL)
2387
0
    break;
2388
0
      if (cur == (xmlNodePtr) doc) {
2389
0
    cur = NULL;
2390
0
    break;
2391
0
      }
2392
0
      if (cur->next != NULL) {
2393
0
    cur = cur->next;
2394
0
    break;
2395
0
      }
2396
0
  } while (cur != NULL);
2397
0
    }
2398
0
    return(count);
2399
0
}
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
110k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
110k
    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
110k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
110k
#endif /* WITH_TIM_SORT */
2591
110k
}
2592
2593
3.38M
#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.54M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
1.54M
    xmlNsPtr cur;
2606
2607
1.54M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
1.54M
    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.54M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
1.54M
    if (cur == NULL)
2617
19
  return(NULL);
2618
1.54M
    memset(cur, 0, sizeof(xmlNs));
2619
1.54M
    cur->type = XML_NAMESPACE_DECL;
2620
1.54M
    if (ns->href != NULL) {
2621
1.54M
  cur->href = xmlStrdup(ns->href);
2622
1.54M
        if (cur->href == NULL) {
2623
15
            xmlFree(cur);
2624
15
            return(NULL);
2625
15
        }
2626
1.54M
    }
2627
1.54M
    if (ns->prefix != NULL) {
2628
1.07M
  cur->prefix = xmlStrdup(ns->prefix);
2629
1.07M
        if (cur->prefix == NULL) {
2630
15
            xmlFree((xmlChar *) cur->href);
2631
15
            xmlFree(cur);
2632
15
            return(NULL);
2633
15
        }
2634
1.07M
    }
2635
1.54M
    cur->next = (xmlNsPtr) node;
2636
1.54M
    return((xmlNodePtr) cur);
2637
1.54M
}
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.54M
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
1.54M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
1.54M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
1.54M
  if (ns->href != NULL)
2653
1.54M
      xmlFree((xmlChar *)ns->href);
2654
1.54M
  if (ns->prefix != NULL)
2655
1.07M
      xmlFree((xmlChar *)ns->prefix);
2656
1.54M
  xmlFree(ns);
2657
1.54M
    }
2658
1.54M
}
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
1.79M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
1.79M
    xmlNodeSetPtr ret;
2669
2670
1.79M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
1.79M
    if (ret == NULL)
2672
130
  return(NULL);
2673
1.79M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
1.79M
    if (val != NULL) {
2675
258k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
258k
               sizeof(xmlNodePtr));
2677
258k
  if (ret->nodeTab == NULL) {
2678
33
      xmlFree(ret);
2679
33
      return(NULL);
2680
33
  }
2681
258k
  memset(ret->nodeTab, 0 ,
2682
258k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
258k
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
258k
  if (val->type == XML_NAMESPACE_DECL) {
2685
28.5k
      xmlNsPtr ns = (xmlNsPtr) val;
2686
28.5k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2687
2688
28.5k
            if (nsNode == NULL) {
2689
4
                xmlXPathFreeNodeSet(ret);
2690
4
                return(NULL);
2691
4
            }
2692
28.5k
      ret->nodeTab[ret->nodeNr++] = nsNode;
2693
28.5k
  } else
2694
229k
      ret->nodeTab[ret->nodeNr++] = val;
2695
258k
    }
2696
1.79M
    return(ret);
2697
1.79M
}
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
2.24M
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
2.24M
    xmlNodePtr *temp;
2737
2.24M
    int newSize;
2738
2739
2.24M
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
2.24M
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
2.24M
    if (newSize < 0)
2742
0
        return(-1);
2743
2.24M
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
2.24M
    if (temp == NULL)
2745
257
        return(-1);
2746
2.24M
    cur->nodeMax = newSize;
2747
2.24M
    cur->nodeTab = temp;
2748
2749
2.24M
    return(0);
2750
2.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
1.25M
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
1.25M
    int i;
2763
1.25M
    xmlNodePtr nsNode;
2764
2765
1.25M
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
1.25M
        (ns->type != XML_NAMESPACE_DECL) ||
2767
1.25M
  (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
3.04M
    for (i = 0;i < cur->nodeNr;i++) {
2775
1.79M
        if ((cur->nodeTab[i] != NULL) &&
2776
1.79M
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
1.79M
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
1.79M
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
1.79M
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
1.25M
    if (cur->nodeNr >= cur->nodeMax) {
2786
15.8k
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
8
            return(-1);
2788
15.8k
    }
2789
1.25M
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
1.25M
    if(nsNode == NULL)
2791
19
        return(-1);
2792
1.25M
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
1.25M
    return(0);
2794
1.25M
}
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
3.59k
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
3.59k
    int i;
2806
2807
3.59k
    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
7.37k
    for (i = 0;i < cur->nodeNr;i++)
2814
4.27k
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
3.09k
    if (cur->nodeNr >= cur->nodeMax) {
2820
2.82k
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
7
            return(-1);
2822
2.82k
    }
2823
2824
3.09k
    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
3.09k
  cur->nodeTab[cur->nodeNr++] = val;
2833
3.09k
    return(0);
2834
3.09k
}
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
25.1M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
25.1M
    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
25.1M
    if (cur->nodeNr >= cur->nodeMax) {
2853
1.84M
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
111
            return(-1);
2855
1.84M
    }
2856
2857
25.1M
    if (val->type == XML_NAMESPACE_DECL) {
2858
257k
  xmlNsPtr ns = (xmlNsPtr) val;
2859
257k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
257k
        if (nsNode == NULL)
2862
8
            return(-1);
2863
257k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
257k
    } else
2865
24.8M
  cur->nodeTab[cur->nodeNr++] = val;
2866
25.1M
    return(0);
2867
25.1M
}
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
405k
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
405k
    int i, j, initNr, skip;
2882
405k
    xmlNodePtr n1, n2;
2883
2884
405k
    if (val1 == NULL) {
2885
2
  val1 = xmlXPathNodeSetCreate(NULL);
2886
2
        if (val1 == NULL)
2887
0
            return (NULL);
2888
2
    }
2889
405k
    if (val2 == NULL)
2890
35
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
405k
    initNr = val1->nodeNr;
2894
2895
2.84M
    for (i = 0;i < val2->nodeNr;i++) {
2896
2.43M
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
2.43M
  skip = 0;
2901
8.49M
  for (j = 0; j < initNr; j++) {
2902
6.26M
      n1 = val1->nodeTab[j];
2903
6.26M
      if (n1 == n2) {
2904
200k
    skip = 1;
2905
200k
    break;
2906
6.06M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
2.26M
           (n2->type == XML_NAMESPACE_DECL)) {
2908
2.24M
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2909
15.2k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2910
15.2k
      ((xmlNsPtr) n2)->prefix)))
2911
12.4k
    {
2912
12.4k
        skip = 1;
2913
12.4k
        break;
2914
12.4k
    }
2915
2.24M
      }
2916
6.26M
  }
2917
2.43M
  if (skip)
2918
212k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
2.22M
        if (val1->nodeNr >= val1->nodeMax) {
2924
239k
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
27
                goto error;
2926
239k
        }
2927
2.22M
  if (n2->type == XML_NAMESPACE_DECL) {
2928
7.87k
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
7.87k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
7.87k
            if (nsNode == NULL)
2932
18
                goto error;
2933
7.85k
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
7.85k
  } else
2935
2.21M
      val1->nodeTab[val1->nodeNr++] = n2;
2936
2.22M
    }
2937
2938
405k
    return(val1);
2939
2940
45
error:
2941
45
    xmlXPathFreeNodeSet(val1);
2942
45
    return(NULL);
2943
405k
}
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
526k
{
2959
526k
    {
2960
526k
  int i, j, initNbSet1;
2961
526k
  xmlNodePtr n1, n2;
2962
2963
526k
  initNbSet1 = set1->nodeNr;
2964
14.4M
  for (i = 0;i < set2->nodeNr;i++) {
2965
13.9M
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
3.51G
      for (j = 0; j < initNbSet1; j++) {
2970
3.51G
    n1 = set1->nodeTab[j];
2971
3.51G
    if (n1 == n2) {
2972
12.0M
        goto skip_node;
2973
3.49G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
17.6M
        (n2->type == XML_NAMESPACE_DECL))
2975
16.9M
    {
2976
16.9M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
64.1k
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
64.1k
      ((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
16.9M
    }
2987
3.51G
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
1.90M
            if (set1->nodeNr >= set1->nodeMax) {
2992
92.9k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
43
                    goto error;
2994
92.9k
            }
2995
1.90M
      set1->nodeTab[set1->nodeNr++] = n2;
2996
13.9M
skip_node:
2997
13.9M
            set2->nodeTab[i] = NULL;
2998
13.9M
  }
2999
526k
    }
3000
526k
    set2->nodeNr = 0;
3001
526k
    return(set1);
3002
3003
43
error:
3004
43
    xmlXPathFreeNodeSet(set1);
3005
43
    xmlXPathNodeSetClear(set2, 1);
3006
43
    return(NULL);
3007
526k
}
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
395k
{
3022
395k
    {
3023
395k
  int i;
3024
395k
  xmlNodePtr n2;
3025
3026
2.01M
  for (i = 0;i < set2->nodeNr;i++) {
3027
1.61M
      n2 = set2->nodeTab[i];
3028
1.61M
            if (set1->nodeNr >= set1->nodeMax) {
3029
44.6k
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
61
                    goto error;
3031
44.6k
            }
3032
1.61M
      set1->nodeTab[set1->nodeNr++] = n2;
3033
1.61M
            set2->nodeTab[i] = NULL;
3034
1.61M
  }
3035
395k
    }
3036
395k
    set2->nodeNr = 0;
3037
395k
    return(set1);
3038
3039
61
error:
3040
61
    xmlXPathFreeNodeSet(set1);
3041
61
    xmlXPathNodeSetClear(set2, 1);
3042
61
    return(NULL);
3043
395k
}
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
1.77M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
1.77M
    if (obj == NULL) return;
3103
1.77M
    if (obj->nodeTab != NULL) {
3104
567k
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
15.0M
  for (i = 0;i < obj->nodeNr;i++)
3108
14.4M
      if ((obj->nodeTab[i] != NULL) &&
3109
14.4M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
1.31M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
567k
  xmlFree(obj->nodeTab);
3112
567k
    }
3113
1.77M
    xmlFree(obj);
3114
1.77M
}
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
7.88k
{
3128
7.88k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
7.88k
    else if ((hasNsNodes)) {
3131
7.34k
  int i;
3132
7.34k
  xmlNodePtr node;
3133
3134
269k
  for (i = pos; i < set->nodeNr; i++) {
3135
262k
      node = set->nodeTab[i];
3136
262k
      if ((node != NULL) &&
3137
261k
    (node->type == XML_NAMESPACE_DECL))
3138
11.0k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
262k
  }
3140
7.34k
    }
3141
7.88k
    set->nodeNr = pos;
3142
7.88k
}
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
1.29k
{
3155
1.29k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
1.29k
}
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
10.2k
{
3168
10.2k
    int i;
3169
10.2k
    xmlNodePtr node;
3170
3171
10.2k
    if ((set == NULL) || (set->nodeNr <= 1))
3172
0
  return;
3173
659k
    for (i = 0; i < set->nodeNr - 1; i++) {
3174
649k
        node = set->nodeTab[i];
3175
649k
        if ((node != NULL) &&
3176
649k
            (node->type == XML_NAMESPACE_DECL))
3177
752
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3178
649k
    }
3179
10.2k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3180
10.2k
    set->nodeNr = 1;
3181
10.2k
}
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
251k
xmlXPathNewNodeSet(xmlNode *val) {
3192
251k
    xmlXPathObjectPtr ret;
3193
3194
251k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
251k
    if (ret == NULL)
3196
27
  return(NULL);
3197
251k
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
251k
    ret->type = XPATH_NODESET;
3199
251k
    ret->boolval = 0;
3200
251k
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
251k
    if (ret->nodesetval == NULL) {
3202
69
        xmlFree(ret);
3203
69
        return(NULL);
3204
69
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
251k
    return(ret);
3207
251k
}
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
264k
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
264k
    xmlXPathObjectPtr ret;
3269
3270
264k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
264k
    if (ret == NULL) {
3272
75
        xmlXPathFreeNodeSet(val);
3273
75
  return(NULL);
3274
75
    }
3275
264k
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
264k
    ret->type = XPATH_NODESET;
3277
264k
    ret->nodesetval = val;
3278
264k
    return(ret);
3279
264k
}
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
3.87k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
3.87k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
3.87k
}
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
3.87k
       const xmlChar *ns_uri) {
3759
3.87k
    xmlXPathFunction ret;
3760
3.87k
    void *payload;
3761
3762
3.87k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
3.87k
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
3.87k
    if (ns_uri == NULL) {
3768
3.87k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
5.38k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
5.07k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
5.07k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
5.07k
                       (char *) name) == 0)
3775
3.56k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
1.51k
            bucketIndex += 1;
3778
1.51k
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
1.51k
        }
3781
3.87k
    }
3782
3783
315
    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
315
    if (ctxt->funcHash == NULL)
3793
315
  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
315
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
26.1k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
26.1k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
26.1k
    xmlHashFree(ctxt->funcHash, NULL);
3812
26.1k
    ctxt->funcHash = NULL;
3813
26.1k
}
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
64
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
64
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
64
    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
64
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
64
}
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
65
       const xmlChar *ns_uri) {
3917
65
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
65
    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
65
    if (ctxt->varHash == NULL)
3929
65
  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
26.1k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
26.1k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
26.1k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
26.1k
    ctxt->varHash = NULL;
3948
26.1k
}
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
500
         const xmlChar *ns_uri) {
3962
500
    xmlChar *copy;
3963
3964
500
    if (ctxt == NULL)
3965
0
  return(-1);
3966
500
    if (prefix == NULL)
3967
0
  return(-1);
3968
500
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
500
    if (ctxt->nsHash == NULL)
3972
79
  ctxt->nsHash = xmlHashCreate(10);
3973
500
    if (ctxt->nsHash == NULL) {
3974
2
        xmlXPathErrMemory(ctxt);
3975
2
  return(-1);
3976
2
    }
3977
498
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
498
    copy = xmlStrdup(ns_uri);
3982
498
    if (copy == NULL) {
3983
3
        xmlXPathErrMemory(ctxt);
3984
3
        return(-1);
3985
3
    }
3986
495
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
495
                           xmlHashDefaultDeallocator) < 0) {
3988
2
        xmlXPathErrMemory(ctxt);
3989
2
        xmlFree(copy);
3990
2
        return(-1);
3991
2
    }
3992
3993
493
    return(0);
3994
495
}
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
6.36k
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
6.36k
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
6.36k
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
6.36k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
6.24k
  return(XML_XML_NAMESPACE);
4013
4014
113
    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
113
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
113
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
26.1k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
26.1k
    if (ctxt == NULL)
4035
0
  return;
4036
4037
26.1k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
26.1k
    ctxt->nsHash = NULL;
4039
26.1k
}
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
1.34M
xmlXPathNewFloat(double val) {
4057
1.34M
    xmlXPathObjectPtr ret;
4058
4059
1.34M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
1.34M
    if (ret == NULL)
4061
58
  return(NULL);
4062
1.34M
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
1.34M
    ret->type = XPATH_NUMBER;
4064
1.34M
    ret->floatval = val;
4065
1.34M
    return(ret);
4066
1.34M
}
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
315k
xmlXPathNewBoolean(int val) {
4076
315k
    xmlXPathObjectPtr ret;
4077
4078
315k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
315k
    if (ret == NULL)
4080
16
  return(NULL);
4081
315k
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
315k
    ret->type = XPATH_BOOLEAN;
4083
315k
    ret->boolval = (val != 0);
4084
315k
    return(ret);
4085
315k
}
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
574k
xmlXPathNewString(const xmlChar *val) {
4095
574k
    xmlXPathObjectPtr ret;
4096
4097
574k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
574k
    if (ret == NULL)
4099
20
  return(NULL);
4100
574k
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
574k
    ret->type = XPATH_STRING;
4102
574k
    if (val == NULL)
4103
225
        val = BAD_CAST "";
4104
574k
    ret->stringval = xmlStrdup(val);
4105
574k
    if (ret->stringval == NULL) {
4106
8
        xmlFree(ret);
4107
8
        return(NULL);
4108
8
    }
4109
574k
    return(ret);
4110
574k
}
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
24.0k
xmlXPathWrapString (xmlChar *val) {
4122
24.0k
    xmlXPathObjectPtr ret;
4123
4124
24.0k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
24.0k
    if (ret == NULL) {
4126
29
        xmlFree(val);
4127
29
  return(NULL);
4128
29
    }
4129
24.0k
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
24.0k
    ret->type = XPATH_STRING;
4131
24.0k
    ret->stringval = val;
4132
24.0k
    return(ret);
4133
24.0k
}
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
568k
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
568k
    xmlXPathObjectPtr ret;
4185
4186
568k
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
568k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
568k
    if (ret == NULL)
4191
0
  return(NULL);
4192
568k
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
568k
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
9.66k
  case XPATH_NUMBER:
4196
9.66k
      break;
4197
558k
  case XPATH_STRING:
4198
558k
      ret->stringval = xmlStrdup(val->stringval);
4199
558k
            if (ret->stringval == NULL) {
4200
0
                xmlFree(ret);
4201
0
                return(NULL);
4202
0
            }
4203
558k
      break;
4204
558k
  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
568k
    }
4222
568k
    return(ret);
4223
568k
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
3.32M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
3.32M
    if (obj == NULL) return;
4233
3.29M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
880k
        if (obj->nodesetval != NULL)
4235
880k
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
2.41M
    } else if (obj->type == XPATH_STRING) {
4237
1.14M
  if (obj->stringval != NULL)
4238
1.14M
      xmlFree(obj->stringval);
4239
1.14M
    }
4240
3.29M
    xmlFree(obj);
4241
3.29M
}
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
6.11M
{
4258
6.11M
    if (obj == NULL)
4259
8
  return;
4260
6.11M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
2.86M
   xmlXPathFreeObject(obj);
4262
3.24M
    } else {
4263
3.24M
  xmlXPathContextCachePtr cache =
4264
3.24M
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
3.24M
  switch (obj->type) {
4267
1.70M
      case XPATH_NODESET:
4268
1.70M
      case XPATH_XSLT_TREE:
4269
1.70M
    if (obj->nodesetval != NULL) {
4270
1.70M
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
1.62M
      (cache->numNodeset < cache->maxNodeset)) {
4272
1.15M
                        obj->stringval = (void *) cache->nodesetObjs;
4273
1.15M
                        cache->nodesetObjs = obj;
4274
1.15M
                        cache->numNodeset += 1;
4275
1.15M
      goto obj_cached;
4276
1.15M
        } else {
4277
551k
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
551k
      obj->nodesetval = NULL;
4279
551k
        }
4280
1.70M
    }
4281
551k
    break;
4282
551k
      case XPATH_STRING:
4283
87.9k
    if (obj->stringval != NULL)
4284
87.8k
        xmlFree(obj->stringval);
4285
87.9k
                obj->stringval = NULL;
4286
87.9k
    break;
4287
458k
      case XPATH_BOOLEAN:
4288
1.45M
      case XPATH_NUMBER:
4289
1.45M
    break;
4290
0
      default:
4291
0
    goto free_obj;
4292
3.24M
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
2.09M
        if (cache->numMisc >= cache->maxMisc)
4298
9.53k
      goto free_obj;
4299
2.08M
        obj->stringval = (void *) cache->miscObjs;
4300
2.08M
        cache->miscObjs = obj;
4301
2.08M
        cache->numMisc += 1;
4302
4303
3.23M
obj_cached:
4304
3.23M
        obj->boolval = 0;
4305
3.23M
  if (obj->nodesetval != NULL) {
4306
1.15M
      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
1.15M
      if (tmpset->nodeNr > 0) {
4313
1.12M
    int i;
4314
1.12M
    xmlNodePtr node;
4315
4316
2.31M
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
1.18M
        node = tmpset->nodeTab[i];
4318
1.18M
        if ((node != NULL) &&
4319
1.18M
      (node->type == XML_NAMESPACE_DECL))
4320
132k
        {
4321
132k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
132k
        }
4323
1.18M
    }
4324
1.12M
      }
4325
1.15M
      tmpset->nodeNr = 0;
4326
1.15M
        }
4327
4328
3.23M
  return;
4329
4330
9.53k
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
9.53k
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
9.53k
  xmlFree(obj);
4337
9.53k
    }
4338
6.11M
}
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
886
xmlXPathCastBooleanToString (int val) {
4355
886
    xmlChar *ret;
4356
886
    if (val)
4357
240
  ret = xmlStrdup((const xmlChar *) "true");
4358
646
    else
4359
646
  ret = xmlStrdup((const xmlChar *) "false");
4360
886
    return(ret);
4361
886
}
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
9.02k
xmlXPathCastNumberToString (double val) {
4371
9.02k
    xmlChar *ret;
4372
9.02k
    switch (xmlXPathIsInf(val)) {
4373
215
    case 1:
4374
215
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
215
  break;
4376
215
    case -1:
4377
215
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
215
  break;
4379
8.59k
    default:
4380
8.59k
  if (xmlXPathIsNaN(val)) {
4381
589
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
8.00k
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
1.79k
      ret = xmlStrdup((const xmlChar *) "0");
4385
6.20k
  } else {
4386
      /* could be improved */
4387
6.20k
      char buf[100];
4388
6.20k
      xmlXPathFormatNumber(val, buf, 99);
4389
6.20k
      buf[99] = 0;
4390
6.20k
      ret = xmlStrdup((const xmlChar *) buf);
4391
6.20k
  }
4392
9.02k
    }
4393
9.02k
    return(ret);
4394
9.02k
}
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
5.54M
xmlXPathCastNodeToString (xmlNode *node) {
4404
5.54M
    return(xmlNodeGetContent(node));
4405
5.54M
}
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
109k
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
109k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
43.3k
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
65.8k
    if (ns->nodeNr > 1)
4419
21.9k
  xmlXPathNodeSetSort(ns);
4420
65.8k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
109k
}
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
35.3k
xmlXPathCastToString(xmlXPathObject *val) {
4432
35.3k
    xmlChar *ret = NULL;
4433
4434
35.3k
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
35.3k
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
23.3k
        case XPATH_NODESET:
4441
23.3k
        case XPATH_XSLT_TREE:
4442
23.3k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
23.3k
      break;
4444
2.17k
  case XPATH_STRING:
4445
2.17k
      return(xmlStrdup(val->stringval));
4446
886
        case XPATH_BOOLEAN:
4447
886
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
886
      break;
4449
9.02k
  case XPATH_NUMBER: {
4450
9.02k
      ret = xmlXPathCastNumberToString(val->floatval);
4451
9.02k
      break;
4452
23.3k
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
35.3k
    }
4458
33.2k
    return(ret);
4459
35.3k
}
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
6.67k
xmlXPathCastBooleanToNumber(int val) {
4508
6.67k
    if (val)
4509
2.46k
  return(1.0);
4510
4.20k
    return(0.0);
4511
6.67k
}
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
5.80M
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
5.80M
    return(xmlXPathStringEvalNumber(val));
4522
5.80M
}
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.57M
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
4.57M
    xmlChar *strval;
4534
4.57M
    double ret;
4535
4536
4.57M
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
4.57M
    strval = xmlXPathCastNodeToString(node);
4539
4.57M
    if (strval == NULL) {
4540
29
        xmlXPathPErrMemory(ctxt);
4541
29
  return(xmlXPathNAN);
4542
29
    }
4543
4.57M
    ret = xmlXPathCastStringToNumber(strval);
4544
4.57M
    xmlFree(strval);
4545
4546
4.57M
    return(ret);
4547
4.57M
}
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
197k
xmlXPathCastNumberToBoolean (double val) {
4618
197k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
195k
   return(0);
4620
1.87k
     return(1);
4621
197k
}
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
2.58k
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
2.58k
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
1.12k
  return(0);
4633
1.45k
    return(1);
4634
2.58k
}
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
94.7k
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
94.7k
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
93.6k
  return(0);
4646
1.12k
    return(1);
4647
94.7k
}
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
99.2k
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
99.2k
    int ret = 0;
4658
4659
99.2k
    if (val == NULL)
4660
0
  return(0);
4661
99.2k
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
94.7k
    case XPATH_NODESET:
4666
94.7k
    case XPATH_XSLT_TREE:
4667
94.7k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
94.7k
  break;
4669
2.58k
    case XPATH_STRING:
4670
2.58k
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
2.58k
  break;
4672
1.87k
    case XPATH_NUMBER:
4673
1.87k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
1.87k
  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
99.2k
    }
4683
99.2k
    return(ret);
4684
99.2k
}
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
26.2k
xmlXPathNewContext(xmlDoc *doc) {
4721
26.2k
    xmlXPathContextPtr ret;
4722
4723
26.2k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
26.2k
    if (ret == NULL)
4725
101
  return(NULL);
4726
26.1k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
26.1k
    ret->doc = doc;
4728
26.1k
    ret->node = NULL;
4729
4730
26.1k
    ret->varHash = NULL;
4731
4732
26.1k
    ret->nb_types = 0;
4733
26.1k
    ret->max_types = 0;
4734
26.1k
    ret->types = NULL;
4735
4736
26.1k
    ret->nb_axis = 0;
4737
26.1k
    ret->max_axis = 0;
4738
26.1k
    ret->axis = NULL;
4739
4740
26.1k
    ret->nsHash = NULL;
4741
26.1k
    ret->user = NULL;
4742
4743
26.1k
    ret->contextSize = -1;
4744
26.1k
    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
26.1k
    return(ret);
4754
26.2k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
26.1k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
26.1k
    if (ctxt == NULL) return;
4764
4765
26.1k
    if (ctxt->cache != NULL)
4766
25.5k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
26.1k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
26.1k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
26.1k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
26.1k
    xmlResetError(&ctxt->lastError);
4771
26.1k
    xmlFree(ctxt);
4772
26.1k
}
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
0
                        xmlStructuredErrorFunc handler, void *data) {
4786
0
    if (ctxt == NULL)
4787
0
        return;
4788
4789
0
    ctxt->error = handler;
4790
0
    ctxt->userData = data;
4791
0
}
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
26.1k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
26.1k
    xmlXPathParserContextPtr ret;
4809
4810
26.1k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
26.1k
    if (ret == NULL) {
4812
83
        xmlXPathErrMemory(ctxt);
4813
83
  return(NULL);
4814
83
    }
4815
26.1k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
26.1k
    ret->cur = ret->base = str;
4817
26.1k
    ret->context = ctxt;
4818
4819
26.1k
    ret->comp = xmlXPathNewCompExpr();
4820
26.1k
    if (ret->comp == NULL) {
4821
292
        xmlXPathErrMemory(ctxt);
4822
292
  xmlFree(ret->valueTab);
4823
292
  xmlFree(ret);
4824
292
  return(NULL);
4825
292
    }
4826
25.8k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
0
        ret->comp->dict = ctxt->dict;
4828
0
  xmlDictReference(ret->comp->dict);
4829
0
    }
4830
4831
25.8k
    return(ret);
4832
26.1k
}
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
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
0
    xmlXPathParserContextPtr ret;
4844
4845
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
0
    if (ret == NULL) {
4847
0
        xmlXPathErrMemory(ctxt);
4848
0
  return(NULL);
4849
0
    }
4850
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
0
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
0
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
0
    if (ret->valueTab == NULL) {
4860
0
  xmlFree(ret);
4861
0
  xmlXPathErrMemory(ctxt);
4862
0
  return(NULL);
4863
0
    }
4864
0
    ret->valueNr = 0;
4865
0
    ret->value = NULL;
4866
4867
0
    ret->context = ctxt;
4868
0
    ret->comp = comp;
4869
4870
0
    return(ret);
4871
0
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
25.8k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
25.8k
    int i;
4881
4882
25.8k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
25.8k
    if (ctxt->valueTab != NULL) {
4886
36.1k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
10.4k
            if (ctxt->context)
4888
10.4k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
10.4k
        }
4892
25.7k
        xmlFree(ctxt->valueTab);
4893
25.7k
    }
4894
25.8k
    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
25.8k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
25.8k
    }
4903
25.8k
    xmlFree(ctxt);
4904
25.8k
}
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
94.1k
xmlXPathNodeValHash(xmlNodePtr node) {
4921
94.1k
    int len = 2;
4922
94.1k
    const xmlChar * string = NULL;
4923
94.1k
    xmlNodePtr tmp = NULL;
4924
94.1k
    unsigned int ret = 0;
4925
4926
94.1k
    if (node == NULL)
4927
0
  return(0);
4928
4929
94.1k
    if (node->type == XML_DOCUMENT_NODE) {
4930
5.26k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
5.26k
  if (tmp == NULL)
4932
362
      node = node->children;
4933
4.90k
  else
4934
4.90k
      node = tmp;
4935
4936
5.26k
  if (node == NULL)
4937
289
      return(0);
4938
5.26k
    }
4939
4940
93.8k
    switch (node->type) {
4941
253
  case XML_COMMENT_NODE:
4942
452
  case XML_PI_NODE:
4943
661
  case XML_CDATA_SECTION_NODE:
4944
1.03k
  case XML_TEXT_NODE:
4945
1.03k
      string = node->content;
4946
1.03k
      if (string == NULL)
4947
199
    return(0);
4948
831
      if (string[0] == 0)
4949
435
    return(0);
4950
396
      return(string[0] + (string[1] << 8));
4951
77.4k
  case XML_NAMESPACE_DECL:
4952
77.4k
      string = ((xmlNsPtr)node)->href;
4953
77.4k
      if (string == NULL)
4954
0
    return(0);
4955
77.4k
      if (string[0] == 0)
4956
25.0k
    return(0);
4957
52.3k
      return(string[0] + (string[1] << 8));
4958
199
  case XML_ATTRIBUTE_NODE:
4959
199
      tmp = ((xmlAttrPtr) node)->children;
4960
199
      break;
4961
15.1k
  case XML_ELEMENT_NODE:
4962
15.1k
      tmp = node->children;
4963
15.1k
      break;
4964
66
  default:
4965
66
      return(0);
4966
93.8k
    }
4967
57.3k
    while (tmp != NULL) {
4968
47.4k
  switch (tmp->type) {
4969
907
      case XML_CDATA_SECTION_NODE:
4970
9.66k
      case XML_TEXT_NODE:
4971
9.66k
    string = tmp->content;
4972
9.66k
    break;
4973
37.7k
      default:
4974
37.7k
                string = NULL;
4975
37.7k
    break;
4976
47.4k
  }
4977
47.4k
  if ((string != NULL) && (string[0] != 0)) {
4978
8.78k
      if (len == 1) {
4979
1.37k
    return(ret + (string[0] << 8));
4980
1.37k
      }
4981
7.41k
      if (string[1] == 0) {
4982
3.36k
    len = 1;
4983
3.36k
    ret = string[0];
4984
4.05k
      } else {
4985
4.05k
    return(string[0] + (string[1] << 8));
4986
4.05k
      }
4987
7.41k
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
42.0k
        if ((tmp->children != NULL) &&
4992
11.3k
            (tmp->type != XML_DTD_NODE) &&
4993
11.3k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
11.1k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
11.1k
            tmp = tmp->children;
4996
11.1k
            continue;
4997
11.1k
  }
4998
30.9k
  if (tmp == node)
4999
0
      break;
5000
5001
30.9k
  if (tmp->next != NULL) {
5002
25.3k
      tmp = tmp->next;
5003
25.3k
      continue;
5004
25.3k
  }
5005
5006
10.2k
  do {
5007
10.2k
      tmp = tmp->parent;
5008
10.2k
      if (tmp == NULL)
5009
0
    break;
5010
10.2k
      if (tmp == node) {
5011
5.37k
    tmp = NULL;
5012
5.37k
    break;
5013
5.37k
      }
5014
4.82k
      if (tmp->next != NULL) {
5015
223
    tmp = tmp->next;
5016
223
    break;
5017
223
      }
5018
4.82k
  } while (tmp != NULL);
5019
5.59k
    }
5020
9.92k
    return(ret);
5021
15.3k
}
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
2.18k
xmlXPathStringHash(const xmlChar * string) {
5032
2.18k
    if (string == NULL)
5033
0
  return(0);
5034
2.18k
    if (string[0] == 0)
5035
683
  return(0);
5036
1.49k
    return(string[0] + (string[1] << 8));
5037
2.18k
}
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
5.70k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
5.70k
    int i, ret = 0;
5063
5.70k
    xmlNodeSetPtr ns;
5064
5.70k
    xmlChar *str2;
5065
5066
5.70k
    if ((f == NULL) || (arg == NULL) ||
5067
5.70k
  ((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
5.70k
    ns = arg->nodesetval;
5073
5.70k
    if (ns != NULL) {
5074
15.4k
  for (i = 0;i < ns->nodeNr;i++) {
5075
9.93k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
9.93k
       if (str2 != NULL) {
5077
9.93k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
9.93k
     xmlFree(str2);
5079
9.93k
     xmlXPathNumberFunction(ctxt, 1);
5080
9.93k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
9.93k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
9.93k
     if (ret)
5083
239
         break;
5084
9.93k
       } else {
5085
6
                 xmlXPathPErrMemory(ctxt);
5086
6
             }
5087
9.93k
  }
5088
5.70k
    }
5089
5.70k
    xmlXPathReleaseObject(ctxt->context, arg);
5090
5.70k
    xmlXPathReleaseObject(ctxt->context, f);
5091
5.70k
    return(ret);
5092
5.70k
}
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
19.0k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
19.0k
    int i, ret = 0;
5117
19.0k
    xmlNodeSetPtr ns;
5118
19.0k
    xmlChar *str2;
5119
5120
19.0k
    if ((s == NULL) || (arg == NULL) ||
5121
19.0k
  ((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
19.0k
    ns = arg->nodesetval;
5127
19.0k
    if (ns != NULL) {
5128
581k
  for (i = 0;i < ns->nodeNr;i++) {
5129
562k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
562k
       if (str2 != NULL) {
5131
562k
     xmlXPathValuePush(ctxt,
5132
562k
         xmlXPathCacheNewString(ctxt, str2));
5133
562k
     xmlFree(str2);
5134
562k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
562k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
562k
     if (ret)
5137
208
         break;
5138
562k
       } else {
5139
2
                 xmlXPathPErrMemory(ctxt);
5140
2
             }
5141
562k
  }
5142
19.0k
    }
5143
19.0k
    xmlXPathReleaseObject(ctxt->context, arg);
5144
19.0k
    xmlXPathReleaseObject(ctxt->context, s);
5145
19.0k
    return(ret);
5146
19.0k
}
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
201k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
201k
    int i, j, init = 0;
5180
201k
    double val1;
5181
201k
    double *values2;
5182
201k
    int ret = 0;
5183
201k
    xmlNodeSetPtr ns1;
5184
201k
    xmlNodeSetPtr ns2;
5185
5186
201k
    if ((arg1 == NULL) ||
5187
201k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
201k
    if ((arg2 == NULL) ||
5192
201k
  ((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
201k
    ns1 = arg1->nodesetval;
5199
201k
    ns2 = arg2->nodesetval;
5200
5201
201k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
195k
  xmlXPathFreeObject(arg1);
5203
195k
  xmlXPathFreeObject(arg2);
5204
195k
  return(0);
5205
195k
    }
5206
5.73k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
1.47k
  xmlXPathFreeObject(arg1);
5208
1.47k
  xmlXPathFreeObject(arg2);
5209
1.47k
  return(0);
5210
1.47k
    }
5211
5212
4.25k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
4.25k
    if (values2 == NULL) {
5214
1
        xmlXPathPErrMemory(ctxt);
5215
1
  xmlXPathFreeObject(arg1);
5216
1
  xmlXPathFreeObject(arg2);
5217
1
  return(0);
5218
1
    }
5219
21.5k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
17.7k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
17.7k
  if (xmlXPathIsNaN(val1))
5222
14.4k
      continue;
5223
7.00k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
4.20k
      if (init == 0) {
5225
1.73k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
1.73k
                                                          ns2->nodeTab[j]);
5227
1.73k
      }
5228
4.20k
      if (xmlXPathIsNaN(values2[j]))
5229
1.02k
    continue;
5230
3.18k
      if (inf && strict)
5231
887
    ret = (val1 < values2[j]);
5232
2.29k
      else if (inf && !strict)
5233
230
    ret = (val1 <= values2[j]);
5234
2.06k
      else if (!inf && strict)
5235
1.85k
    ret = (val1 > values2[j]);
5236
215
      else if (!inf && !strict)
5237
215
    ret = (val1 >= values2[j]);
5238
3.18k
      if (ret)
5239
466
    break;
5240
3.18k
  }
5241
3.26k
  if (ret)
5242
466
      break;
5243
2.79k
  init = 1;
5244
2.79k
    }
5245
4.25k
    xmlFree(values2);
5246
4.25k
    xmlXPathFreeObject(arg1);
5247
4.25k
    xmlXPathFreeObject(arg2);
5248
4.25k
    return(ret);
5249
4.25k
}
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
26.9k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
26.9k
    if ((val == NULL) || (arg == NULL) ||
5274
26.9k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
26.9k
    switch(val->type) {
5278
5.70k
        case XPATH_NUMBER:
5279
5.70k
      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
19.0k
        case XPATH_STRING:
5284
19.0k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
2.20k
        case XPATH_BOOLEAN:
5286
2.20k
      xmlXPathValuePush(ctxt, arg);
5287
2.20k
      xmlXPathBooleanFunction(ctxt, 1);
5288
2.20k
      xmlXPathValuePush(ctxt, val);
5289
2.20k
      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
26.9k
    }
5295
0
    return(0);
5296
26.9k
}
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
2.75k
{
5315
2.75k
    int i;
5316
2.75k
    xmlNodeSetPtr ns;
5317
2.75k
    xmlChar *str2;
5318
2.75k
    unsigned int hash;
5319
5320
2.75k
    if ((str == NULL) || (arg == NULL) ||
5321
2.75k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
2.75k
    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
2.75k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
568
        return (0);
5330
2.18k
    hash = xmlXPathStringHash(str);
5331
6.57k
    for (i = 0; i < ns->nodeNr; i++) {
5332
5.23k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
1.45k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
1.45k
            if (str2 == NULL) {
5335
3
                xmlXPathPErrMemory(ctxt);
5336
3
                return(0);
5337
3
            }
5338
1.45k
            if (xmlStrEqual(str, str2)) {
5339
976
                xmlFree(str2);
5340
976
    if (neq)
5341
663
        continue;
5342
313
                return (1);
5343
976
            } else if (neq) {
5344
215
    xmlFree(str2);
5345
215
    return (1);
5346
215
      }
5347
264
            xmlFree(str2);
5348
3.77k
        } else if (neq)
5349
316
      return (1);
5350
5.23k
    }
5351
1.33k
    return (0);
5352
2.18k
}
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
3.85k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
3.85k
  int i, ret=0;
5372
3.85k
  xmlNodeSetPtr ns;
5373
3.85k
  xmlChar *str2;
5374
3.85k
  xmlXPathObjectPtr val;
5375
3.85k
  double v;
5376
5377
3.85k
    if ((arg == NULL) ||
5378
3.85k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
3.85k
    ns = arg->nodesetval;
5382
3.85k
    if (ns != NULL) {
5383
9.69k
  for (i=0;i<ns->nodeNr;i++) {
5384
6.27k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
6.27k
      if (str2 != NULL) {
5386
6.27k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
6.27k
    xmlFree(str2);
5388
6.27k
    xmlXPathNumberFunction(ctxt, 1);
5389
6.27k
                CHECK_ERROR0;
5390
6.26k
    val = xmlXPathValuePop(ctxt);
5391
6.26k
    v = val->floatval;
5392
6.26k
    xmlXPathReleaseObject(ctxt->context, val);
5393
6.26k
    if (!xmlXPathIsNaN(v)) {
5394
956
        if ((!neq) && (v==f)) {
5395
215
      ret = 1;
5396
215
      break;
5397
741
        } else if ((neq) && (v!=f)) {
5398
215
      ret = 1;
5399
215
      break;
5400
215
        }
5401
5.31k
    } else { /* NaN is unequal to any value */
5402
5.31k
        if (neq)
5403
916
      ret = 1;
5404
5.31k
    }
5405
6.26k
      } else {
5406
5
                xmlXPathPErrMemory(ctxt);
5407
5
            }
5408
6.27k
  }
5409
3.85k
    }
5410
5411
3.84k
    return(ret);
5412
3.85k
}
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
7.56k
                      xmlXPathObjectPtr arg2, int neq) {
5434
7.56k
    int i, j;
5435
7.56k
    unsigned int *hashs1;
5436
7.56k
    unsigned int *hashs2;
5437
7.56k
    xmlChar **values1;
5438
7.56k
    xmlChar **values2;
5439
7.56k
    int ret = 0;
5440
7.56k
    xmlNodeSetPtr ns1;
5441
7.56k
    xmlNodeSetPtr ns2;
5442
5443
7.56k
    if ((arg1 == NULL) ||
5444
7.56k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
7.56k
    if ((arg2 == NULL) ||
5447
7.56k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
7.56k
    ns1 = arg1->nodesetval;
5451
7.56k
    ns2 = arg2->nodesetval;
5452
5453
7.56k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
2.35k
  return(0);
5455
5.21k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
1.15k
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
4.05k
    if (neq == 0)
5462
876k
  for (i = 0;i < ns1->nodeNr;i++)
5463
1.74M
      for (j = 0;j < ns2->nodeNr;j++)
5464
875k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
323
        return(1);
5466
5467
3.73k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
3.73k
    if (values1 == NULL) {
5469
1
        xmlXPathPErrMemory(ctxt);
5470
1
  return(0);
5471
1
    }
5472
3.73k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
3.73k
    if (hashs1 == NULL) {
5474
2
        xmlXPathPErrMemory(ctxt);
5475
2
  xmlFree(values1);
5476
2
  return(0);
5477
2
    }
5478
3.72k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
3.72k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
3.72k
    if (values2 == NULL) {
5481
1
        xmlXPathPErrMemory(ctxt);
5482
1
  xmlFree(hashs1);
5483
1
  xmlFree(values1);
5484
1
  return(0);
5485
1
    }
5486
3.72k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
3.72k
    if (hashs2 == NULL) {
5488
1
        xmlXPathPErrMemory(ctxt);
5489
1
  xmlFree(hashs1);
5490
1
  xmlFree(values1);
5491
1
  xmlFree(values2);
5492
1
  return(0);
5493
1
    }
5494
3.72k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
83.7k
    for (i = 0;i < ns1->nodeNr;i++) {
5496
81.7k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
165k
  for (j = 0;j < ns2->nodeNr;j++) {
5498
85.6k
      if (i == 0)
5499
7.18k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
85.6k
      if (hashs1[i] != hashs2[j]) {
5501
77.9k
    if (neq) {
5502
503
        ret = 1;
5503
503
        break;
5504
503
    }
5505
77.9k
      }
5506
7.67k
      else {
5507
7.67k
    if (values1[i] == NULL) {
5508
4.24k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
4.24k
                    if (values1[i] == NULL)
5510
3
                        xmlXPathPErrMemory(ctxt);
5511
4.24k
                }
5512
7.67k
    if (values2[j] == NULL) {
5513
5.97k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
5.97k
                    if (values2[j] == NULL)
5515
7
                        xmlXPathPErrMemory(ctxt);
5516
5.97k
                }
5517
7.67k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
7.67k
    if (ret)
5519
1.19k
        break;
5520
7.67k
      }
5521
85.6k
  }
5522
81.7k
  if (ret)
5523
1.70k
      break;
5524
81.7k
    }
5525
884k
    for (i = 0;i < ns1->nodeNr;i++)
5526
880k
  if (values1[i] != NULL)
5527
4.23k
      xmlFree(values1[i]);
5528
11.3k
    for (j = 0;j < ns2->nodeNr;j++)
5529
7.60k
  if (values2[j] != NULL)
5530
5.97k
      xmlFree(values2[j]);
5531
3.72k
    xmlFree(values1);
5532
3.72k
    xmlFree(values2);
5533
3.72k
    xmlFree(hashs1);
5534
3.72k
    xmlFree(hashs2);
5535
3.72k
    return(ret);
5536
3.72k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
209k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
209k
    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
209k
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
195k
        case XPATH_BOOLEAN:
5550
195k
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
1.25k
    case XPATH_BOOLEAN:
5554
1.25k
        ret = (arg1->boolval == arg2->boolval);
5555
1.25k
        break;
5556
193k
    case XPATH_NUMBER:
5557
193k
        ret = (arg1->boolval ==
5558
193k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
193k
        break;
5560
649
    case XPATH_STRING:
5561
649
        if ((arg2->stringval == NULL) ||
5562
649
      (arg2->stringval[0] == 0)) ret = 0;
5563
325
        else
5564
325
      ret = 1;
5565
649
        ret = (arg1->boolval == ret);
5566
649
        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
195k
      }
5574
195k
      break;
5575
195k
        case XPATH_NUMBER:
5576
10.3k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
1.29k
    case XPATH_BOOLEAN:
5580
1.29k
        ret = (arg2->boolval==
5581
1.29k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
1.29k
        break;
5583
1.44k
    case XPATH_STRING:
5584
1.44k
        xmlXPathValuePush(ctxt, arg2);
5585
1.44k
        xmlXPathNumberFunction(ctxt, 1);
5586
1.44k
        arg2 = xmlXPathValuePop(ctxt);
5587
1.44k
                    if (ctxt->error)
5588
0
                        break;
5589
                    /* Falls through. */
5590
9.08k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
9.08k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
8.69k
          xmlXPathIsNaN(arg2->floatval)) {
5594
1.78k
            ret = 0;
5595
7.30k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
430
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
215
          ret = 1;
5598
215
      else
5599
215
          ret = 0;
5600
6.87k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
491
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
215
          ret = 1;
5603
276
      else
5604
276
          ret = 0;
5605
6.38k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
215
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
215
      else
5609
215
          ret = 0;
5610
6.16k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
215
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
215
      else
5614
215
          ret = 0;
5615
5.95k
        } else {
5616
5.95k
            ret = (arg1->floatval == arg2->floatval);
5617
5.95k
        }
5618
9.08k
        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
10.3k
      }
5626
10.3k
      break;
5627
10.3k
        case XPATH_STRING:
5628
2.87k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
613
    case XPATH_BOOLEAN:
5632
613
        if ((arg1->stringval == NULL) ||
5633
613
      (arg1->stringval[0] == 0)) ret = 0;
5634
331
        else
5635
331
      ret = 1;
5636
613
        ret = (arg2->boolval == ret);
5637
613
        break;
5638
224
    case XPATH_STRING:
5639
224
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
224
        break;
5641
2.03k
    case XPATH_NUMBER:
5642
2.03k
        xmlXPathValuePush(ctxt, arg1);
5643
2.03k
        xmlXPathNumberFunction(ctxt, 1);
5644
2.03k
        arg1 = xmlXPathValuePop(ctxt);
5645
2.03k
                    if (ctxt->error)
5646
0
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
2.03k
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
1.65k
          xmlXPathIsNaN(arg2->floatval)) {
5650
585
            ret = 0;
5651
1.45k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
400
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
195
          ret = 1;
5654
205
      else
5655
205
          ret = 0;
5656
1.05k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
393
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
197
          ret = 1;
5659
196
      else
5660
196
          ret = 0;
5661
659
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
197
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
197
      else
5665
197
          ret = 0;
5666
462
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
206
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
206
      else
5670
206
          ret = 0;
5671
256
        } else {
5672
256
            ret = (arg1->floatval == arg2->floatval);
5673
256
        }
5674
2.03k
        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
2.87k
      }
5682
2.87k
      break;
5683
2.87k
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
209k
    }
5690
209k
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
209k
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
209k
    return(ret);
5693
209k
}
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
220k
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
220k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
220k
    int ret = 0;
5705
5706
220k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
220k
    arg2 = xmlXPathValuePop(ctxt);
5708
220k
    arg1 = xmlXPathValuePop(ctxt);
5709
220k
    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
220k
    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
220k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
211k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
12.2k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
3.56k
    argtmp = arg2;
5732
3.56k
    arg2 = arg1;
5733
3.56k
    arg1 = argtmp;
5734
3.56k
  }
5735
12.2k
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
5.13k
      case XPATH_NODESET:
5739
5.13k
      case XPATH_XSLT_TREE:
5740
5.13k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
5.13k
    break;
5742
2.32k
      case XPATH_BOOLEAN:
5743
2.32k
    if ((arg1->nodesetval == NULL) ||
5744
2.32k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
302
    else
5746
302
        ret = 1;
5747
2.32k
    ret = (ret == arg2->boolval);
5748
2.32k
    break;
5749
3.11k
      case XPATH_NUMBER:
5750
3.11k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
3.11k
    break;
5752
1.67k
      case XPATH_STRING:
5753
1.67k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
1.67k
                                                 arg2->stringval, 0);
5755
1.67k
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
12.2k
  }
5760
12.2k
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
12.2k
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
12.2k
  return(ret);
5763
12.2k
    }
5764
5765
208k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
220k
}
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
5.53k
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
5.53k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
5.53k
    int ret = 0;
5778
5779
5.53k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
5.53k
    arg2 = xmlXPathValuePop(ctxt);
5781
5.53k
    arg1 = xmlXPathValuePop(ctxt);
5782
5.53k
    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
5.53k
    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
5.53k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
4.93k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
4.93k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
372
    argtmp = arg2;
5805
372
    arg2 = arg1;
5806
372
    arg1 = argtmp;
5807
372
  }
5808
4.93k
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
2.43k
      case XPATH_NODESET:
5812
2.43k
      case XPATH_XSLT_TREE:
5813
2.43k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
2.43k
    break;
5815
699
      case XPATH_BOOLEAN:
5816
699
    if ((arg1->nodesetval == NULL) ||
5817
699
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
478
    else
5819
478
        ret = 1;
5820
699
    ret = (ret != arg2->boolval);
5821
699
    break;
5822
733
      case XPATH_NUMBER:
5823
733
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
733
    break;
5825
1.07k
      case XPATH_STRING:
5826
1.07k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
1.07k
                                                 arg2->stringval, 1);
5828
1.07k
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
4.93k
  }
5833
4.93k
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
4.93k
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
4.93k
  return(ret);
5836
4.93k
    }
5837
5838
599
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
5.53k
}
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
811k
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
811k
    int ret = 0, arg1i = 0, arg2i = 0;
5866
811k
    xmlXPathObjectPtr arg1, arg2;
5867
5868
811k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
811k
    arg2 = xmlXPathValuePop(ctxt);
5870
811k
    arg1 = xmlXPathValuePop(ctxt);
5871
811k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
8
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
8
  else
5875
8
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
8
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
811k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
603k
      (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
228k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
207k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
201k
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
201k
  } else {
5890
26.9k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
20.5k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
20.5k
                                arg1, arg2);
5893
20.5k
      } else {
5894
6.38k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
6.38k
                                arg2, arg1);
5896
6.38k
      }
5897
26.9k
  }
5898
228k
  return(ret);
5899
228k
    }
5900
5901
583k
    if (arg1->type != XPATH_NUMBER) {
5902
566k
  xmlXPathValuePush(ctxt, arg1);
5903
566k
  xmlXPathNumberFunction(ctxt, 1);
5904
566k
  arg1 = xmlXPathValuePop(ctxt);
5905
566k
    }
5906
583k
    if (arg2->type != XPATH_NUMBER) {
5907
565k
  xmlXPathValuePush(ctxt, arg2);
5908
565k
  xmlXPathNumberFunction(ctxt, 1);
5909
565k
  arg2 = xmlXPathValuePop(ctxt);
5910
565k
    }
5911
583k
    if (ctxt->error)
5912
206
        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
583k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
572k
  ret=0;
5920
572k
    } else {
5921
10.6k
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
10.6k
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
10.6k
  if (inf && strict) {
5924
4.60k
      if ((arg1i == -1 && arg2i != -1) ||
5925
4.39k
    (arg2i == 1 && arg1i != 1)) {
5926
431
    ret = 1;
5927
4.17k
      } else if (arg1i == 0 && arg2i == 0) {
5928
3.46k
    ret = (arg1->floatval < arg2->floatval);
5929
3.46k
      } else {
5930
715
    ret = 0;
5931
715
      }
5932
4.60k
  }
5933
6.03k
  else if (inf && !strict) {
5934
1.29k
      if (arg1i == -1 || arg2i == 1) {
5935
429
    ret = 1;
5936
866
      } else if (arg1i == 0 && arg2i == 0) {
5937
388
    ret = (arg1->floatval <= arg2->floatval);
5938
478
      } else {
5939
478
    ret = 0;
5940
478
      }
5941
1.29k
  }
5942
4.73k
  else if (!inf && strict) {
5943
3.46k
      if ((arg1i == 1 && arg2i != 1) ||
5944
3.25k
    (arg2i == -1 && arg1i != -1)) {
5945
419
    ret = 1;
5946
3.04k
      } else if (arg1i == 0 && arg2i == 0) {
5947
2.23k
    ret = (arg1->floatval > arg2->floatval);
5948
2.23k
      } else {
5949
811
    ret = 0;
5950
811
      }
5951
3.46k
  }
5952
1.27k
  else if (!inf && !strict) {
5953
1.27k
      if (arg1i == 1 || arg2i == -1) {
5954
455
    ret = 1;
5955
823
      } else if (arg1i == 0 && arg2i == 0) {
5956
405
    ret = (arg1->floatval >= arg2->floatval);
5957
418
      } else {
5958
418
    ret = 0;
5959
418
      }
5960
1.27k
  }
5961
10.6k
    }
5962
583k
error:
5963
583k
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
583k
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
583k
    return(ret);
5966
583k
}
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
31.1k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
31.1k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
31.1k
    CAST_TO_NUMBER;
5979
31.1k
    CHECK_TYPE(XPATH_NUMBER);
5980
31.1k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
31.1k
}
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
2.26k
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
2.26k
    xmlXPathObjectPtr arg;
5993
2.26k
    double val;
5994
5995
2.26k
    arg = xmlXPathValuePop(ctxt);
5996
2.26k
    if (arg == NULL)
5997
2.26k
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
2.26k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
2.26k
    xmlXPathReleaseObject(ctxt->context, arg);
6000
2.26k
    CAST_TO_NUMBER;
6001
2.26k
    CHECK_TYPE(XPATH_NUMBER);
6002
2.26k
    ctxt->value->floatval += val;
6003
2.26k
}
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
153k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
153k
    xmlXPathObjectPtr arg;
6015
153k
    double val;
6016
6017
153k
    arg = xmlXPathValuePop(ctxt);
6018
153k
    if (arg == NULL)
6019
153k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
153k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
153k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
153k
    CAST_TO_NUMBER;
6023
153k
    CHECK_TYPE(XPATH_NUMBER);
6024
153k
    ctxt->value->floatval -= val;
6025
153k
}
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
24.0k
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
24.0k
    xmlXPathObjectPtr arg;
6037
24.0k
    double val;
6038
6039
24.0k
    arg = xmlXPathValuePop(ctxt);
6040
24.0k
    if (arg == NULL)
6041
24.0k
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
24.0k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
24.0k
    xmlXPathReleaseObject(ctxt->context, arg);
6044
24.0k
    CAST_TO_NUMBER;
6045
24.0k
    CHECK_TYPE(XPATH_NUMBER);
6046
24.0k
    ctxt->value->floatval *= val;
6047
24.0k
}
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
2.17k
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
2.17k
    xmlXPathObjectPtr arg;
6060
2.17k
    double val;
6061
6062
2.17k
    arg = xmlXPathValuePop(ctxt);
6063
2.17k
    if (arg == NULL)
6064
2.17k
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
2.17k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
2.17k
    xmlXPathReleaseObject(ctxt->context, arg);
6067
2.17k
    CAST_TO_NUMBER;
6068
2.17k
    CHECK_TYPE(XPATH_NUMBER);
6069
2.17k
    ctxt->value->floatval /= val;
6070
2.17k
}
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
855
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
855
    xmlXPathObjectPtr arg;
6082
855
    double arg1, arg2;
6083
6084
855
    arg = xmlXPathValuePop(ctxt);
6085
855
    if (arg == NULL)
6086
855
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
855
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
855
    xmlXPathReleaseObject(ctxt->context, arg);
6089
855
    CAST_TO_NUMBER;
6090
855
    CHECK_TYPE(XPATH_NUMBER);
6091
853
    arg1 = ctxt->value->floatval;
6092
853
    if (arg2 == 0)
6093
334
  ctxt->value->floatval = xmlXPathNAN;
6094
519
    else {
6095
519
  ctxt->value->floatval = fmod(arg1, arg2);
6096
519
    }
6097
853
}
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
1.29k
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
1.29k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
1.29k
    if (cur == NULL)
6141
750
        return(ctxt->context->node);
6142
540
    return(NULL);
6143
1.29k
}
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
1.85M
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
1.85M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
1.85M
    if (cur == NULL) {
6157
825k
  if (ctxt->context->node == NULL) return(NULL);
6158
825k
  switch (ctxt->context->node->type) {
6159
553k
            case XML_ELEMENT_NODE:
6160
818k
            case XML_TEXT_NODE:
6161
819k
            case XML_CDATA_SECTION_NODE:
6162
819k
            case XML_ENTITY_REF_NODE:
6163
819k
            case XML_ENTITY_NODE:
6164
820k
            case XML_PI_NODE:
6165
820k
            case XML_COMMENT_NODE:
6166
820k
            case XML_NOTATION_NODE:
6167
820k
            case XML_DTD_NODE:
6168
820k
    return(ctxt->context->node->children);
6169
4.27k
            case XML_DOCUMENT_NODE:
6170
4.27k
            case XML_DOCUMENT_TYPE_NODE:
6171
4.27k
            case XML_DOCUMENT_FRAG_NODE:
6172
4.27k
            case XML_HTML_DOCUMENT_NODE:
6173
4.27k
    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
0
            case XML_ATTRIBUTE_NODE:
6178
238
      case XML_NAMESPACE_DECL:
6179
238
      case XML_XINCLUDE_START:
6180
238
      case XML_XINCLUDE_END:
6181
238
    return(NULL);
6182
825k
  }
6183
0
  return(NULL);
6184
825k
    }
6185
1.03M
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
1.03M
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
1.03M
    return(cur->next);
6189
1.03M
}
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
2.99M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
2.99M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
2.99M
    if (cur == NULL) {
6203
1.76M
  cur = ctxt->context->node;
6204
1.76M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
1.76M
  switch (cur->type) {
6209
1.23M
            case XML_ELEMENT_NODE:
6210
1.23M
      case XML_DOCUMENT_FRAG_NODE:
6211
1.23M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
1.23M
            case XML_ENTITY_NODE:
6213
1.23M
    cur = cur->children;
6214
1.23M
    if (cur != NULL) {
6215
390k
        if (cur->type == XML_ELEMENT_NODE)
6216
333k
      return(cur);
6217
58.0k
        do {
6218
58.0k
      cur = cur->next;
6219
58.0k
        } while ((cur != NULL) &&
6220
55.5k
      (cur->type != XML_ELEMENT_NODE));
6221
57.0k
        return(cur);
6222
390k
    }
6223
839k
    return(NULL);
6224
67.4k
            case XML_DOCUMENT_NODE:
6225
67.4k
            case XML_HTML_DOCUMENT_NODE:
6226
67.4k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
463k
      default:
6228
463k
    return(NULL);
6229
1.76M
  }
6230
0
  return(NULL);
6231
1.76M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
1.23M
    switch (cur->type) {
6236
1.23M
  case XML_ELEMENT_NODE:
6237
1.23M
  case XML_TEXT_NODE:
6238
1.23M
  case XML_ENTITY_REF_NODE:
6239
1.23M
  case XML_ENTITY_NODE:
6240
1.23M
  case XML_CDATA_SECTION_NODE:
6241
1.23M
  case XML_PI_NODE:
6242
1.23M
  case XML_COMMENT_NODE:
6243
1.23M
  case XML_XINCLUDE_END:
6244
1.23M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
1.23M
    }
6249
1.23M
    if (cur->next != NULL) {
6250
803k
  if (cur->next->type == XML_ELEMENT_NODE)
6251
347k
      return(cur->next);
6252
455k
  cur = cur->next;
6253
456k
  do {
6254
456k
      cur = cur->next;
6255
456k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
455k
  return(cur);
6257
803k
    }
6258
430k
    return(NULL);
6259
1.23M
}
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
22.6M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
22.6M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
22.6M
    if (cur == NULL) {
6274
29.0k
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
29.0k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
28.8k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
474
      return(NULL);
6279
6280
28.6k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
26.1k
      return(ctxt->context->doc->children);
6282
2.47k
        return(ctxt->context->node->children);
6283
28.6k
    }
6284
6285
22.6M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
22.6M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
2.26M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
2.25M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
2.25M
      if (cur->type != XML_DTD_NODE)
6297
2.25M
    return(cur);
6298
2.25M
  }
6299
2.26M
    }
6300
6301
20.3M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
20.3M
    while (cur->next != NULL) {
6304
20.0M
  cur = cur->next;
6305
20.0M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
20.0M
      (cur->type != XML_DTD_NODE))
6307
20.0M
      return(cur);
6308
20.0M
    }
6309
6310
2.28M
    do {
6311
2.28M
        cur = cur->parent;
6312
2.28M
  if (cur == NULL) break;
6313
2.28M
  if (cur == ctxt->context->node) return(NULL);
6314
2.05M
  if (cur->next != NULL) {
6315
81.9k
      cur = cur->next;
6316
81.9k
      return(cur);
6317
81.9k
  }
6318
2.05M
    } while (cur != NULL);
6319
0
    return(cur);
6320
308k
}
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
22.4M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
22.4M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
22.4M
    if (cur == NULL)
6337
384k
        return(ctxt->context->node);
6338
6339
22.1M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
22.1M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
22.1M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
127k
        return(NULL);
6344
6345
21.9M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
22.1M
}
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
608k
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
608k
    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
608k
    if (cur == NULL) {
6365
312k
  if (ctxt->context->node == NULL) return(NULL);
6366
312k
  switch (ctxt->context->node->type) {
6367
288k
            case XML_ELEMENT_NODE:
6368
299k
            case XML_TEXT_NODE:
6369
300k
            case XML_CDATA_SECTION_NODE:
6370
300k
            case XML_ENTITY_REF_NODE:
6371
300k
            case XML_ENTITY_NODE:
6372
300k
            case XML_PI_NODE:
6373
300k
            case XML_COMMENT_NODE:
6374
300k
            case XML_NOTATION_NODE:
6375
300k
            case XML_DTD_NODE:
6376
300k
      case XML_ELEMENT_DECL:
6377
300k
      case XML_ATTRIBUTE_DECL:
6378
300k
      case XML_XINCLUDE_START:
6379
300k
      case XML_XINCLUDE_END:
6380
300k
      case XML_ENTITY_DECL:
6381
300k
    if (ctxt->context->node->parent == NULL)
6382
0
        return((xmlNodePtr) ctxt->context->doc);
6383
300k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
292k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
292k
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
292k
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
300k
    return(ctxt->context->node->parent);
6389
196
            case XML_ATTRIBUTE_NODE: {
6390
196
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
196
    return(att->parent);
6393
300k
      }
6394
8.47k
            case XML_DOCUMENT_NODE:
6395
8.47k
            case XML_DOCUMENT_TYPE_NODE:
6396
8.47k
            case XML_DOCUMENT_FRAG_NODE:
6397
8.47k
            case XML_HTML_DOCUMENT_NODE:
6398
8.47k
                return(NULL);
6399
3.02k
      case XML_NAMESPACE_DECL: {
6400
3.02k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6401
6402
3.02k
    if ((ns->next != NULL) &&
6403
3.02k
        (ns->next->type != XML_NAMESPACE_DECL))
6404
3.02k
        return((xmlNodePtr) ns->next);
6405
0
                return(NULL);
6406
3.02k
      }
6407
312k
  }
6408
312k
    }
6409
296k
    return(NULL);
6410
608k
}
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
257k
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
257k
    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
257k
    if (cur == NULL) {
6433
35.7k
  if (ctxt->context->node == NULL) return(NULL);
6434
35.7k
  switch (ctxt->context->node->type) {
6435
31.0k
            case XML_ELEMENT_NODE:
6436
33.2k
            case XML_TEXT_NODE:
6437
33.5k
            case XML_CDATA_SECTION_NODE:
6438
33.5k
            case XML_ENTITY_REF_NODE:
6439
33.5k
            case XML_ENTITY_NODE:
6440
33.7k
            case XML_PI_NODE:
6441
33.9k
            case XML_COMMENT_NODE:
6442
33.9k
      case XML_DTD_NODE:
6443
33.9k
      case XML_ELEMENT_DECL:
6444
33.9k
      case XML_ATTRIBUTE_DECL:
6445
33.9k
      case XML_ENTITY_DECL:
6446
33.9k
            case XML_NOTATION_NODE:
6447
33.9k
      case XML_XINCLUDE_START:
6448
33.9k
      case XML_XINCLUDE_END:
6449
33.9k
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
33.9k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
32.0k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
32.0k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
32.0k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
33.9k
    return(ctxt->context->node->parent);
6457
204
            case XML_ATTRIBUTE_NODE: {
6458
204
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
204
    return(tmp->parent);
6461
33.9k
      }
6462
1.37k
            case XML_DOCUMENT_NODE:
6463
1.37k
            case XML_DOCUMENT_TYPE_NODE:
6464
1.37k
            case XML_DOCUMENT_FRAG_NODE:
6465
1.37k
            case XML_HTML_DOCUMENT_NODE:
6466
1.37k
                return(NULL);
6467
217
      case XML_NAMESPACE_DECL: {
6468
217
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
217
    if ((ns->next != NULL) &&
6471
217
        (ns->next->type != XML_NAMESPACE_DECL))
6472
217
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
217
      }
6476
35.7k
  }
6477
0
  return(NULL);
6478
35.7k
    }
6479
221k
    if (cur == ctxt->context->doc->children)
6480
40.1k
  return((xmlNodePtr) ctxt->context->doc);
6481
181k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
44.8k
  return(NULL);
6483
136k
    switch (cur->type) {
6484
133k
  case XML_ELEMENT_NODE:
6485
134k
  case XML_TEXT_NODE:
6486
134k
  case XML_CDATA_SECTION_NODE:
6487
134k
  case XML_ENTITY_REF_NODE:
6488
134k
  case XML_ENTITY_NODE:
6489
134k
  case XML_PI_NODE:
6490
135k
  case XML_COMMENT_NODE:
6491
135k
  case XML_NOTATION_NODE:
6492
135k
  case XML_DTD_NODE:
6493
135k
        case XML_ELEMENT_DECL:
6494
135k
        case XML_ATTRIBUTE_DECL:
6495
136k
        case XML_ENTITY_DECL:
6496
136k
  case XML_XINCLUDE_START:
6497
136k
  case XML_XINCLUDE_END:
6498
136k
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
136k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
132k
    ((cur->parent->name[0] == ' ') ||
6502
132k
     (xmlStrEqual(cur->parent->name,
6503
132k
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
136k
      return(cur->parent);
6506
198
  case XML_ATTRIBUTE_NODE: {
6507
198
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
198
      return(att->parent);
6510
136k
  }
6511
427
  case XML_NAMESPACE_DECL: {
6512
427
      xmlNsPtr ns = (xmlNsPtr) cur;
6513
6514
427
      if ((ns->next != NULL) &&
6515
427
          (ns->next->type != XML_NAMESPACE_DECL))
6516
427
          return((xmlNodePtr) ns->next);
6517
      /* Bad, how did that namespace end up here ? */
6518
0
            return(NULL);
6519
427
  }
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
136k
    }
6526
0
    return(NULL);
6527
136k
}
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
66.6k
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
66.6k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
66.6k
    if (cur == NULL)
6544
10.5k
        return(ctxt->context->node);
6545
56.1k
    return(xmlXPathNextAncestor(ctxt, cur));
6546
66.6k
}
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
1.61k
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
1.61k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
1.61k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
1.41k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
410
  return(NULL);
6563
1.20k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6564
0
        return(NULL);
6565
1.20k
    if (cur == NULL)
6566
555
        return(ctxt->context->node->next);
6567
648
    return(cur->next);
6568
1.20k
}
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
29.3k
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6582
29.3k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6583
29.3k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6584
29.1k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6585
417
  return(NULL);
6586
28.9k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6587
0
        return(NULL);
6588
28.9k
    if (cur == NULL)
6589
4.34k
        return(ctxt->context->node->prev);
6590
24.6k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6591
194
  cur = cur->prev;
6592
194
  if (cur == NULL)
6593
0
      return(ctxt->context->node->prev);
6594
194
    }
6595
24.6k
    return(cur->prev);
6596
24.6k
}
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
1.53M
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6611
1.53M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6612
1.53M
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6613
1.52M
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6614
960k
        return(cur->children);
6615
6616
571k
    if (cur == NULL) {
6617
3.92k
        cur = ctxt->context->node;
6618
3.92k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6619
202
            cur = cur->parent;
6620
3.72k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6621
229
            xmlNsPtr ns = (xmlNsPtr) cur;
6622
6623
229
            if ((ns->next == NULL) ||
6624
229
                (ns->next->type == XML_NAMESPACE_DECL))
6625
0
                return (NULL);
6626
229
            cur = (xmlNodePtr) ns->next;
6627
229
        }
6628
3.92k
    }
6629
571k
    if (cur == NULL) return(NULL) ; /* ERROR */
6630
571k
    if (cur->next != NULL) return(cur->next) ;
6631
426k
    do {
6632
426k
        cur = cur->parent;
6633
426k
        if (cur == NULL) break;
6634
426k
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6635
422k
        if (cur->next != NULL) return(cur->next);
6636
422k
    } while (cur != NULL);
6637
478
    return(cur);
6638
274k
}
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
33.9k
{
6732
33.9k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6733
33.9k
    if (cur == NULL) {
6734
5.94k
        cur = ctxt->context->node;
6735
5.94k
        if (cur == NULL)
6736
0
            return (NULL);
6737
5.94k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6738
216
            cur = cur->parent;
6739
5.72k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6740
215
            xmlNsPtr ns = (xmlNsPtr) cur;
6741
6742
215
            if ((ns->next == NULL) ||
6743
215
                (ns->next->type == XML_NAMESPACE_DECL))
6744
0
                return (NULL);
6745
215
            cur = (xmlNodePtr) ns->next;
6746
215
        }
6747
5.94k
        ctxt->ancestor = cur->parent;
6748
5.94k
    }
6749
33.9k
    if (cur->type == XML_NAMESPACE_DECL)
6750
0
        return(NULL);
6751
33.9k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6752
277
  cur = cur->prev;
6753
45.1k
    while (cur->prev == NULL) {
6754
17.8k
        cur = cur->parent;
6755
17.8k
        if (cur == NULL)
6756
1.55k
            return (NULL);
6757
16.3k
        if (cur == ctxt->context->doc->children)
6758
4.15k
            return (NULL);
6759
12.1k
        if (cur != ctxt->ancestor)
6760
989
            return (cur);
6761
11.1k
        ctxt->ancestor = cur->parent;
6762
11.1k
    }
6763
27.2k
    cur = cur->prev;
6764
28.2k
    while (cur->last != NULL)
6765
1.00k
        cur = cur->last;
6766
27.2k
    return (cur);
6767
33.9k
}
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.73M
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6783
1.73M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6784
1.73M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6785
1.65M
    if (cur == NULL) {
6786
398k
        if (ctxt->context->tmpNsList != NULL)
6787
238
      xmlFree(ctxt->context->tmpNsList);
6788
398k
  ctxt->context->tmpNsNr = 0;
6789
398k
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6790
398k
                             &ctxt->context->tmpNsList) < 0) {
6791
1
            xmlXPathPErrMemory(ctxt);
6792
1
            return(NULL);
6793
1
        }
6794
398k
        if (ctxt->context->tmpNsList != NULL) {
6795
1.24M
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6796
862k
                ctxt->context->tmpNsNr++;
6797
862k
            }
6798
384k
        }
6799
398k
  return((xmlNodePtr) xmlXPathXMLNamespace);
6800
398k
    }
6801
1.25M
    if (ctxt->context->tmpNsNr > 0) {
6802
862k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6803
862k
    } else {
6804
396k
  if (ctxt->context->tmpNsList != NULL)
6805
384k
      xmlFree(ctxt->context->tmpNsList);
6806
396k
  ctxt->context->tmpNsList = NULL;
6807
396k
  return(NULL);
6808
396k
    }
6809
1.25M
}
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
68.7k
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6821
68.7k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6822
68.7k
    if (ctxt->context->node == NULL)
6823
0
  return(NULL);
6824
68.7k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6825
16.2k
  return(NULL);
6826
52.4k
    if (cur == NULL) {
6827
46.0k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6828
0
      return(NULL);
6829
46.0k
        return((xmlNodePtr)ctxt->context->node->properties);
6830
46.0k
    }
6831
6.39k
    return((xmlNodePtr)cur->next);
6832
52.4k
}
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
206k
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6856
206k
    if ((ctxt == NULL) || (ctxt->context == NULL))
6857
0
  return;
6858
206k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6859
206k
                                            (xmlNodePtr) ctxt->context->doc));
6860
206k
}
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
27.1k
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6880
81.4k
    CHECK_ARITY(0);
6881
81.4k
    if (ctxt->context->contextSize >= 0) {
6882
27.1k
  xmlXPathValuePush(ctxt,
6883
27.1k
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6884
27.1k
    } else {
6885
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6886
0
    }
6887
81.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
364k
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6901
1.09M
    CHECK_ARITY(0);
6902
1.09M
    if (ctxt->context->proximityPosition >= 0) {
6903
364k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6904
364k
            (double) ctxt->context->proximityPosition));
6905
364k
    } else {
6906
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6907
0
    }
6908
1.09M
}
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
651
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6919
651
    xmlXPathObjectPtr cur;
6920
6921
1.94k
    CHECK_ARITY(1);
6922
1.94k
    if ((ctxt->value == NULL) ||
6923
647
  ((ctxt->value->type != XPATH_NODESET) &&
6924
2
   (ctxt->value->type != XPATH_XSLT_TREE)))
6925
645
  XP_ERROR(XPATH_INVALID_TYPE);
6926
645
    cur = xmlXPathValuePop(ctxt);
6927
6928
645
    if ((cur == NULL) || (cur->nodesetval == NULL))
6929
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6930
645
    else
6931
645
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6932
645
      (double) cur->nodesetval->nodeNr));
6933
645
    xmlXPathReleaseObject(ctxt->context, cur);
6934
645
}
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
311k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6945
311k
    xmlNodeSetPtr ret;
6946
311k
    const xmlChar *cur = ids;
6947
311k
    xmlChar *ID;
6948
311k
    xmlAttrPtr attr;
6949
311k
    xmlNodePtr elem = NULL;
6950
6951
311k
    if (ids == NULL) return(NULL);
6952
6953
311k
    ret = xmlXPathNodeSetCreate(NULL);
6954
311k
    if (ret == NULL)
6955
8
        return(ret);
6956
6957
311k
    while (IS_BLANK_CH(*cur)) cur++;
6958
3.35M
    while (*cur != 0) {
6959
27.4M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6960
24.3M
      cur++;
6961
6962
3.04M
        ID = xmlStrndup(ids, cur - ids);
6963
3.04M
  if (ID == NULL) {
6964
27
            xmlXPathFreeNodeSet(ret);
6965
27
            return(NULL);
6966
27
        }
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
3.04M
        attr = xmlGetID(doc, ID);
6975
3.04M
        xmlFree(ID);
6976
3.04M
        if (attr != NULL) {
6977
3.59k
            if (attr->type == XML_ATTRIBUTE_NODE)
6978
3.59k
                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
3.59k
            if (elem != NULL) {
6984
3.59k
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
6985
7
                    xmlXPathFreeNodeSet(ret);
6986
7
                    return(NULL);
6987
7
                }
6988
3.59k
            }
6989
3.59k
        }
6990
6991
3.06M
  while (IS_BLANK_CH(*cur)) cur++;
6992
3.04M
  ids = cur;
6993
3.04M
    }
6994
311k
    return(ret);
6995
311k
}
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
13.3k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7016
13.3k
    xmlChar *tokens;
7017
13.3k
    xmlNodeSetPtr ret;
7018
13.3k
    xmlXPathObjectPtr obj;
7019
7020
39.8k
    CHECK_ARITY(1);
7021
39.8k
    obj = xmlXPathValuePop(ctxt);
7022
39.8k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7023
13.2k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7024
8.04k
  xmlNodeSetPtr ns;
7025
8.04k
  int i;
7026
7027
8.04k
  ret = xmlXPathNodeSetCreate(NULL);
7028
8.04k
        if (ret == NULL)
7029
1
            xmlXPathPErrMemory(ctxt);
7030
7031
8.04k
  if (obj->nodesetval != NULL) {
7032
313k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7033
305k
    tokens =
7034
305k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7035
305k
                if (tokens == NULL)
7036
7
                    xmlXPathPErrMemory(ctxt);
7037
305k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7038
305k
                if (ns == NULL)
7039
35
                    xmlXPathPErrMemory(ctxt);
7040
305k
    ret = xmlXPathNodeSetMerge(ret, ns);
7041
305k
                if (ret == NULL)
7042
2
                    xmlXPathPErrMemory(ctxt);
7043
305k
    xmlXPathFreeNodeSet(ns);
7044
305k
    if (tokens != NULL)
7045
305k
        xmlFree(tokens);
7046
305k
      }
7047
8.04k
  }
7048
8.04k
  xmlXPathReleaseObject(ctxt->context, obj);
7049
8.04k
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7050
8.04k
  return;
7051
8.04k
    }
7052
5.23k
    tokens = xmlXPathCastToString(obj);
7053
5.23k
    if (tokens == NULL)
7054
4
        xmlXPathPErrMemory(ctxt);
7055
5.23k
    xmlXPathReleaseObject(ctxt->context, obj);
7056
5.23k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7057
5.23k
    if (ret == NULL)
7058
18
        xmlXPathPErrMemory(ctxt);
7059
5.23k
    xmlFree(tokens);
7060
5.23k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7061
5.23k
}
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
5.93k
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7077
5.93k
    xmlXPathObjectPtr cur;
7078
7079
5.93k
    if (ctxt == NULL) return;
7080
7081
5.93k
    if (nargs == 0) {
7082
394
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7083
394
  nargs = 1;
7084
394
    }
7085
7086
17.8k
    CHECK_ARITY(1);
7087
17.8k
    if ((ctxt->value == NULL) ||
7088
5.93k
  ((ctxt->value->type != XPATH_NODESET) &&
7089
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
7090
5.93k
  XP_ERROR(XPATH_INVALID_TYPE);
7091
5.93k
    cur = xmlXPathValuePop(ctxt);
7092
7093
5.93k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7094
213
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7095
5.72k
    } else {
7096
5.72k
  int i = 0; /* Should be first in document order !!!!! */
7097
5.72k
  switch (cur->nodesetval->nodeTab[i]->type) {
7098
200
  case XML_ELEMENT_NODE:
7099
394
  case XML_ATTRIBUTE_NODE:
7100
609
  case XML_PI_NODE:
7101
609
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7102
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7103
609
      else
7104
609
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7105
609
      cur->nodesetval->nodeTab[i]->name));
7106
609
      break;
7107
1.04k
  case XML_NAMESPACE_DECL:
7108
1.04k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7109
1.04k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7110
1.04k
      break;
7111
4.06k
  default:
7112
4.06k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7113
5.72k
  }
7114
5.72k
    }
7115
5.93k
    xmlXPathReleaseObject(ctxt->context, cur);
7116
5.93k
}
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
1.11k
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7133
1.11k
    xmlXPathObjectPtr cur;
7134
7135
1.11k
    if (ctxt == NULL) return;
7136
7137
1.11k
    if (nargs == 0) {
7138
536
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7139
536
  nargs = 1;
7140
536
    }
7141
3.33k
    CHECK_ARITY(1);
7142
3.33k
    if ((ctxt->value == NULL) ||
7143
1.11k
  ((ctxt->value->type != XPATH_NODESET) &&
7144
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
7145
1.10k
  XP_ERROR(XPATH_INVALID_TYPE);
7146
1.10k
    cur = xmlXPathValuePop(ctxt);
7147
7148
1.10k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7149
215
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7150
894
    } else {
7151
894
  int i = 0; /* Should be first in document order !!!!! */
7152
894
  switch (cur->nodesetval->nodeTab[i]->type) {
7153
535
  case XML_ELEMENT_NODE:
7154
535
  case XML_ATTRIBUTE_NODE:
7155
535
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7156
336
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7157
199
      else
7158
199
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7159
199
        cur->nodesetval->nodeTab[i]->ns->href));
7160
535
      break;
7161
359
  default:
7162
359
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7163
894
  }
7164
894
    }
7165
1.10k
    xmlXPathReleaseObject(ctxt->context, cur);
7166
1.10k
}
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
18.2k
{
7192
18.2k
    xmlXPathObjectPtr cur;
7193
7194
18.2k
    if (nargs == 0) {
7195
17.5k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7196
17.5k
        nargs = 1;
7197
17.5k
    }
7198
7199
54.7k
    CHECK_ARITY(1);
7200
54.7k
    if ((ctxt->value == NULL) ||
7201
18.2k
        ((ctxt->value->type != XPATH_NODESET) &&
7202
1
         (ctxt->value->type != XPATH_XSLT_TREE)))
7203
18.2k
        XP_ERROR(XPATH_INVALID_TYPE);
7204
18.2k
    cur = xmlXPathValuePop(ctxt);
7205
7206
18.2k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7207
682
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7208
17.5k
    } else {
7209
17.5k
        int i = 0;              /* Should be first in document order !!!!! */
7210
7211
17.5k
        switch (cur->nodesetval->nodeTab[i]->type) {
7212
12.2k
            case XML_ELEMENT_NODE:
7213
12.2k
            case XML_ATTRIBUTE_NODE:
7214
12.2k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7215
0
        xmlXPathValuePush(ctxt,
7216
0
      xmlXPathCacheNewCString(ctxt, ""));
7217
12.2k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7218
11.8k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7219
11.8k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7220
11.8k
          cur->nodesetval->nodeTab[i]->name));
7221
11.8k
    } else {
7222
421
        xmlChar *fullname;
7223
7224
421
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7225
421
             cur->nodesetval->nodeTab[i]->ns->prefix,
7226
421
             NULL, 0);
7227
421
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7228
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7229
421
        if (fullname == NULL)
7230
1
                        xmlXPathPErrMemory(ctxt);
7231
421
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7232
421
                }
7233
12.2k
                break;
7234
5.32k
            default:
7235
5.32k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7236
5.32k
        cur->nodesetval->nodeTab[i]));
7237
5.32k
                xmlXPathLocalNameFunction(ctxt, 1);
7238
17.5k
        }
7239
17.5k
    }
7240
18.2k
    xmlXPathReleaseObject(ctxt->context, cur);
7241
18.2k
}
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
30.9k
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7281
30.9k
    xmlXPathObjectPtr cur;
7282
30.9k
    xmlChar *stringval;
7283
7284
30.9k
    if (ctxt == NULL) return;
7285
30.9k
    if (nargs == 0) {
7286
610
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7287
610
        if (stringval == NULL)
7288
1
            xmlXPathPErrMemory(ctxt);
7289
610
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7290
610
  return;
7291
610
    }
7292
7293
121k
    CHECK_ARITY(1);
7294
121k
    cur = xmlXPathValuePop(ctxt);
7295
121k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7296
30.3k
    if (cur->type != XPATH_STRING) {
7297
30.1k
        stringval = xmlXPathCastToString(cur);
7298
30.1k
        if (stringval == NULL)
7299
29
            xmlXPathPErrMemory(ctxt);
7300
30.1k
        xmlXPathReleaseObject(ctxt->context, cur);
7301
30.1k
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7302
30.1k
    }
7303
30.3k
    xmlXPathValuePush(ctxt, cur);
7304
30.3k
}
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
1.48k
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7319
1.48k
    xmlXPathObjectPtr cur;
7320
7321
1.48k
    if (nargs == 0) {
7322
623
        if ((ctxt == NULL) || (ctxt->context == NULL))
7323
0
      return;
7324
623
  if (ctxt->context->node == NULL) {
7325
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7326
623
  } else {
7327
623
      xmlChar *content;
7328
7329
623
      content = xmlXPathCastNodeToString(ctxt->context->node);
7330
623
            if (content == NULL)
7331
1
                xmlXPathPErrMemory(ctxt);
7332
623
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7333
623
    xmlUTF8Strlen(content)));
7334
623
      xmlFree(content);
7335
623
  }
7336
623
  return;
7337
623
    }
7338
3.43k
    CHECK_ARITY(1);
7339
3.43k
    CAST_TO_STRING;
7340
3.43k
    CHECK_TYPE(XPATH_STRING);
7341
855
    cur = xmlXPathValuePop(ctxt);
7342
855
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7343
855
  xmlUTF8Strlen(cur->stringval)));
7344
855
    xmlXPathReleaseObject(ctxt->context, cur);
7345
855
}
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
1.31k
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7357
1.31k
    xmlXPathObjectPtr cur, newobj;
7358
1.31k
    xmlChar *tmp;
7359
7360
1.31k
    if (ctxt == NULL) return;
7361
1.31k
    if (nargs < 2) {
7362
1
  CHECK_ARITY(2);
7363
1
    }
7364
7365
1.31k
    CAST_TO_STRING;
7366
1.31k
    cur = xmlXPathValuePop(ctxt);
7367
1.31k
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7368
1
  xmlXPathReleaseObject(ctxt->context, cur);
7369
1
  return;
7370
1
    }
7371
1.31k
    nargs--;
7372
7373
3.79k
    while (nargs > 0) {
7374
2.48k
  CAST_TO_STRING;
7375
2.48k
  newobj = xmlXPathValuePop(ctxt);
7376
2.48k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7377
3
      xmlXPathReleaseObject(ctxt->context, newobj);
7378
3
      xmlXPathReleaseObject(ctxt->context, cur);
7379
3
      XP_ERROR(XPATH_INVALID_TYPE);
7380
0
  }
7381
2.47k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7382
2.47k
        if (tmp == NULL)
7383
1
            xmlXPathPErrMemory(ctxt);
7384
2.47k
  newobj->stringval = cur->stringval;
7385
2.47k
  cur->stringval = tmp;
7386
2.47k
  xmlXPathReleaseObject(ctxt->context, newobj);
7387
2.47k
  nargs--;
7388
2.47k
    }
7389
1.30k
    xmlXPathValuePush(ctxt, cur);
7390
1.30k
}
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.08k
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7403
1.08k
    xmlXPathObjectPtr hay, needle;
7404
7405
3.26k
    CHECK_ARITY(2);
7406
3.26k
    CAST_TO_STRING;
7407
3.26k
    CHECK_TYPE(XPATH_STRING);
7408
1.08k
    needle = xmlXPathValuePop(ctxt);
7409
1.08k
    CAST_TO_STRING;
7410
1.08k
    hay = xmlXPathValuePop(ctxt);
7411
7412
1.08k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7413
2
  xmlXPathReleaseObject(ctxt->context, hay);
7414
2
  xmlXPathReleaseObject(ctxt->context, needle);
7415
2
  XP_ERROR(XPATH_INVALID_TYPE);
7416
0
    }
7417
1.08k
    if (xmlStrstr(hay->stringval, needle->stringval))
7418
696
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7419
388
    else
7420
388
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7421
1.08k
    xmlXPathReleaseObject(ctxt->context, hay);
7422
1.08k
    xmlXPathReleaseObject(ctxt->context, needle);
7423
1.08k
}
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
708
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7436
708
    xmlXPathObjectPtr hay, needle;
7437
708
    int n;
7438
7439
2.12k
    CHECK_ARITY(2);
7440
2.12k
    CAST_TO_STRING;
7441
2.12k
    CHECK_TYPE(XPATH_STRING);
7442
706
    needle = xmlXPathValuePop(ctxt);
7443
706
    CAST_TO_STRING;
7444
706
    hay = xmlXPathValuePop(ctxt);
7445
7446
706
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7447
2
  xmlXPathReleaseObject(ctxt->context, hay);
7448
2
  xmlXPathReleaseObject(ctxt->context, needle);
7449
2
  XP_ERROR(XPATH_INVALID_TYPE);
7450
0
    }
7451
704
    n = xmlStrlen(needle->stringval);
7452
704
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7453
403
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7454
301
    else
7455
301
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7456
704
    xmlXPathReleaseObject(ctxt->context, hay);
7457
704
    xmlXPathReleaseObject(ctxt->context, needle);
7458
704
}
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
2.65k
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7489
2.65k
    xmlXPathObjectPtr str, start, len;
7490
2.65k
    double le=0, in;
7491
2.65k
    int i = 1, j = INT_MAX;
7492
7493
2.65k
    if (nargs < 2) {
7494
1
  CHECK_ARITY(2);
7495
1
    }
7496
2.65k
    if (nargs > 3) {
7497
1
  CHECK_ARITY(3);
7498
1
    }
7499
    /*
7500
     * take care of possible last (position) argument
7501
    */
7502
2.65k
    if (nargs == 3) {
7503
1.26k
  CAST_TO_NUMBER;
7504
1.26k
  CHECK_TYPE(XPATH_NUMBER);
7505
1.26k
  len = xmlXPathValuePop(ctxt);
7506
1.26k
  le = len->floatval;
7507
1.26k
  xmlXPathReleaseObject(ctxt->context, len);
7508
1.26k
    }
7509
7510
2.65k
    CAST_TO_NUMBER;
7511
2.65k
    CHECK_TYPE(XPATH_NUMBER);
7512
2.65k
    start = xmlXPathValuePop(ctxt);
7513
2.65k
    in = start->floatval;
7514
2.65k
    xmlXPathReleaseObject(ctxt->context, start);
7515
2.65k
    CAST_TO_STRING;
7516
2.65k
    CHECK_TYPE(XPATH_STRING);
7517
2.65k
    str = xmlXPathValuePop(ctxt);
7518
7519
2.65k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7520
870
        i = INT_MAX;
7521
1.78k
    } else if (in >= 1.0) {
7522
1.08k
        i = (int)in;
7523
1.08k
        if (in - floor(in) >= 0.5)
7524
227
            i += 1;
7525
1.08k
    }
7526
7527
2.65k
    if (nargs == 3) {
7528
1.26k
        double rin, rle, end;
7529
7530
1.26k
        rin = floor(in);
7531
1.26k
        if (in - rin >= 0.5)
7532
194
            rin += 1.0;
7533
7534
1.26k
        rle = floor(le);
7535
1.26k
        if (le - rle >= 0.5)
7536
194
            rle += 1.0;
7537
7538
1.26k
        end = rin + rle;
7539
1.26k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7540
448
            j = 1;
7541
812
        } else if (end < INT_MAX) {
7542
595
            j = (int)end;
7543
595
        }
7544
1.26k
    }
7545
7546
2.65k
    i -= 1;
7547
2.65k
    j -= 1;
7548
7549
2.65k
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7550
861
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7551
861
        if (ret == NULL)
7552
5
            xmlXPathPErrMemory(ctxt);
7553
861
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7554
861
  xmlFree(ret);
7555
1.79k
    } else {
7556
1.79k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7557
1.79k
    }
7558
7559
2.65k
    xmlXPathReleaseObject(ctxt->context, str);
7560
2.65k
}
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
1.20k
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7576
1.20k
    xmlXPathObjectPtr str = NULL;
7577
1.20k
    xmlXPathObjectPtr find = NULL;
7578
1.20k
    const xmlChar *point;
7579
1.20k
    xmlChar *result;
7580
7581
3.60k
    CHECK_ARITY(2);
7582
3.60k
    CAST_TO_STRING;
7583
3.60k
    find = xmlXPathValuePop(ctxt);
7584
3.60k
    CAST_TO_STRING;
7585
3.60k
    str = xmlXPathValuePop(ctxt);
7586
3.60k
    if (ctxt->error != 0)
7587
2
        goto error;
7588
7589
1.19k
    point = xmlStrstr(str->stringval, find->stringval);
7590
1.19k
    if (point == NULL) {
7591
697
        result = xmlStrdup(BAD_CAST "");
7592
697
    } else {
7593
502
        result = xmlStrndup(str->stringval, point - str->stringval);
7594
502
    }
7595
1.19k
    if (result == NULL) {
7596
1
        xmlXPathPErrMemory(ctxt);
7597
1
        goto error;
7598
1
    }
7599
1.19k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7600
7601
1.20k
error:
7602
1.20k
    xmlXPathReleaseObject(ctxt->context, str);
7603
1.20k
    xmlXPathReleaseObject(ctxt->context, find);
7604
1.20k
}
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
1.55k
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7621
1.55k
    xmlXPathObjectPtr str = NULL;
7622
1.55k
    xmlXPathObjectPtr find = NULL;
7623
1.55k
    const xmlChar *point;
7624
1.55k
    xmlChar *result;
7625
7626
4.67k
    CHECK_ARITY(2);
7627
4.67k
    CAST_TO_STRING;
7628
4.67k
    find = xmlXPathValuePop(ctxt);
7629
4.67k
    CAST_TO_STRING;
7630
4.67k
    str = xmlXPathValuePop(ctxt);
7631
4.67k
    if (ctxt->error != 0)
7632
3
        goto error;
7633
7634
1.55k
    point = xmlStrstr(str->stringval, find->stringval);
7635
1.55k
    if (point == NULL) {
7636
475
        result = xmlStrdup(BAD_CAST "");
7637
1.07k
    } else {
7638
1.07k
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7639
1.07k
    }
7640
1.55k
    if (result == NULL) {
7641
3
        xmlXPathPErrMemory(ctxt);
7642
3
        goto error;
7643
3
    }
7644
1.55k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7645
7646
1.55k
error:
7647
1.55k
    xmlXPathReleaseObject(ctxt->context, str);
7648
1.55k
    xmlXPathReleaseObject(ctxt->context, find);
7649
1.55k
}
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
19.6k
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7666
19.6k
    xmlChar *source, *target;
7667
19.6k
    int blank;
7668
7669
19.6k
    if (ctxt == NULL) return;
7670
19.6k
    if (nargs == 0) {
7671
        /* Use current context node */
7672
18.9k
        source = xmlXPathCastNodeToString(ctxt->context->node);
7673
18.9k
        if (source == NULL)
7674
2
            xmlXPathPErrMemory(ctxt);
7675
18.9k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7676
18.9k
        nargs = 1;
7677
18.9k
    }
7678
7679
58.9k
    CHECK_ARITY(1);
7680
58.9k
    CAST_TO_STRING;
7681
58.9k
    CHECK_TYPE(XPATH_STRING);
7682
19.6k
    source = ctxt->value->stringval;
7683
19.6k
    if (source == NULL)
7684
3
        return;
7685
19.6k
    target = source;
7686
7687
    /* Skip leading whitespaces */
7688
19.6k
    while (IS_BLANK_CH(*source))
7689
429
        source++;
7690
7691
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7692
19.6k
    blank = 0;
7693
181k
    while (*source) {
7694
161k
        if (IS_BLANK_CH(*source)) {
7695
807
      blank = 1;
7696
161k
        } else {
7697
161k
            if (blank) {
7698
327
                *target++ = 0x20;
7699
327
                blank = 0;
7700
327
            }
7701
161k
            *target++ = *source;
7702
161k
        }
7703
161k
        source++;
7704
161k
    }
7705
19.6k
    *target = 0;
7706
19.6k
}
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
3.60k
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7731
3.60k
    xmlXPathObjectPtr str = NULL;
7732
3.60k
    xmlXPathObjectPtr from = NULL;
7733
3.60k
    xmlXPathObjectPtr to = NULL;
7734
3.60k
    xmlBufPtr target;
7735
3.60k
    int offset, max;
7736
3.60k
    int ch;
7737
3.60k
    const xmlChar *point;
7738
3.60k
    xmlChar *cptr, *content;
7739
7740
10.7k
    CHECK_ARITY(3);
7741
7742
10.7k
    CAST_TO_STRING;
7743
10.7k
    to = xmlXPathValuePop(ctxt);
7744
10.7k
    CAST_TO_STRING;
7745
10.7k
    from = xmlXPathValuePop(ctxt);
7746
10.7k
    CAST_TO_STRING;
7747
10.7k
    str = xmlXPathValuePop(ctxt);
7748
10.7k
    if (ctxt->error != 0)
7749
4
        goto error;
7750
7751
    /*
7752
     * Account for quadratic runtime
7753
     */
7754
3.59k
    if (ctxt->context->opLimit != 0) {
7755
3.59k
        unsigned long f1 = xmlStrlen(from->stringval);
7756
3.59k
        unsigned long f2 = xmlStrlen(str->stringval);
7757
7758
3.59k
        if ((f1 > 0) && (f2 > 0)) {
7759
2.53k
            unsigned long p;
7760
7761
2.53k
            f1 = f1 / 10 + 1;
7762
2.53k
            f2 = f2 / 10 + 1;
7763
2.53k
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7764
2.53k
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7765
26
                goto error;
7766
2.53k
        }
7767
3.59k
    }
7768
7769
3.56k
    target = xmlBufCreate(50);
7770
3.56k
    if (target == NULL) {
7771
2
        xmlXPathPErrMemory(ctxt);
7772
2
        goto error;
7773
2
    }
7774
7775
3.56k
    max = xmlUTF8Strlen(to->stringval);
7776
825k
    for (cptr = str->stringval; (ch=*cptr); ) {
7777
822k
        offset = xmlUTF8Strloc(from->stringval, cptr);
7778
822k
        if (offset >= 0) {
7779
174k
            if (offset < max) {
7780
123k
                point = xmlUTF8Strpos(to->stringval, offset);
7781
123k
                if (point)
7782
123k
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7783
123k
            }
7784
174k
        } else
7785
648k
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7786
7787
        /* Step to next character in input */
7788
822k
        cptr++;
7789
822k
        if ( ch & 0x80 ) {
7790
            /* if not simple ascii, verify proper format */
7791
181k
            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
540k
            while ( (ch <<= 1) & 0x80 )
7797
358k
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7798
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7799
0
                    break;
7800
0
                }
7801
181k
            if (ch & 0x80) /* must have had error encountered */
7802
0
                break;
7803
181k
        }
7804
822k
    }
7805
7806
3.56k
    content = xmlBufDetach(target);
7807
3.56k
    if (content == NULL)
7808
8
        xmlXPathPErrMemory(ctxt);
7809
3.55k
    else
7810
3.55k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7811
3.56k
    xmlBufFree(target);
7812
3.59k
error:
7813
3.59k
    xmlXPathReleaseObject(ctxt->context, str);
7814
3.59k
    xmlXPathReleaseObject(ctxt->context, from);
7815
3.59k
    xmlXPathReleaseObject(ctxt->context, to);
7816
3.59k
}
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
100k
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7832
100k
    xmlXPathObjectPtr cur;
7833
7834
301k
    CHECK_ARITY(1);
7835
301k
    cur = xmlXPathValuePop(ctxt);
7836
301k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7837
100k
    if (cur->type != XPATH_BOOLEAN) {
7838
99.2k
        int boolval = xmlXPathCastToBoolean(cur);
7839
7840
99.2k
        xmlXPathReleaseObject(ctxt->context, cur);
7841
99.2k
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7842
99.2k
    }
7843
100k
    xmlXPathValuePush(ctxt, cur);
7844
100k
}
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
600
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7857
1.79k
    CHECK_ARITY(1);
7858
1.79k
    CAST_TO_BOOLEAN;
7859
1.79k
    CHECK_TYPE(XPATH_BOOLEAN);
7860
597
    ctxt->value->boolval = ! ctxt->value->boolval;
7861
597
}
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
781
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7872
2.34k
    CHECK_ARITY(0);
7873
2.34k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7874
2.34k
}
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
670
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7885
2.00k
    CHECK_ARITY(0);
7886
2.00k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7887
2.00k
}
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
8.23k
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7911
8.23k
    xmlXPathObjectPtr val;
7912
8.23k
    xmlNodePtr cur;
7913
8.23k
    xmlChar *theLang = NULL;
7914
8.23k
    const xmlChar *lang;
7915
8.23k
    int ret = 0;
7916
8.23k
    int i;
7917
7918
24.6k
    CHECK_ARITY(1);
7919
24.6k
    CAST_TO_STRING;
7920
24.6k
    CHECK_TYPE(XPATH_STRING);
7921
8.22k
    val = xmlXPathValuePop(ctxt);
7922
8.22k
    lang = val->stringval;
7923
8.22k
    cur = ctxt->context->node;
7924
50.5k
    while (cur != NULL) {
7925
43.0k
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7926
43.0k
                                &theLang) < 0)
7927
1
            xmlXPathPErrMemory(ctxt);
7928
43.0k
        if (theLang != NULL)
7929
796
            break;
7930
42.2k
        cur = cur->parent;
7931
42.2k
    }
7932
8.22k
    if ((theLang != NULL) && (lang != NULL)) {
7933
1.50k
        for (i = 0;lang[i] != 0;i++)
7934
912
            if (toupper(lang[i]) != toupper(theLang[i]))
7935
206
                goto not_equal;
7936
589
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7937
392
            ret = 1;
7938
589
    }
7939
8.22k
not_equal:
7940
8.22k
    if (theLang != NULL)
7941
796
  xmlFree((void *)theLang);
7942
7943
8.22k
    xmlXPathReleaseObject(ctxt->context, val);
7944
8.22k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7945
8.22k
}
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
1.19M
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7956
1.19M
    xmlXPathObjectPtr cur;
7957
1.19M
    double res;
7958
7959
1.19M
    if (ctxt == NULL) return;
7960
1.19M
    if (nargs == 0) {
7961
1.70k
  if (ctxt->context->node == NULL) {
7962
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7963
1.70k
  } else {
7964
1.70k
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7965
1.70k
            if (content == NULL)
7966
3
                xmlXPathPErrMemory(ctxt);
7967
7968
1.70k
      res = xmlXPathStringEvalNumber(content);
7969
1.70k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
7970
1.70k
      xmlFree(content);
7971
1.70k
  }
7972
1.70k
  return;
7973
1.70k
    }
7974
7975
4.77M
    CHECK_ARITY(1);
7976
4.77M
    cur = xmlXPathValuePop(ctxt);
7977
4.77M
    if (cur->type != XPATH_NUMBER) {
7978
1.19M
        double floatval;
7979
7980
1.19M
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
7981
1.19M
        xmlXPathReleaseObject(ctxt->context, cur);
7982
1.19M
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
7983
1.19M
    }
7984
4.77M
    xmlXPathValuePush(ctxt, cur);
7985
4.77M
}
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
20.8k
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
7998
20.8k
    xmlXPathObjectPtr cur;
7999
20.8k
    int i;
8000
20.8k
    double res = 0.0;
8001
8002
62.5k
    CHECK_ARITY(1);
8003
62.5k
    if ((ctxt->value == NULL) ||
8004
20.8k
  ((ctxt->value->type != XPATH_NODESET) &&
8005
4
   (ctxt->value->type != XPATH_XSLT_TREE)))
8006
20.8k
  XP_ERROR(XPATH_INVALID_TYPE);
8007
20.8k
    cur = xmlXPathValuePop(ctxt);
8008
8009
20.8k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8010
4.57M
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8011
4.55M
      res += xmlXPathNodeToNumberInternal(ctxt,
8012
4.55M
                                                cur->nodesetval->nodeTab[i]);
8013
4.55M
  }
8014
20.4k
    }
8015
20.8k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8016
20.8k
    xmlXPathReleaseObject(ctxt->context, cur);
8017
20.8k
}
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
620
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
1.85k
    CHECK_ARITY(1);
8031
1.85k
    CAST_TO_NUMBER;
8032
1.85k
    CHECK_TYPE(XPATH_NUMBER);
8033
8034
617
    ctxt->value->floatval = floor(ctxt->value->floatval);
8035
617
}
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
411
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8048
1.23k
    CHECK_ARITY(1);
8049
1.23k
    CAST_TO_NUMBER;
8050
1.23k
    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
408
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8057
408
#endif
8058
408
}
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
819
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8072
819
    double f;
8073
8074
2.45k
    CHECK_ARITY(1);
8075
2.45k
    CAST_TO_NUMBER;
8076
2.45k
    CHECK_TYPE(XPATH_NUMBER);
8077
8078
816
    f = ctxt->value->floatval;
8079
8080
816
    if ((f >= -0.5) && (f < 0.5)) {
8081
        /* Handles negative zero. */
8082
196
        ctxt->value->floatval *= 0.0;
8083
196
    }
8084
620
    else {
8085
620
        double rounded = floor(f);
8086
620
        if (f - rounded >= 0.5)
8087
199
            rounded += 1.0;
8088
620
        ctxt->value->floatval = rounded;
8089
620
    }
8090
816
}
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
76.3k
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8116
76.3k
    const xmlChar *end;
8117
76.3k
    xmlChar *ret;
8118
8119
76.3k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8120
8121
76.3k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8122
76.3k
    if (end == NULL) {
8123
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8124
0
    }
8125
76.3k
    if (end == ctxt->cur)
8126
3.50k
        return(NULL);
8127
8128
72.8k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8129
72.8k
    if (ret == NULL)
8130
28
        xmlXPathPErrMemory(ctxt);
8131
72.8k
    ctxt->cur = end;
8132
72.8k
    return(ret);
8133
76.3k
}
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
6.93k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8147
6.93k
    xmlChar *ret = NULL;
8148
8149
6.93k
    *prefix = NULL;
8150
6.93k
    ret = xmlXPathParseNCName(ctxt);
8151
6.93k
    if (ret && CUR == ':') {
8152
446
        *prefix = ret;
8153
446
  NEXT;
8154
446
  ret = xmlXPathParseNCName(ctxt);
8155
446
    }
8156
6.93k
    return(ret);
8157
6.93k
}
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
36.7k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8168
36.7k
    const xmlChar *end;
8169
36.7k
    xmlChar *ret;
8170
8171
36.7k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8172
8173
36.7k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8174
36.7k
    if (end == NULL) {
8175
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8176
0
    }
8177
36.7k
    if (end == ctxt->cur)
8178
19.2k
        return(NULL);
8179
8180
17.5k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8181
17.5k
    if (ret == NULL)
8182
6
        xmlXPathPErrMemory(ctxt);
8183
17.5k
    ctxt->cur = end;
8184
17.5k
    return(ret);
8185
36.7k
}
8186
8187
2.99k
#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
5.80M
xmlXPathStringEvalNumber(const xmlChar *str) {
8205
5.80M
    const xmlChar *cur = str;
8206
5.80M
    double ret;
8207
5.80M
    int ok = 0;
8208
5.80M
    int isneg = 0;
8209
5.80M
    int exponent = 0;
8210
5.80M
    int is_exponent_negative = 0;
8211
5.80M
#ifdef __GNUC__
8212
5.80M
    unsigned long tmp = 0;
8213
5.80M
    double temp;
8214
5.80M
#endif
8215
5.80M
    if (cur == NULL) return(0);
8216
5.80M
    while (IS_BLANK_CH(*cur)) cur++;
8217
5.80M
    if (*cur == '-') {
8218
3.42k
  isneg = 1;
8219
3.42k
  cur++;
8220
3.42k
    }
8221
5.80M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8222
5.77M
        return(xmlXPathNAN);
8223
5.77M
    }
8224
8225
29.2k
#ifdef __GNUC__
8226
    /*
8227
     * tmp/temp is a workaround against a gcc compiler bug
8228
     * http://veillard.com/gcc.bug
8229
     */
8230
29.2k
    ret = 0;
8231
59.3k
    while ((*cur >= '0') && (*cur <= '9')) {
8232
30.1k
  ret = ret * 10;
8233
30.1k
  tmp = (*cur - '0');
8234
30.1k
  ok = 1;
8235
30.1k
  cur++;
8236
30.1k
  temp = (double) tmp;
8237
30.1k
  ret = ret + temp;
8238
30.1k
    }
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
29.2k
    if (*cur == '.') {
8249
2.81k
  int v, frac = 0, max;
8250
2.81k
  double fraction = 0;
8251
8252
2.81k
        cur++;
8253
2.81k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8254
1.41k
      return(xmlXPathNAN);
8255
1.41k
  }
8256
2.11k
        while (*cur == '0') {
8257
709
      frac = frac + 1;
8258
709
      cur++;
8259
709
        }
8260
1.40k
        max = frac + MAX_FRAC;
8261
3.31k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8262
1.91k
      v = (*cur - '0');
8263
1.91k
      fraction = fraction * 10 + v;
8264
1.91k
      frac = frac + 1;
8265
1.91k
      cur++;
8266
1.91k
  }
8267
1.40k
  fraction /= pow(10.0, frac);
8268
1.40k
  ret = ret + fraction;
8269
1.60k
  while ((*cur >= '0') && (*cur <= '9'))
8270
201
      cur++;
8271
1.40k
    }
8272
27.7k
    if ((*cur == 'e') || (*cur == 'E')) {
8273
2.13k
      cur++;
8274
2.13k
      if (*cur == '-') {
8275
219
  is_exponent_negative = 1;
8276
219
  cur++;
8277
1.91k
      } else if (*cur == '+') {
8278
224
        cur++;
8279
224
      }
8280
5.61k
      while ((*cur >= '0') && (*cur <= '9')) {
8281
3.48k
        if (exponent < 1000000)
8282
3.23k
    exponent = exponent * 10 + (*cur - '0');
8283
3.48k
  cur++;
8284
3.48k
      }
8285
2.13k
    }
8286
27.7k
    while (IS_BLANK_CH(*cur)) cur++;
8287
27.7k
    if (*cur != 0) return(xmlXPathNAN);
8288
16.1k
    if (isneg) ret = -ret;
8289
16.1k
    if (is_exponent_negative) exponent = -exponent;
8290
16.1k
    ret *= pow(10.0, (double)exponent);
8291
16.1k
    return(ret);
8292
27.7k
}
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
11.9k
{
8306
11.9k
    double ret = 0.0;
8307
11.9k
    int ok = 0;
8308
11.9k
    int exponent = 0;
8309
11.9k
    int is_exponent_negative = 0;
8310
11.9k
    xmlXPathObjectPtr num;
8311
11.9k
#ifdef __GNUC__
8312
11.9k
    unsigned long tmp = 0;
8313
11.9k
    double temp;
8314
11.9k
#endif
8315
8316
11.9k
    CHECK_ERROR;
8317
11.9k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8318
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8319
0
    }
8320
11.9k
#ifdef __GNUC__
8321
    /*
8322
     * tmp/temp is a workaround against a gcc compiler bug
8323
     * http://veillard.com/gcc.bug
8324
     */
8325
11.9k
    ret = 0;
8326
29.9k
    while ((CUR >= '0') && (CUR <= '9')) {
8327
17.9k
  ret = ret * 10;
8328
17.9k
  tmp = (CUR - '0');
8329
17.9k
        ok = 1;
8330
17.9k
        NEXT;
8331
17.9k
  temp = (double) tmp;
8332
17.9k
  ret = ret + temp;
8333
17.9k
    }
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
11.9k
    if (CUR == '.') {
8343
1.59k
  int v, frac = 0, max;
8344
1.59k
  double fraction = 0;
8345
8346
1.59k
        NEXT;
8347
1.59k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8348
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8349
0
        }
8350
2.22k
        while (CUR == '0') {
8351
631
            frac = frac + 1;
8352
631
            NEXT;
8353
631
        }
8354
1.59k
        max = frac + MAX_FRAC;
8355
2.60k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8356
1.01k
      v = (CUR - '0');
8357
1.01k
      fraction = fraction * 10 + v;
8358
1.01k
      frac = frac + 1;
8359
1.01k
            NEXT;
8360
1.01k
        }
8361
1.59k
        fraction /= pow(10.0, frac);
8362
1.59k
        ret = ret + fraction;
8363
1.78k
        while ((CUR >= '0') && (CUR <= '9'))
8364
194
            NEXT;
8365
1.59k
    }
8366
11.9k
    if ((CUR == 'e') || (CUR == 'E')) {
8367
1.50k
        NEXT;
8368
1.50k
        if (CUR == '-') {
8369
342
            is_exponent_negative = 1;
8370
342
            NEXT;
8371
1.16k
        } else if (CUR == '+') {
8372
196
      NEXT;
8373
196
  }
8374
4.19k
        while ((CUR >= '0') && (CUR <= '9')) {
8375
2.69k
            if (exponent < 1000000)
8376
2.30k
                exponent = exponent * 10 + (CUR - '0');
8377
2.69k
            NEXT;
8378
2.69k
        }
8379
1.50k
        if (is_exponent_negative)
8380
342
            exponent = -exponent;
8381
1.50k
        ret *= pow(10.0, (double) exponent);
8382
1.50k
    }
8383
11.9k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8384
11.9k
    if (num == NULL) {
8385
2
  ctxt->error = XPATH_MEMORY_ERROR;
8386
11.9k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8387
11.9k
                              NULL) == -1) {
8388
1
        xmlXPathReleaseObject(ctxt->context, num);
8389
1
    }
8390
11.9k
}
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
2.23k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8403
2.23k
    const xmlChar *q;
8404
2.23k
    xmlChar *ret = NULL;
8405
2.23k
    int quote;
8406
8407
2.23k
    if (CUR == '"') {
8408
1.00k
        quote = '"';
8409
1.22k
    } else if (CUR == '\'') {
8410
1.22k
        quote = '\'';
8411
1.22k
    } else {
8412
7
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8413
0
    }
8414
8415
2.22k
    NEXT;
8416
2.22k
    q = CUR_PTR;
8417
8.51k
    while (CUR != quote) {
8418
6.38k
        int ch;
8419
6.38k
        int len = 4;
8420
8421
6.38k
        if (CUR == 0)
8422
6.30k
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8423
6.30k
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8424
6.30k
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8425
6.29k
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8426
6.29k
        CUR_PTR += len;
8427
6.29k
    }
8428
2.12k
    ret = xmlStrndup(q, CUR_PTR - q);
8429
2.12k
    if (ret == NULL)
8430
2
        xmlXPathPErrMemory(ctxt);
8431
2.12k
    NEXT;
8432
2.12k
    return(ret);
8433
2.22k
}
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
2.08k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8447
2.08k
    xmlChar *ret = NULL;
8448
2.08k
    xmlXPathObjectPtr lit;
8449
8450
2.08k
    ret = xmlXPathParseLiteral(ctxt);
8451
2.08k
    if (ret == NULL)
8452
97
        return;
8453
1.99k
    lit = xmlXPathCacheNewString(ctxt, ret);
8454
1.99k
    if (lit == NULL) {
8455
1
        ctxt->error = XPATH_MEMORY_ERROR;
8456
1.98k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8457
1.98k
                              NULL) == -1) {
8458
1
        xmlXPathReleaseObject(ctxt->context, lit);
8459
1
    }
8460
1.99k
    xmlFree(ret);
8461
1.99k
}
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
729
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8480
729
    xmlChar *name;
8481
729
    xmlChar *prefix;
8482
8483
729
    SKIP_BLANKS;
8484
729
    if (CUR != '$') {
8485
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8486
0
    }
8487
729
    NEXT;
8488
729
    name = xmlXPathParseQName(ctxt, &prefix);
8489
729
    if (name == NULL) {
8490
212
        xmlFree(prefix);
8491
212
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8492
0
    }
8493
517
    ctxt->comp->last = -1;
8494
517
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8495
1
        xmlFree(prefix);
8496
1
        xmlFree(name);
8497
1
    }
8498
517
    SKIP_BLANKS;
8499
517
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8500
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8501
0
    }
8502
517
}
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
7.14k
xmlXPathIsNodeType(const xmlChar *name) {
8517
7.14k
    if (name == NULL)
8518
0
  return(0);
8519
8520
7.14k
    if (xmlStrEqual(name, BAD_CAST "node"))
8521
267
  return(1);
8522
6.87k
    if (xmlStrEqual(name, BAD_CAST "text"))
8523
252
  return(1);
8524
6.62k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8525
197
  return(1);
8526
6.43k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8527
221
  return(1);
8528
6.20k
    return(0);
8529
6.43k
}
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
6.20k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8542
6.20k
    xmlChar *name;
8543
6.20k
    xmlChar *prefix;
8544
6.20k
    int nbargs = 0;
8545
6.20k
    int sort = 1;
8546
8547
6.20k
    name = xmlXPathParseQName(ctxt, &prefix);
8548
6.20k
    if (name == NULL) {
8549
1
  xmlFree(prefix);
8550
1
  XP_ERROR(XPATH_EXPR_ERROR);
8551
0
    }
8552
6.20k
    SKIP_BLANKS;
8553
8554
6.20k
    if (CUR != '(') {
8555
1
  xmlFree(name);
8556
1
  xmlFree(prefix);
8557
1
  XP_ERROR(XPATH_EXPR_ERROR);
8558
0
    }
8559
6.20k
    NEXT;
8560
6.20k
    SKIP_BLANKS;
8561
8562
    /*
8563
    * Optimization for count(): we don't need the node-set to be sorted.
8564
    */
8565
6.20k
    if ((prefix == NULL) && (name[0] == 'c') &&
8566
790
  xmlStrEqual(name, BAD_CAST "count"))
8567
271
    {
8568
271
  sort = 0;
8569
271
    }
8570
6.20k
    ctxt->comp->last = -1;
8571
6.20k
    if (CUR != ')') {
8572
30.6k
  while (CUR != 0) {
8573
30.6k
      int op1 = ctxt->comp->last;
8574
30.6k
      ctxt->comp->last = -1;
8575
30.6k
      xmlXPathCompileExpr(ctxt, sort);
8576
30.6k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8577
161
    xmlFree(name);
8578
161
    xmlFree(prefix);
8579
161
    return;
8580
161
      }
8581
30.5k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8582
30.5k
      nbargs++;
8583
30.5k
      if (CUR == ')') break;
8584
27.2k
      if (CUR != ',') {
8585
6
    xmlFree(name);
8586
6
    xmlFree(prefix);
8587
6
    XP_ERROR(XPATH_EXPR_ERROR);
8588
0
      }
8589
27.2k
      NEXT;
8590
27.2k
      SKIP_BLANKS;
8591
27.2k
  }
8592
3.47k
    }
8593
6.04k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8594
1
        xmlFree(prefix);
8595
1
        xmlFree(name);
8596
1
    }
8597
6.04k
    NEXT;
8598
6.04k
    SKIP_BLANKS;
8599
6.04k
}
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
24.0k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8614
24.0k
    SKIP_BLANKS;
8615
24.0k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8616
23.3k
    else if (CUR == '(') {
8617
3.07k
  NEXT;
8618
3.07k
  SKIP_BLANKS;
8619
3.07k
  xmlXPathCompileExpr(ctxt, 1);
8620
3.07k
  CHECK_ERROR;
8621
2.91k
  if (CUR != ')') {
8622
7
      XP_ERROR(XPATH_EXPR_ERROR);
8623
0
  }
8624
2.90k
  NEXT;
8625
2.90k
  SKIP_BLANKS;
8626
20.2k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8627
11.9k
  xmlXPathCompNumber(ctxt);
8628
11.9k
    } else if ((CUR == '\'') || (CUR == '"')) {
8629
2.08k
  xmlXPathCompLiteral(ctxt);
8630
6.20k
    } else {
8631
6.20k
  xmlXPathCompFunctionCall(ctxt);
8632
6.20k
    }
8633
23.9k
    SKIP_BLANKS;
8634
23.9k
}
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
24.0k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8652
24.0k
    xmlXPathCompPrimaryExpr(ctxt);
8653
24.0k
    CHECK_ERROR;
8654
23.4k
    SKIP_BLANKS;
8655
8656
26.3k
    while (CUR == '[') {
8657
2.98k
  xmlXPathCompPredicate(ctxt, 1);
8658
2.98k
  SKIP_BLANKS;
8659
2.98k
    }
8660
8661
8662
23.4k
}
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
56.3k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8674
56.3k
    const xmlChar *end;
8675
56.3k
    xmlChar *ret;
8676
8677
56.3k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8678
56.3k
    if (end == NULL) {
8679
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8680
0
    }
8681
56.3k
    if (end == ctxt->cur)
8682
5.95k
        return(NULL);
8683
8684
50.3k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8685
50.3k
    if (ret == NULL)
8686
1
        xmlXPathPErrMemory(ctxt);
8687
50.3k
    return(ret);
8688
56.3k
}
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
135k
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8703
135k
    int lc = 1;           /* Should we branch to LocationPath ?         */
8704
135k
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8705
8706
135k
    SKIP_BLANKS;
8707
135k
    if ((CUR == '$') || (CUR == '(') ||
8708
132k
  (IS_ASCII_DIGIT(CUR)) ||
8709
120k
        (CUR == '\'') || (CUR == '"') ||
8710
118k
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8711
17.8k
  lc = 0;
8712
118k
    } else if (CUR == '*') {
8713
  /* relative or absolute location path */
8714
13.9k
  lc = 1;
8715
104k
    } else if (CUR == '/') {
8716
  /* relative or absolute location path */
8717
32.4k
  lc = 1;
8718
71.6k
    } else if (CUR == '@') {
8719
  /* relative abbreviated attribute location path */
8720
864
  lc = 1;
8721
70.7k
    } else if (CUR == '.') {
8722
  /* relative abbreviated attribute location path */
8723
14.4k
  lc = 1;
8724
56.3k
    } 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
56.3k
  SKIP_BLANKS;
8737
56.3k
  name = xmlXPathScanName(ctxt);
8738
56.3k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8739
1.21k
      lc = 1;
8740
1.21k
      xmlFree(name);
8741
55.0k
  } else if (name != NULL) {
8742
49.1k
      int len =xmlStrlen(name);
8743
8744
8745
55.3k
      while (NXT(len) != 0) {
8746
53.7k
    if (NXT(len) == '/') {
8747
        /* element name */
8748
2.27k
        lc = 1;
8749
2.27k
        break;
8750
51.4k
    } else if (IS_BLANK_CH(NXT(len))) {
8751
        /* ignore blanks */
8752
6.17k
        ;
8753
45.3k
    } else if (NXT(len) == ':') {
8754
66
        lc = 1;
8755
66
        break;
8756
45.2k
    } else if ((NXT(len) == '(')) {
8757
        /* Node Type or Function */
8758
7.14k
        if (xmlXPathIsNodeType(name)) {
8759
937
      lc = 1;
8760
6.20k
        } else {
8761
6.20k
      lc = 0;
8762
6.20k
        }
8763
7.14k
                    break;
8764
38.1k
    } else if ((NXT(len) == '[')) {
8765
        /* element name */
8766
538
        lc = 1;
8767
538
        break;
8768
37.5k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8769
35.5k
         (NXT(len) == '=')) {
8770
3.58k
        lc = 1;
8771
3.58k
        break;
8772
33.9k
    } else {
8773
33.9k
        lc = 1;
8774
33.9k
        break;
8775
33.9k
    }
8776
6.17k
    len++;
8777
6.17k
      }
8778
49.1k
      if (NXT(len) == 0) {
8779
    /* element name */
8780
1.55k
    lc = 1;
8781
1.55k
      }
8782
49.1k
      xmlFree(name);
8783
49.1k
  } else {
8784
      /* make sure all cases are covered explicitly */
8785
5.95k
      XP_ERROR(XPATH_EXPR_ERROR);
8786
0
  }
8787
56.3k
    }
8788
8789
129k
    if (lc) {
8790
105k
  if (CUR == '/') {
8791
32.4k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8792
73.4k
  } else {
8793
73.4k
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8794
73.4k
  }
8795
105k
  xmlXPathCompLocationPath(ctxt);
8796
105k
    } else {
8797
24.0k
  xmlXPathCompFilterExpr(ctxt);
8798
24.0k
  CHECK_ERROR;
8799
23.1k
  if ((CUR == '/') && (NXT(1) == '/')) {
8800
503
      SKIP(2);
8801
503
      SKIP_BLANKS;
8802
8803
503
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8804
503
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8805
8806
503
      xmlXPathCompRelativeLocationPath(ctxt);
8807
22.6k
  } else if (CUR == '/') {
8808
712
      xmlXPathCompRelativeLocationPath(ctxt);
8809
712
  }
8810
23.1k
    }
8811
129k
    SKIP_BLANKS;
8812
129k
}
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
98.5k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8825
98.5k
    xmlXPathCompPathExpr(ctxt);
8826
98.5k
    CHECK_ERROR;
8827
94.1k
    SKIP_BLANKS;
8828
131k
    while (CUR == '|') {
8829
37.4k
  int op1 = ctxt->comp->last;
8830
37.4k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8831
8832
37.4k
  NEXT;
8833
37.4k
  SKIP_BLANKS;
8834
37.4k
  xmlXPathCompPathExpr(ctxt);
8835
8836
37.4k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8837
8838
37.4k
  SKIP_BLANKS;
8839
37.4k
    }
8840
94.1k
}
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
98.5k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8853
98.5k
    int minus = 0;
8854
98.5k
    int found = 0;
8855
8856
98.5k
    SKIP_BLANKS;
8857
102k
    while (CUR == '-') {
8858
3.89k
        minus = 1 - minus;
8859
3.89k
  found = 1;
8860
3.89k
  NEXT;
8861
3.89k
  SKIP_BLANKS;
8862
3.89k
    }
8863
8864
98.5k
    xmlXPathCompUnionExpr(ctxt);
8865
98.5k
    CHECK_ERROR;
8866
93.9k
    if (found) {
8867
3.14k
  if (minus)
8868
2.78k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8869
360
  else
8870
360
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8871
3.14k
    }
8872
93.9k
}
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
83.7k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8888
83.7k
    xmlXPathCompUnaryExpr(ctxt);
8889
83.7k
    CHECK_ERROR;
8890
79.4k
    SKIP_BLANKS;
8891
93.9k
    while ((CUR == '*') ||
8892
79.8k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8893
79.3k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8894
14.7k
  int op = -1;
8895
14.7k
  int op1 = ctxt->comp->last;
8896
8897
14.7k
        if (CUR == '*') {
8898
14.1k
      op = 0;
8899
14.1k
      NEXT;
8900
14.1k
  } else if (CUR == 'd') {
8901
455
      op = 1;
8902
455
      SKIP(3);
8903
455
  } else if (CUR == 'm') {
8904
92
      op = 2;
8905
92
      SKIP(3);
8906
92
  }
8907
14.7k
  SKIP_BLANKS;
8908
14.7k
        xmlXPathCompUnaryExpr(ctxt);
8909
14.7k
  CHECK_ERROR;
8910
14.5k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8911
14.5k
  SKIP_BLANKS;
8912
14.5k
    }
8913
79.4k
}
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
75.6k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8927
8928
75.6k
    xmlXPathCompMultiplicativeExpr(ctxt);
8929
75.6k
    CHECK_ERROR;
8930
71.3k
    SKIP_BLANKS;
8931
79.2k
    while ((CUR == '+') || (CUR == '-')) {
8932
8.14k
  int plus;
8933
8.14k
  int op1 = ctxt->comp->last;
8934
8935
8.14k
        if (CUR == '+') plus = 1;
8936
5.60k
  else plus = 0;
8937
8.14k
  NEXT;
8938
8.14k
  SKIP_BLANKS;
8939
8.14k
        xmlXPathCompMultiplicativeExpr(ctxt);
8940
8.14k
  CHECK_ERROR;
8941
7.89k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8942
7.89k
  SKIP_BLANKS;
8943
7.89k
    }
8944
71.3k
}
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
71.1k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8965
71.1k
    xmlXPathCompAdditiveExpr(ctxt);
8966
71.1k
    CHECK_ERROR;
8967
66.8k
    SKIP_BLANKS;
8968
71.1k
    while ((CUR == '<') || (CUR == '>')) {
8969
4.45k
  int inf, strict;
8970
4.45k
  int op1 = ctxt->comp->last;
8971
8972
4.45k
        if (CUR == '<') inf = 1;
8973
2.19k
  else inf = 0;
8974
4.45k
  if (NXT(1) == '=') strict = 0;
8975
3.94k
  else strict = 1;
8976
4.45k
  NEXT;
8977
4.45k
  if (!strict) NEXT;
8978
4.45k
  SKIP_BLANKS;
8979
4.45k
        xmlXPathCompAdditiveExpr(ctxt);
8980
4.45k
  CHECK_ERROR;
8981
4.32k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
8982
4.32k
  SKIP_BLANKS;
8983
4.32k
    }
8984
66.8k
}
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
64.4k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9002
64.4k
    xmlXPathCompRelationalExpr(ctxt);
9003
64.4k
    CHECK_ERROR;
9004
60.1k
    SKIP_BLANKS;
9005
66.6k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9006
6.71k
  int eq;
9007
6.71k
  int op1 = ctxt->comp->last;
9008
9009
6.71k
        if (CUR == '=') eq = 1;
9010
781
  else eq = 0;
9011
6.71k
  NEXT;
9012
6.71k
  if (!eq) NEXT;
9013
6.71k
  SKIP_BLANKS;
9014
6.71k
        xmlXPathCompRelationalExpr(ctxt);
9015
6.71k
  CHECK_ERROR;
9016
6.50k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9017
6.50k
  SKIP_BLANKS;
9018
6.50k
    }
9019
60.1k
}
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
63.8k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9031
63.8k
    xmlXPathCompEqualityExpr(ctxt);
9032
63.8k
    CHECK_ERROR;
9033
59.3k
    SKIP_BLANKS;
9034
59.9k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9035
669
  int op1 = ctxt->comp->last;
9036
669
        SKIP(3);
9037
669
  SKIP_BLANKS;
9038
669
        xmlXPathCompEqualityExpr(ctxt);
9039
669
  CHECK_ERROR;
9040
583
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9041
583
  SKIP_BLANKS;
9042
583
    }
9043
59.3k
}
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
63.0k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9057
63.0k
    xmlXPathContextPtr xpctxt = ctxt->context;
9058
9059
63.0k
    if (xpctxt != NULL) {
9060
63.0k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9061
62.5k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9062
        /*
9063
         * Parsing a single '(' pushes about 10 functions on the call stack
9064
         * before recursing!
9065
         */
9066
62.5k
        xpctxt->depth += 10;
9067
62.5k
    }
9068
9069
62.5k
    xmlXPathCompAndExpr(ctxt);
9070
62.5k
    CHECK_ERROR;
9071
58.1k
    SKIP_BLANKS;
9072
59.2k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9073
1.26k
  int op1 = ctxt->comp->last;
9074
1.26k
        SKIP(2);
9075
1.26k
  SKIP_BLANKS;
9076
1.26k
        xmlXPathCompAndExpr(ctxt);
9077
1.26k
  CHECK_ERROR;
9078
1.12k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9079
1.12k
  SKIP_BLANKS;
9080
1.12k
    }
9081
58.0k
    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
43.8k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9089
43.8k
    }
9090
9091
58.0k
    if (xpctxt != NULL)
9092
58.0k
        xpctxt->depth -= 10;
9093
58.0k
}
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
16.2k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9106
16.2k
    int op1 = ctxt->comp->last;
9107
9108
16.2k
    SKIP_BLANKS;
9109
16.2k
    if (CUR != '[') {
9110
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9111
0
    }
9112
16.2k
    NEXT;
9113
16.2k
    SKIP_BLANKS;
9114
9115
16.2k
    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
16.2k
    if (! filter)
9126
13.2k
  xmlXPathCompileExpr(ctxt, 0);
9127
2.98k
    else
9128
2.98k
  xmlXPathCompileExpr(ctxt, 1);
9129
16.2k
    CHECK_ERROR;
9130
9131
12.6k
    if (CUR != ']') {
9132
94
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9133
0
    }
9134
9135
12.5k
    if (filter)
9136
2.32k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9137
10.2k
    else
9138
10.2k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9139
9140
12.5k
    NEXT;
9141
12.5k
    SKIP_BLANKS;
9142
12.5k
}
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
84.9k
         xmlChar *name) {
9170
84.9k
    int blanks;
9171
9172
84.9k
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9173
0
  return(NULL);
9174
0
    }
9175
84.9k
    *type = (xmlXPathTypeVal) 0;
9176
84.9k
    *test = (xmlXPathTestVal) 0;
9177
84.9k
    *prefix = NULL;
9178
84.9k
    SKIP_BLANKS;
9179
9180
84.9k
    if ((name == NULL) && (CUR == '*')) {
9181
  /*
9182
   * All elements
9183
   */
9184
25.0k
  NEXT;
9185
25.0k
  *test = NODE_TEST_ALL;
9186
25.0k
  return(NULL);
9187
25.0k
    }
9188
9189
59.9k
    if (name == NULL)
9190
3.62k
  name = xmlXPathParseNCName(ctxt);
9191
59.9k
    if (name == NULL) {
9192
295
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9193
0
    }
9194
9195
59.6k
    blanks = IS_BLANK_CH(CUR);
9196
59.6k
    SKIP_BLANKS;
9197
59.6k
    if (CUR == '(') {
9198
2.16k
  NEXT;
9199
  /*
9200
   * NodeType or PI search
9201
   */
9202
2.16k
  if (xmlStrEqual(name, BAD_CAST "comment"))
9203
360
      *type = NODE_TYPE_COMMENT;
9204
1.80k
  else if (xmlStrEqual(name, BAD_CAST "node"))
9205
885
      *type = NODE_TYPE_NODE;
9206
915
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9207
374
      *type = NODE_TYPE_PI;
9208
541
  else if (xmlStrEqual(name, BAD_CAST "text"))
9209
531
      *type = NODE_TYPE_TEXT;
9210
10
  else {
9211
10
      if (name != NULL)
9212
10
    xmlFree(name);
9213
10
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9214
0
  }
9215
9216
2.15k
  *test = NODE_TEST_TYPE;
9217
9218
2.15k
  SKIP_BLANKS;
9219
2.15k
  if (*type == NODE_TYPE_PI) {
9220
      /*
9221
       * Specific case: search a PI by name.
9222
       */
9223
374
      if (name != NULL)
9224
374
    xmlFree(name);
9225
374
      name = NULL;
9226
374
      if (CUR != ')') {
9227
144
    name = xmlXPathParseLiteral(ctxt);
9228
144
    *test = NODE_TEST_PI;
9229
144
    SKIP_BLANKS;
9230
144
      }
9231
374
  }
9232
2.15k
  if (CUR != ')') {
9233
11
      if (name != NULL)
9234
3
    xmlFree(name);
9235
11
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9236
0
  }
9237
2.13k
  NEXT;
9238
2.13k
  return(name);
9239
2.15k
    }
9240
57.4k
    *test = NODE_TEST_NAME;
9241
57.4k
    if ((!blanks) && (CUR == ':')) {
9242
1.95k
  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
1.95k
  *prefix = name;
9252
9253
1.95k
  if (CUR == '*') {
9254
      /*
9255
       * All elements
9256
       */
9257
474
      NEXT;
9258
474
      *test = NODE_TEST_ALL;
9259
474
      return(NULL);
9260
474
  }
9261
9262
1.48k
  name = xmlXPathParseNCName(ctxt);
9263
1.48k
  if (name == NULL) {
9264
41
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9265
0
  }
9266
1.48k
    }
9267
56.9k
    return(name);
9268
57.4k
}
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
60.3k
xmlXPathIsAxisName(const xmlChar *name) {
9290
60.3k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9291
60.3k
    switch (name[0]) {
9292
2.06k
  case 'a':
9293
2.06k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9294
809
    ret = AXIS_ANCESTOR;
9295
2.06k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9296
193
    ret = AXIS_ANCESTOR_OR_SELF;
9297
2.06k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9298
299
    ret = AXIS_ATTRIBUTE;
9299
2.06k
      break;
9300
2.14k
  case 'c':
9301
2.14k
      if (xmlStrEqual(name, BAD_CAST "child"))
9302
260
    ret = AXIS_CHILD;
9303
2.14k
      break;
9304
1.69k
  case 'd':
9305
1.69k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9306
205
    ret = AXIS_DESCENDANT;
9307
1.69k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9308
226
    ret = AXIS_DESCENDANT_OR_SELF;
9309
1.69k
      break;
9310
1.03k
  case 'f':
9311
1.03k
      if (xmlStrEqual(name, BAD_CAST "following"))
9312
334
    ret = AXIS_FOLLOWING;
9313
1.03k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9314
104
    ret = AXIS_FOLLOWING_SIBLING;
9315
1.03k
      break;
9316
4.02k
  case 'n':
9317
4.02k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9318
1.05k
    ret = AXIS_NAMESPACE;
9319
4.02k
      break;
9320
23.6k
  case 'p':
9321
23.6k
      if (xmlStrEqual(name, BAD_CAST "parent"))
9322
218
    ret = AXIS_PARENT;
9323
23.6k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9324
403
    ret = AXIS_PRECEDING;
9325
23.6k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9326
294
    ret = AXIS_PRECEDING_SIBLING;
9327
23.6k
      break;
9328
3.97k
  case 's':
9329
3.97k
      if (xmlStrEqual(name, BAD_CAST "self"))
9330
871
    ret = AXIS_SELF;
9331
3.97k
      break;
9332
60.3k
    }
9333
60.3k
    return(ret);
9334
60.3k
}
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
105k
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9359
105k
    SKIP_BLANKS;
9360
105k
    if ((CUR == '.') && (NXT(1) == '.')) {
9361
1.67k
  SKIP(2);
9362
1.67k
  SKIP_BLANKS;
9363
1.67k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9364
1.67k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9365
104k
    } else if (CUR == '.') {
9366
17.7k
  NEXT;
9367
17.7k
  SKIP_BLANKS;
9368
86.4k
    } else {
9369
86.4k
  xmlChar *name = NULL;
9370
86.4k
  xmlChar *prefix = NULL;
9371
86.4k
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9372
86.4k
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9373
86.4k
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9374
86.4k
  int op1;
9375
9376
86.4k
  if (CUR == '*') {
9377
23.1k
      axis = AXIS_CHILD;
9378
63.3k
  } else {
9379
63.3k
      if (name == NULL)
9380
63.3k
    name = xmlXPathParseNCName(ctxt);
9381
63.3k
      if (name != NULL) {
9382
60.3k
    axis = xmlXPathIsAxisName(name);
9383
60.3k
    if (axis != 0) {
9384
5.26k
        SKIP_BLANKS;
9385
5.26k
        if ((CUR == ':') && (NXT(1) == ':')) {
9386
3.45k
      SKIP(2);
9387
3.45k
      xmlFree(name);
9388
3.45k
      name = NULL;
9389
3.45k
        } else {
9390
      /* an element name can conflict with an axis one :-\ */
9391
1.81k
      axis = AXIS_CHILD;
9392
1.81k
        }
9393
55.0k
    } else {
9394
55.0k
        axis = AXIS_CHILD;
9395
55.0k
    }
9396
60.3k
      } else if (CUR == '@') {
9397
2.00k
    NEXT;
9398
2.00k
    axis = AXIS_ATTRIBUTE;
9399
2.00k
      } else {
9400
971
    axis = AXIS_CHILD;
9401
971
      }
9402
63.3k
  }
9403
9404
86.4k
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9405
1.56k
            xmlFree(name);
9406
1.56k
            return;
9407
1.56k
        }
9408
9409
84.9k
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9410
84.9k
  if (test == 0)
9411
305
      return;
9412
9413
84.6k
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9414
1.95k
      (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
84.6k
  op1 = ctxt->comp->last;
9422
84.6k
  ctxt->comp->last = -1;
9423
9424
84.6k
  SKIP_BLANKS;
9425
97.8k
  while (CUR == '[') {
9426
13.2k
      xmlXPathCompPredicate(ctxt, 0);
9427
13.2k
  }
9428
9429
84.6k
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9430
84.6k
                           test, type, (void *)prefix, (void *)name) == -1) {
9431
4
            xmlFree(prefix);
9432
4
            xmlFree(name);
9433
4
        }
9434
84.6k
    }
9435
105k
}
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
94.6k
(xmlXPathParserContextPtr ctxt) {
9450
94.6k
    SKIP_BLANKS;
9451
94.6k
    if ((CUR == '/') && (NXT(1) == '/')) {
9452
343
  SKIP(2);
9453
343
  SKIP_BLANKS;
9454
343
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9455
343
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9456
94.2k
    } else if (CUR == '/') {
9457
1.10k
      NEXT;
9458
1.10k
  SKIP_BLANKS;
9459
1.10k
    }
9460
94.6k
    xmlXPathCompStep(ctxt);
9461
94.6k
    CHECK_ERROR;
9462
91.8k
    SKIP_BLANKS;
9463
103k
    while (CUR == '/') {
9464
11.2k
  if ((CUR == '/') && (NXT(1) == '/')) {
9465
2.95k
      SKIP(2);
9466
2.95k
      SKIP_BLANKS;
9467
2.95k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9468
2.95k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9469
2.95k
      xmlXPathCompStep(ctxt);
9470
8.28k
  } else if (CUR == '/') {
9471
8.28k
      NEXT;
9472
8.28k
      SKIP_BLANKS;
9473
8.28k
      xmlXPathCompStep(ctxt);
9474
8.28k
  }
9475
11.2k
  SKIP_BLANKS;
9476
11.2k
    }
9477
91.8k
}
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
105k
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9493
105k
    SKIP_BLANKS;
9494
105k
    if (CUR != '/') {
9495
73.4k
        xmlXPathCompRelativeLocationPath(ctxt);
9496
73.4k
    } else {
9497
63.9k
  while (CUR == '/') {
9498
32.5k
      if ((CUR == '/') && (NXT(1) == '/')) {
9499
16.0k
    SKIP(2);
9500
16.0k
    SKIP_BLANKS;
9501
16.0k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9502
16.0k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9503
16.0k
    xmlXPathCompRelativeLocationPath(ctxt);
9504
16.4k
      } else if (CUR == '/') {
9505
16.4k
    NEXT;
9506
16.4k
    SKIP_BLANKS;
9507
16.4k
    if ((CUR != 0) &&
9508
16.2k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9509
14.6k
                     (CUR == '_') || (CUR == '.') ||
9510
13.5k
         (CUR == '@') || (CUR == '*')))
9511
3.91k
        xmlXPathCompRelativeLocationPath(ctxt);
9512
16.4k
      }
9513
32.5k
      CHECK_ERROR;
9514
32.5k
  }
9515
32.4k
    }
9516
105k
}
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
334k
{
9546
334k
    xmlXPathContextPtr xpctxt;
9547
334k
    xmlNodePtr oldnode;
9548
334k
    xmlDocPtr olddoc;
9549
334k
    xmlXPathStepOpPtr filterOp;
9550
334k
    int oldcs, oldpp;
9551
334k
    int i, j, pos;
9552
9553
334k
    if ((set == NULL) || (set->nodeNr == 0))
9554
14.3k
        return;
9555
9556
    /*
9557
    * Check if the node set contains a sufficient number of nodes for
9558
    * the requested range.
9559
    */
9560
320k
    if (set->nodeNr < minPos) {
9561
1.18k
        xmlXPathNodeSetClear(set, hasNsNodes);
9562
1.18k
        return;
9563
1.18k
    }
9564
9565
319k
    xpctxt = ctxt->context;
9566
319k
    oldnode = xpctxt->node;
9567
319k
    olddoc = xpctxt->doc;
9568
319k
    oldcs = xpctxt->contextSize;
9569
319k
    oldpp = xpctxt->proximityPosition;
9570
319k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9571
9572
319k
    xpctxt->contextSize = set->nodeNr;
9573
9574
2.07M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9575
1.77M
        xmlNodePtr node = set->nodeTab[i];
9576
1.77M
        int res;
9577
9578
1.77M
        xpctxt->node = node;
9579
1.77M
        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
1.77M
        if ((node->type != XML_NAMESPACE_DECL) &&
9588
1.54M
            (node->doc != NULL))
9589
1.54M
            xpctxt->doc = node->doc;
9590
9591
1.77M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9592
9593
1.77M
        if (ctxt->error != XPATH_EXPRESSION_OK)
9594
1.00k
            break;
9595
1.77M
        if (res < 0) {
9596
            /* Shouldn't happen */
9597
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9598
0
            break;
9599
0
        }
9600
9601
1.77M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9602
540k
            if (i != j) {
9603
14.3k
                set->nodeTab[j] = node;
9604
14.3k
                set->nodeTab[i] = NULL;
9605
14.3k
            }
9606
9607
540k
            j += 1;
9608
1.23M
        } else {
9609
            /* Remove the entry from the initial node set. */
9610
1.23M
            set->nodeTab[i] = NULL;
9611
1.23M
            if (node->type == XML_NAMESPACE_DECL)
9612
89.5k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9613
1.23M
        }
9614
9615
1.77M
        if (res != 0) {
9616
732k
            if (pos == maxPos) {
9617
13.0k
                i += 1;
9618
13.0k
                break;
9619
13.0k
            }
9620
9621
719k
            pos += 1;
9622
719k
        }
9623
1.77M
    }
9624
9625
    /* Free remaining nodes. */
9626
319k
    if (hasNsNodes) {
9627
36.0k
        for (; i < set->nodeNr; i++) {
9628
3.02k
            xmlNodePtr node = set->nodeTab[i];
9629
3.02k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9630
559
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9631
3.02k
        }
9632
33.0k
    }
9633
9634
319k
    set->nodeNr = j;
9635
9636
    /* If too many elements were removed, shrink table to preserve memory. */
9637
319k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9638
28.2k
        (set->nodeNr < set->nodeMax / 2)) {
9639
26.8k
        xmlNodePtr *tmp;
9640
26.8k
        int nodeMax = set->nodeNr;
9641
9642
26.8k
        if (nodeMax < XML_NODESET_DEFAULT)
9643
26.5k
            nodeMax = XML_NODESET_DEFAULT;
9644
26.8k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9645
26.8k
                nodeMax * sizeof(xmlNodePtr));
9646
26.8k
        if (tmp == NULL) {
9647
1
            xmlXPathPErrMemory(ctxt);
9648
26.8k
        } else {
9649
26.8k
            set->nodeTab = tmp;
9650
26.8k
            set->nodeMax = nodeMax;
9651
26.8k
        }
9652
26.8k
    }
9653
9654
319k
    xpctxt->node = oldnode;
9655
319k
    xpctxt->doc = olddoc;
9656
319k
    xpctxt->contextSize = oldcs;
9657
319k
    xpctxt->proximityPosition = oldpp;
9658
319k
}
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
292k
{
9679
292k
    if (op->ch1 != -1) {
9680
653
  xmlXPathCompExprPtr comp = ctxt->comp;
9681
  /*
9682
  * Process inner predicates first.
9683
  */
9684
653
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9685
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9686
0
  }
9687
653
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9688
653
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9689
653
        ctxt->context->depth += 1;
9690
653
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9691
653
                                    1, set->nodeNr, hasNsNodes);
9692
653
        ctxt->context->depth -= 1;
9693
653
  CHECK_ERROR;
9694
653
    }
9695
9696
292k
    if (op->ch2 != -1)
9697
292k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9698
292k
}
9699
9700
static int
9701
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9702
          xmlXPathStepOpPtr op,
9703
          int *maxPos)
9704
256k
{
9705
9706
256k
    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
256k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9722
0
  return(0);
9723
9724
256k
    if (op->ch2 != -1) {
9725
256k
  exprOp = &ctxt->comp->steps[op->ch2];
9726
256k
    } else
9727
0
  return(0);
9728
9729
256k
    if ((exprOp != NULL) &&
9730
256k
  (exprOp->op == XPATH_OP_VALUE) &&
9731
210k
  (exprOp->value4 != NULL) &&
9732
210k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9733
209k
    {
9734
209k
        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
209k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9748
208k
      *maxPos = (int) floatval;
9749
208k
            if (floatval == (double) *maxPos)
9750
208k
                return(1);
9751
208k
        }
9752
209k
    }
9753
48.5k
    return(0);
9754
256k
}
9755
9756
static int
9757
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9758
                           xmlXPathStepOpPtr op,
9759
         xmlNodePtr * first, xmlNodePtr * last,
9760
         int toBool)
9761
1.18M
{
9762
9763
1.18M
#define XP_TEST_HIT \
9764
25.4M
    if (hasAxisRange != 0) { \
9765
433k
  if (++pos == maxPos) { \
9766
3.70k
      if (addNode(seq, cur) < 0) \
9767
3.70k
          xmlXPathPErrMemory(ctxt); \
9768
3.70k
      goto axis_range_end; } \
9769
24.9M
    } else { \
9770
24.9M
  if (addNode(seq, cur) < 0) \
9771
24.9M
      xmlXPathPErrMemory(ctxt); \
9772
24.9M
  if (breakOnFirstHit) goto first_hit; }
9773
9774
1.18M
#define XP_TEST_HIT_NS \
9775
1.25M
    if (hasAxisRange != 0) { \
9776
1.88k
  if (++pos == maxPos) { \
9777
998
      hasNsNodes = 1; \
9778
998
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9779
998
          xmlXPathPErrMemory(ctxt); \
9780
998
  goto axis_range_end; } \
9781
1.25M
    } else { \
9782
1.25M
  hasNsNodes = 1; \
9783
1.25M
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9784
1.25M
      xmlXPathPErrMemory(ctxt); \
9785
1.25M
  if (breakOnFirstHit) goto first_hit; }
9786
9787
1.18M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9788
1.18M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9789
1.18M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9790
1.18M
    const xmlChar *prefix = op->value4;
9791
1.18M
    const xmlChar *name = op->value5;
9792
1.18M
    const xmlChar *URI = NULL;
9793
9794
1.18M
    int total = 0, hasNsNodes = 0;
9795
    /* The popped object holding the context nodes */
9796
1.18M
    xmlXPathObjectPtr obj;
9797
    /* The set of context nodes for the node tests */
9798
1.18M
    xmlNodeSetPtr contextSeq;
9799
1.18M
    int contextIdx;
9800
1.18M
    xmlNodePtr contextNode;
9801
    /* The final resulting node set wrt to all context nodes */
9802
1.18M
    xmlNodeSetPtr outSeq;
9803
    /*
9804
    * The temporary resulting node set wrt 1 context node.
9805
    * Used to feed predicate evaluation.
9806
    */
9807
1.18M
    xmlNodeSetPtr seq;
9808
1.18M
    xmlNodePtr cur;
9809
    /* First predicate operator */
9810
1.18M
    xmlXPathStepOpPtr predOp;
9811
1.18M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9812
1.18M
    int hasPredicateRange, hasAxisRange, pos;
9813
1.18M
    int breakOnFirstHit;
9814
9815
1.18M
    xmlXPathTraversalFunction next = NULL;
9816
1.18M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9817
1.18M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9818
1.18M
    xmlNodePtr oldContextNode;
9819
1.18M
    xmlXPathContextPtr xpctxt = ctxt->context;
9820
9821
9822
1.18M
    CHECK_TYPE0(XPATH_NODESET);
9823
1.18M
    obj = xmlXPathValuePop(ctxt);
9824
    /*
9825
    * Setup namespaces.
9826
    */
9827
1.18M
    if (prefix != NULL) {
9828
6.35k
        URI = xmlXPathNsLookup(xpctxt, prefix);
9829
6.35k
        if (URI == NULL) {
9830
42
      xmlXPathReleaseObject(xpctxt, obj);
9831
42
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9832
42
                           "Undefined namespace prefix: %s\n", prefix);
9833
42
            return 0;
9834
42
  }
9835
6.35k
    }
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
1.18M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9850
1.18M
    switch (axis) {
9851
23.0k
        case AXIS_ANCESTOR:
9852
23.0k
            first = NULL;
9853
23.0k
            next = xmlXPathNextAncestor;
9854
23.0k
            break;
9855
1.61k
        case AXIS_ANCESTOR_OR_SELF:
9856
1.61k
            first = NULL;
9857
1.61k
            next = xmlXPathNextAncestorOrSelf;
9858
1.61k
            break;
9859
5.89k
        case AXIS_ATTRIBUTE:
9860
5.89k
            first = NULL;
9861
5.89k
      last = NULL;
9862
5.89k
            next = xmlXPathNextAttribute;
9863
5.89k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9864
5.89k
            break;
9865
955k
        case AXIS_CHILD:
9866
955k
      last = NULL;
9867
955k
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9868
743k
    (type == NODE_TYPE_NODE))
9869
743k
      {
9870
    /*
9871
    * Optimization if an element node type is 'element'.
9872
    */
9873
743k
    next = xmlXPathNextChildElement;
9874
743k
      } else
9875
211k
    next = xmlXPathNextChild;
9876
955k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9877
955k
            break;
9878
26.9k
        case AXIS_DESCENDANT:
9879
26.9k
      last = NULL;
9880
26.9k
            next = xmlXPathNextDescendant;
9881
26.9k
            break;
9882
140k
        case AXIS_DESCENDANT_OR_SELF:
9883
140k
      last = NULL;
9884
140k
            next = xmlXPathNextDescendantOrSelf;
9885
140k
            break;
9886
999
        case AXIS_FOLLOWING:
9887
999
      last = NULL;
9888
999
            next = xmlXPathNextFollowing;
9889
999
            break;
9890
471
        case AXIS_FOLLOWING_SIBLING:
9891
471
      last = NULL;
9892
471
            next = xmlXPathNextFollowingSibling;
9893
471
            break;
9894
6.14k
        case AXIS_NAMESPACE:
9895
6.14k
            first = NULL;
9896
6.14k
      last = NULL;
9897
6.14k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9898
6.14k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9899
6.14k
            break;
9900
23.9k
        case AXIS_PARENT:
9901
23.9k
            first = NULL;
9902
23.9k
            next = xmlXPathNextParent;
9903
23.9k
            break;
9904
1.24k
        case AXIS_PRECEDING:
9905
1.24k
            first = NULL;
9906
1.24k
            next = xmlXPathNextPrecedingInternal;
9907
1.24k
            break;
9908
938
        case AXIS_PRECEDING_SIBLING:
9909
938
            first = NULL;
9910
938
            next = xmlXPathNextPrecedingSibling;
9911
938
            break;
9912
386
        case AXIS_SELF:
9913
386
            first = NULL;
9914
386
      last = NULL;
9915
386
            next = xmlXPathNextSelf;
9916
386
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9917
386
            break;
9918
1.18M
    }
9919
9920
1.18M
    if (next == NULL) {
9921
0
  xmlXPathReleaseObject(xpctxt, obj);
9922
0
        return(0);
9923
0
    }
9924
1.18M
    contextSeq = obj->nodesetval;
9925
1.18M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9926
5.52k
        xmlXPathValuePush(ctxt, obj);
9927
5.52k
        return(0);
9928
5.52k
    }
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
1.18M
    maxPos = 0;
9948
1.18M
    predOp = NULL;
9949
1.18M
    hasPredicateRange = 0;
9950
1.18M
    hasAxisRange = 0;
9951
1.18M
    if (op->ch2 != -1) {
9952
  /*
9953
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9954
  */
9955
256k
  predOp = &ctxt->comp->steps[op->ch2];
9956
256k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9957
208k
      if (predOp->ch1 != -1) {
9958
    /*
9959
    * Use the next inner predicate operator.
9960
    */
9961
1.88k
    predOp = &ctxt->comp->steps[predOp->ch1];
9962
1.88k
    hasPredicateRange = 1;
9963
206k
      } else {
9964
    /*
9965
    * There's no other predicate than the [n] predicate.
9966
    */
9967
206k
    predOp = NULL;
9968
206k
    hasAxisRange = 1;
9969
206k
      }
9970
208k
  }
9971
256k
    }
9972
1.18M
    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
1.18M
    oldContextNode = xpctxt->node;
9987
1.18M
    addNode = xmlXPathNodeSetAddUnique;
9988
1.18M
    outSeq = NULL;
9989
1.18M
    seq = NULL;
9990
1.18M
    contextNode = NULL;
9991
1.18M
    contextIdx = 0;
9992
9993
9994
5.08M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
9995
3.91M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
9996
3.91M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
9997
9998
3.91M
  if (seq == NULL) {
9999
1.21M
      seq = xmlXPathNodeSetCreate(NULL);
10000
1.21M
      if (seq == NULL) {
10001
85
                xmlXPathPErrMemory(ctxt);
10002
85
    total = 0;
10003
85
    goto error;
10004
85
      }
10005
1.21M
  }
10006
  /*
10007
  * Traverse the axis and test the nodes.
10008
  */
10009
3.91M
  pos = 0;
10010
3.91M
  cur = NULL;
10011
3.91M
  hasNsNodes = 0;
10012
32.2M
        do {
10013
32.2M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10014
29
                goto error;
10015
10016
32.2M
            cur = next(ctxt, cur);
10017
32.2M
            if (cur == NULL)
10018
3.89M
                break;
10019
10020
      /*
10021
      * QUESTION TODO: What does the "first" and "last" stuff do?
10022
      */
10023
28.4M
            if ((first != NULL) && (*first != NULL)) {
10024
2.12k
    if (*first == cur)
10025
399
        break;
10026
1.72k
    if (((total % 256) == 0) &&
10027
1.05k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10028
1.05k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10029
#else
10030
        (xmlXPathCmpNodes(*first, cur) >= 0))
10031
#endif
10032
732
    {
10033
732
        break;
10034
732
    }
10035
1.72k
      }
10036
28.3M
      if ((last != NULL) && (*last != NULL)) {
10037
7.69k
    if (*last == cur)
10038
523
        break;
10039
7.16k
    if (((total % 256) == 0) &&
10040
6.16k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10041
6.16k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10042
#else
10043
        (xmlXPathCmpNodes(cur, *last) >= 0))
10044
#endif
10045
5.86k
    {
10046
5.86k
        break;
10047
5.86k
    }
10048
7.16k
      }
10049
10050
28.3M
            total++;
10051
10052
28.3M
      switch (test) {
10053
0
                case NODE_TEST_NONE:
10054
0
        total = 0;
10055
0
        goto error;
10056
24.0M
                case NODE_TEST_TYPE:
10057
24.0M
        if (type == NODE_TYPE_NODE) {
10058
23.9M
      switch (cur->type) {
10059
119k
          case XML_DOCUMENT_NODE:
10060
119k
          case XML_HTML_DOCUMENT_NODE:
10061
14.0M
          case XML_ELEMENT_NODE:
10062
14.0M
          case XML_ATTRIBUTE_NODE:
10063
14.0M
          case XML_PI_NODE:
10064
14.0M
          case XML_COMMENT_NODE:
10065
14.0M
          case XML_CDATA_SECTION_NODE:
10066
23.8M
          case XML_TEXT_NODE:
10067
23.8M
        XP_TEST_HIT
10068
23.8M
        break;
10069
23.8M
          case XML_NAMESPACE_DECL: {
10070
131k
        if (axis == AXIS_NAMESPACE) {
10071
3.52k
            XP_TEST_HIT_NS
10072
127k
        } else {
10073
127k
                              hasNsNodes = 1;
10074
127k
            XP_TEST_HIT
10075
127k
        }
10076
130k
        break;
10077
131k
                            }
10078
130k
          default:
10079
2.22k
        break;
10080
23.9M
      }
10081
23.9M
        } else if (cur->type == (xmlElementType) type) {
10082
28.7k
      if (cur->type == XML_NAMESPACE_DECL)
10083
0
          XP_TEST_HIT_NS
10084
28.7k
      else
10085
28.7k
          XP_TEST_HIT
10086
40.3k
        } else if ((type == NODE_TYPE_TEXT) &&
10087
40.1k
       (cur->type == XML_CDATA_SECTION_NODE))
10088
886
        {
10089
886
      XP_TEST_HIT
10090
886
        }
10091
24.0M
        break;
10092
24.0M
                case NODE_TEST_PI:
10093
11.8k
                    if ((cur->type == XML_PI_NODE) &&
10094
989
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10095
790
        {
10096
790
      XP_TEST_HIT
10097
790
                    }
10098
11.4k
                    break;
10099
3.66M
                case NODE_TEST_ALL:
10100
3.66M
                    if (axis == AXIS_ATTRIBUTE) {
10101
4.88k
                        if (cur->type == XML_ATTRIBUTE_NODE)
10102
4.88k
      {
10103
4.88k
                            if (prefix == NULL)
10104
3.54k
          {
10105
3.54k
        XP_TEST_HIT
10106
3.54k
                            } else if ((cur->ns != NULL) &&
10107
1.10k
        (xmlStrEqual(URI, cur->ns->href)))
10108
915
          {
10109
915
        XP_TEST_HIT
10110
915
                            }
10111
4.88k
                        }
10112
3.66M
                    } else if (axis == AXIS_NAMESPACE) {
10113
1.25M
                        if (cur->type == XML_NAMESPACE_DECL)
10114
1.25M
      {
10115
1.25M
          XP_TEST_HIT_NS
10116
1.25M
                        }
10117
2.40M
                    } else {
10118
2.40M
                        if (cur->type == XML_ELEMENT_NODE) {
10119
1.40M
                            if (prefix == NULL)
10120
1.39M
          {
10121
1.39M
        XP_TEST_HIT
10122
10123
1.39M
                            } else if ((cur->ns != NULL) &&
10124
1.11k
        (xmlStrEqual(URI, cur->ns->href)))
10125
900
          {
10126
900
        XP_TEST_HIT
10127
900
                            }
10128
1.40M
                        }
10129
2.40M
                    }
10130
3.66M
                    break;
10131
3.66M
                case NODE_TEST_NS:{
10132
                        /* TODO */
10133
0
                        break;
10134
3.66M
                    }
10135
687k
                case NODE_TEST_NAME:
10136
687k
                    if (axis == AXIS_ATTRIBUTE) {
10137
2.83k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10138
0
          break;
10139
684k
        } else if (axis == AXIS_NAMESPACE) {
10140
4.64k
                        if (cur->type != XML_NAMESPACE_DECL)
10141
0
          break;
10142
679k
        } else {
10143
679k
            if (cur->type != XML_ELEMENT_NODE)
10144
45.3k
          break;
10145
679k
        }
10146
642k
                    switch (cur->type) {
10147
634k
                        case XML_ELEMENT_NODE:
10148
634k
                            if (xmlStrEqual(name, cur->name)) {
10149
12.0k
                                if (prefix == NULL) {
10150
10.2k
                                    if (cur->ns == NULL)
10151
10.0k
            {
10152
10.0k
          XP_TEST_HIT
10153
10.0k
                                    }
10154
10.2k
                                } else {
10155
1.77k
                                    if ((cur->ns != NULL) &&
10156
1.02k
                                        (xmlStrEqual(URI, cur->ns->href)))
10157
829
            {
10158
829
          XP_TEST_HIT
10159
829
                                    }
10160
1.77k
                                }
10161
12.0k
                            }
10162
633k
                            break;
10163
633k
                        case XML_ATTRIBUTE_NODE:{
10164
2.83k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10165
10166
2.83k
                                if (xmlStrEqual(name, attr->name)) {
10167
2.59k
                                    if (prefix == NULL) {
10168
1.29k
                                        if ((attr->ns == NULL) ||
10169
211
                                            (attr->ns->prefix == NULL))
10170
1.08k
          {
10171
1.08k
              XP_TEST_HIT
10172
1.08k
                                        }
10173
1.30k
                                    } else {
10174
1.30k
                                        if ((attr->ns != NULL) &&
10175
1.10k
                                            (xmlStrEqual(URI,
10176
1.10k
                attr->ns->href)))
10177
909
          {
10178
909
              XP_TEST_HIT
10179
909
                                        }
10180
1.30k
                                    }
10181
2.59k
                                }
10182
1.95k
                                break;
10183
2.83k
                            }
10184
4.64k
                        case XML_NAMESPACE_DECL:
10185
4.64k
                            if (cur->type == XML_NAMESPACE_DECL) {
10186
4.64k
                                xmlNsPtr ns = (xmlNsPtr) cur;
10187
10188
4.64k
                                if ((ns->prefix != NULL) && (name != NULL)
10189
3.91k
                                    && (xmlStrEqual(ns->prefix, name)))
10190
863
        {
10191
863
            XP_TEST_HIT_NS
10192
863
                                }
10193
4.64k
                            }
10194
4.22k
                            break;
10195
4.22k
                        default:
10196
0
                            break;
10197
642k
                    }
10198
639k
                    break;
10199
28.3M
      } /* switch(test) */
10200
28.3M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10201
10202
3.90M
  goto apply_predicates;
10203
10204
3.90M
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
4.69k
  if (outSeq == NULL) {
10212
2.27k
      outSeq = seq;
10213
2.27k
      seq = NULL;
10214
2.42k
  } else {
10215
2.42k
      outSeq = mergeAndClear(outSeq, seq);
10216
2.42k
            if (outSeq == NULL)
10217
7
                xmlXPathPErrMemory(ctxt);
10218
2.42k
        }
10219
  /*
10220
  * Break if only a true/false result was requested.
10221
  */
10222
4.69k
  if (toBool)
10223
533
      break;
10224
4.16k
  continue;
10225
10226
7.85k
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
7.85k
  if (outSeq == NULL) {
10232
7.85k
      outSeq = seq;
10233
7.85k
      seq = NULL;
10234
7.85k
  } else {
10235
0
      outSeq = mergeAndClear(outSeq, seq);
10236
0
            if (outSeq == NULL)
10237
0
                xmlXPathPErrMemory(ctxt);
10238
0
        }
10239
7.85k
  break;
10240
10241
3.90M
apply_predicates: /* --------------------------------------------------- */
10242
3.90M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10243
110
      goto error;
10244
10245
        /*
10246
  * Apply predicates.
10247
  */
10248
3.90M
        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
291k
      if (hasPredicateRange != 0)
10278
7.03k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10279
7.03k
              hasNsNodes);
10280
284k
      else
10281
284k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10282
284k
              hasNsNodes);
10283
10284
291k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10285
965
    total = 0;
10286
965
    goto error;
10287
965
      }
10288
291k
        }
10289
10290
3.89M
        if (seq->nodeNr > 0) {
10291
      /*
10292
      * Add to result set.
10293
      */
10294
1.14M
      if (outSeq == NULL) {
10295
223k
    outSeq = seq;
10296
223k
    seq = NULL;
10297
918k
      } else {
10298
918k
    outSeq = mergeAndClear(outSeq, seq);
10299
918k
                if (outSeq == NULL)
10300
97
                    xmlXPathPErrMemory(ctxt);
10301
918k
      }
10302
10303
1.14M
            if (toBool)
10304
817
                break;
10305
1.14M
  }
10306
3.89M
    }
10307
10308
1.18M
error:
10309
1.18M
    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
1.18M
    xmlXPathReleaseObject(xpctxt, obj);
10321
10322
    /*
10323
    * Ensure we return at least an empty set.
10324
    */
10325
1.18M
    if (outSeq == NULL) {
10326
948k
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10327
948k
      outSeq = seq;
10328
948k
        } else {
10329
167
      outSeq = xmlXPathNodeSetCreate(NULL);
10330
167
            if (outSeq == NULL)
10331
1
                xmlXPathPErrMemory(ctxt);
10332
167
        }
10333
948k
    }
10334
1.18M
    if ((seq != NULL) && (seq != outSeq)) {
10335
35.9k
   xmlXPathFreeNodeSet(seq);
10336
35.9k
    }
10337
    /*
10338
    * Hand over the result. Better to push the set also in
10339
    * case of errors.
10340
    */
10341
1.18M
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10342
    /*
10343
    * Reset the context node.
10344
    */
10345
1.18M
    xpctxt->node = oldContextNode;
10346
    /*
10347
    * When traversing the namespace axis in "toBool" mode, it's
10348
    * possible that tmpNsList wasn't freed.
10349
    */
10350
1.18M
    if (xpctxt->tmpNsList != NULL) {
10351
261
        xmlFree(xpctxt->tmpNsList);
10352
261
        xpctxt->tmpNsList = NULL;
10353
261
    }
10354
10355
1.18M
    return(total);
10356
1.18M
}
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
47.3k
{
10375
47.3k
    int total = 0, cur;
10376
47.3k
    xmlXPathCompExprPtr comp;
10377
47.3k
    xmlXPathObjectPtr arg1, arg2;
10378
10379
47.3k
    CHECK_ERROR0;
10380
47.3k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10381
1
        return(0);
10382
47.3k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10383
47.3k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10384
47.3k
    ctxt->context->depth += 1;
10385
47.3k
    comp = ctxt->comp;
10386
47.3k
    switch (op->op) {
10387
0
        case XPATH_OP_END:
10388
0
            break;
10389
10.0k
        case XPATH_OP_UNION:
10390
10.0k
            total =
10391
10.0k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10392
10.0k
                                        first);
10393
10.0k
      CHECK_ERROR0;
10394
9.27k
            if ((ctxt->value != NULL)
10395
9.27k
                && (ctxt->value->type == XPATH_NODESET)
10396
9.26k
                && (ctxt->value->nodesetval != NULL)
10397
9.26k
                && (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
8.86k
    if (ctxt->value->nodesetval->nodeNr > 1)
10409
1.79k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10410
8.86k
                *first = ctxt->value->nodesetval->nodeTab[0];
10411
8.86k
            }
10412
9.27k
            cur =
10413
9.27k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10414
9.27k
                                        first);
10415
9.27k
      CHECK_ERROR0;
10416
10417
9.24k
            arg2 = xmlXPathValuePop(ctxt);
10418
9.24k
            arg1 = xmlXPathValuePop(ctxt);
10419
9.24k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10420
9.24k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10421
6
          xmlXPathReleaseObject(ctxt->context, arg1);
10422
6
          xmlXPathReleaseObject(ctxt->context, arg2);
10423
6
                XP_ERROR0(XPATH_INVALID_TYPE);
10424
0
            }
10425
9.24k
            if ((ctxt->context->opLimit != 0) &&
10426
9.24k
                (((arg1->nodesetval != NULL) &&
10427
9.24k
                  (xmlXPathCheckOpLimit(ctxt,
10428
9.24k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10429
9.23k
                 ((arg2->nodesetval != NULL) &&
10430
9.23k
                  (xmlXPathCheckOpLimit(ctxt,
10431
9.23k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10432
2
          xmlXPathReleaseObject(ctxt->context, arg1);
10433
2
          xmlXPathReleaseObject(ctxt->context, arg2);
10434
2
                break;
10435
2
            }
10436
10437
9.23k
            if ((arg2->nodesetval != NULL) &&
10438
9.23k
                (arg2->nodesetval->nodeNr != 0)) {
10439
7.56k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10440
7.56k
                                                        arg2->nodesetval);
10441
7.56k
                if (arg1->nodesetval == NULL)
10442
3
                    xmlXPathPErrMemory(ctxt);
10443
7.56k
            }
10444
9.23k
            xmlXPathValuePush(ctxt, arg1);
10445
9.23k
      xmlXPathReleaseObject(ctxt->context, arg2);
10446
9.23k
            total += cur;
10447
9.23k
            break;
10448
1.12k
        case XPATH_OP_ROOT:
10449
1.12k
            xmlXPathRoot(ctxt);
10450
1.12k
            break;
10451
7.56k
        case XPATH_OP_NODE:
10452
7.56k
            if (op->ch1 != -1)
10453
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10454
7.56k
      CHECK_ERROR0;
10455
7.56k
            if (op->ch2 != -1)
10456
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10457
7.56k
      CHECK_ERROR0;
10458
7.56k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10459
7.56k
    ctxt->context->node));
10460
7.56k
            break;
10461
8.72k
        case XPATH_OP_COLLECT:{
10462
8.72k
                if (op->ch1 == -1)
10463
0
                    break;
10464
10465
8.72k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10466
8.72k
    CHECK_ERROR0;
10467
10468
8.71k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10469
8.71k
                break;
10470
8.72k
            }
10471
16
        case XPATH_OP_VALUE:
10472
16
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10473
16
            break;
10474
8.50k
        case XPATH_OP_SORT:
10475
8.50k
            if (op->ch1 != -1)
10476
8.50k
                total +=
10477
8.50k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10478
8.50k
                                            first);
10479
8.50k
      CHECK_ERROR0;
10480
8.36k
            if ((ctxt->value != NULL)
10481
8.36k
                && (ctxt->value->type == XPATH_NODESET)
10482
8.12k
                && (ctxt->value->nodesetval != NULL)
10483
8.12k
    && (ctxt->value->nodesetval->nodeNr > 1))
10484
6.59k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10485
8.36k
            break;
10486
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10487
11.1k
  case XPATH_OP_FILTER:
10488
11.1k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10489
11.1k
            break;
10490
0
#endif
10491
237
        default:
10492
237
            total += xmlXPathCompOpEval(ctxt, op);
10493
237
            break;
10494
47.3k
    }
10495
10496
46.4k
    ctxt->context->depth -= 1;
10497
46.4k
    return(total);
10498
47.3k
}
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
110k
{
10513
110k
    int total = 0, cur;
10514
110k
    xmlXPathCompExprPtr comp;
10515
110k
    xmlXPathObjectPtr arg1, arg2;
10516
10517
110k
    CHECK_ERROR0;
10518
110k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10519
1
        return(0);
10520
110k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10521
110k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10522
110k
    ctxt->context->depth += 1;
10523
110k
    comp = ctxt->comp;
10524
110k
    switch (op->op) {
10525
0
        case XPATH_OP_END:
10526
0
            break;
10527
43.2k
        case XPATH_OP_UNION:
10528
43.2k
            total =
10529
43.2k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10530
43.2k
      CHECK_ERROR0;
10531
42.1k
            if ((ctxt->value != NULL)
10532
42.1k
                && (ctxt->value->type == XPATH_NODESET)
10533
42.1k
                && (ctxt->value->nodesetval != NULL)
10534
42.1k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10535
                /*
10536
                 * limit tree traversing to first node in the result
10537
                 */
10538
40.7k
    if (ctxt->value->nodesetval->nodeNr > 1)
10539
30.4k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10540
40.7k
                *last =
10541
40.7k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10542
40.7k
                                                     nodesetval->nodeNr -
10543
40.7k
                                                     1];
10544
40.7k
            }
10545
42.1k
            cur =
10546
42.1k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10547
42.1k
      CHECK_ERROR0;
10548
42.1k
            if ((ctxt->value != NULL)
10549
42.1k
                && (ctxt->value->type == XPATH_NODESET)
10550
42.0k
                && (ctxt->value->nodesetval != NULL)
10551
42.0k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10552
36.9k
            }
10553
10554
42.1k
            arg2 = xmlXPathValuePop(ctxt);
10555
42.1k
            arg1 = xmlXPathValuePop(ctxt);
10556
42.1k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10557
42.0k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10558
8
          xmlXPathReleaseObject(ctxt->context, arg1);
10559
8
          xmlXPathReleaseObject(ctxt->context, arg2);
10560
8
                XP_ERROR0(XPATH_INVALID_TYPE);
10561
0
            }
10562
42.0k
            if ((ctxt->context->opLimit != 0) &&
10563
42.0k
                (((arg1->nodesetval != NULL) &&
10564
42.0k
                  (xmlXPathCheckOpLimit(ctxt,
10565
42.0k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10566
42.0k
                 ((arg2->nodesetval != NULL) &&
10567
42.0k
                  (xmlXPathCheckOpLimit(ctxt,
10568
42.0k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10569
5
          xmlXPathReleaseObject(ctxt->context, arg1);
10570
5
          xmlXPathReleaseObject(ctxt->context, arg2);
10571
5
                break;
10572
5
            }
10573
10574
42.0k
            if ((arg2->nodesetval != NULL) &&
10575
42.0k
                (arg2->nodesetval->nodeNr != 0)) {
10576
36.9k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10577
36.9k
                                                        arg2->nodesetval);
10578
36.9k
                if (arg1->nodesetval == NULL)
10579
8
                    xmlXPathPErrMemory(ctxt);
10580
36.9k
            }
10581
42.0k
            xmlXPathValuePush(ctxt, arg1);
10582
42.0k
      xmlXPathReleaseObject(ctxt->context, arg2);
10583
42.0k
            total += cur;
10584
42.0k
            break;
10585
11.6k
        case XPATH_OP_ROOT:
10586
11.6k
            xmlXPathRoot(ctxt);
10587
11.6k
            break;
10588
17.4k
        case XPATH_OP_NODE:
10589
17.4k
            if (op->ch1 != -1)
10590
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10591
17.4k
      CHECK_ERROR0;
10592
17.4k
            if (op->ch2 != -1)
10593
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10594
17.4k
      CHECK_ERROR0;
10595
17.4k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10596
17.4k
    ctxt->context->node));
10597
17.4k
            break;
10598
25.1k
        case XPATH_OP_COLLECT:{
10599
25.1k
                if (op->ch1 == -1)
10600
0
                    break;
10601
10602
25.1k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10603
25.1k
    CHECK_ERROR0;
10604
10605
25.1k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10606
25.1k
                break;
10607
25.1k
            }
10608
18
        case XPATH_OP_VALUE:
10609
18
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10610
18
            break;
10611
12.6k
        case XPATH_OP_SORT:
10612
12.6k
            if (op->ch1 != -1)
10613
12.6k
                total +=
10614
12.6k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10615
12.6k
                                           last);
10616
12.6k
      CHECK_ERROR0;
10617
12.4k
            if ((ctxt->value != NULL)
10618
12.4k
                && (ctxt->value->type == XPATH_NODESET)
10619
12.0k
                && (ctxt->value->nodesetval != NULL)
10620
12.0k
    && (ctxt->value->nodesetval->nodeNr > 1))
10621
10.2k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10622
12.4k
            break;
10623
456
        default:
10624
456
            total += xmlXPathCompOpEval(ctxt, op);
10625
456
            break;
10626
110k
    }
10627
10628
109k
    ctxt->context->depth -= 1;
10629
109k
    return (total);
10630
110k
}
10631
10632
#ifdef XP_OPTIMIZED_FILTER_FIRST
10633
static int
10634
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10635
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10636
11.1k
{
10637
11.1k
    int total = 0;
10638
11.1k
    xmlXPathCompExprPtr comp;
10639
11.1k
    xmlXPathObjectPtr obj;
10640
11.1k
    xmlNodeSetPtr set;
10641
10642
11.1k
    CHECK_ERROR0;
10643
11.1k
    comp = ctxt->comp;
10644
    /*
10645
    * Optimization for ()[last()] selection i.e. the last elem
10646
    */
10647
11.1k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10648
11.1k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10649
2.38k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10650
1.76k
  int f = comp->steps[op->ch2].ch1;
10651
10652
1.76k
  if ((f != -1) &&
10653
1.76k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10654
1.53k
      (comp->steps[f].value5 == NULL) &&
10655
1.31k
      (comp->steps[f].value == 0) &&
10656
1.10k
      (comp->steps[f].value4 != NULL) &&
10657
1.10k
      (xmlStrEqual
10658
1.10k
      (comp->steps[f].value4, BAD_CAST "last"))) {
10659
883
      xmlNodePtr last = NULL;
10660
10661
883
      total +=
10662
883
    xmlXPathCompOpEvalLast(ctxt,
10663
883
        &comp->steps[op->ch1],
10664
883
        &last);
10665
883
      CHECK_ERROR0;
10666
      /*
10667
      * The nodeset should be in document order,
10668
      * Keep only the last value
10669
      */
10670
872
      if ((ctxt->value != NULL) &&
10671
872
    (ctxt->value->type == XPATH_NODESET) &&
10672
657
    (ctxt->value->nodesetval != NULL) &&
10673
657
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10674
442
    (ctxt->value->nodesetval->nodeNr > 1)) {
10675
227
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10676
227
    *first = *(ctxt->value->nodesetval->nodeTab);
10677
227
      }
10678
872
      return (total);
10679
883
  }
10680
1.76k
    }
10681
10682
10.2k
    if (op->ch1 != -1)
10683
10.2k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10684
10.2k
    CHECK_ERROR0;
10685
10.1k
    if (op->ch2 == -1)
10686
0
  return (total);
10687
10.1k
    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
10.1k
    CHECK_TYPE0(XPATH_NODESET);
10696
10.1k
    obj = xmlXPathValuePop(ctxt);
10697
10.1k
    set = obj->nodesetval;
10698
10.1k
    if (set != NULL) {
10699
10.1k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10700
10.1k
        if (set->nodeNr > 0)
10701
266
            *first = set->nodeTab[0];
10702
10.1k
    }
10703
10.1k
    xmlXPathValuePush(ctxt, obj);
10704
10705
10.1k
    return (total);
10706
10.1k
}
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
4.22M
{
10719
4.22M
    int total = 0;
10720
4.22M
    int equal, ret;
10721
4.22M
    xmlXPathCompExprPtr comp;
10722
4.22M
    xmlXPathObjectPtr arg1, arg2;
10723
10724
4.22M
    CHECK_ERROR0;
10725
4.22M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10726
4
        return(0);
10727
4.22M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10728
4.22M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10729
4.22M
    ctxt->context->depth += 1;
10730
4.22M
    comp = ctxt->comp;
10731
4.22M
    switch (op->op) {
10732
0
        case XPATH_OP_END:
10733
0
            break;
10734
92.1k
        case XPATH_OP_AND:
10735
92.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10736
92.1k
      CHECK_ERROR0;
10737
91.9k
            xmlXPathBooleanFunction(ctxt, 1);
10738
91.9k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10739
91.2k
                break;
10740
687
            arg2 = xmlXPathValuePop(ctxt);
10741
687
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10742
687
      if (ctxt->error) {
10743
34
    xmlXPathFreeObject(arg2);
10744
34
    break;
10745
34
      }
10746
653
            xmlXPathBooleanFunction(ctxt, 1);
10747
653
            if (ctxt->value != NULL)
10748
652
                ctxt->value->boolval &= arg2->boolval;
10749
653
      xmlXPathReleaseObject(ctxt->context, arg2);
10750
653
            break;
10751
3.89k
        case XPATH_OP_OR:
10752
3.89k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10753
3.89k
      CHECK_ERROR0;
10754
3.44k
            xmlXPathBooleanFunction(ctxt, 1);
10755
3.44k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10756
1.39k
                break;
10757
2.04k
            arg2 = xmlXPathValuePop(ctxt);
10758
2.04k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10759
2.04k
      if (ctxt->error) {
10760
71
    xmlXPathFreeObject(arg2);
10761
71
    break;
10762
71
      }
10763
1.97k
            xmlXPathBooleanFunction(ctxt, 1);
10764
1.97k
            if (ctxt->value != NULL)
10765
1.97k
                ctxt->value->boolval |= arg2->boolval;
10766
1.97k
      xmlXPathReleaseObject(ctxt->context, arg2);
10767
1.97k
            break;
10768
227k
        case XPATH_OP_EQUAL:
10769
227k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10770
227k
      CHECK_ERROR0;
10771
226k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10772
226k
      CHECK_ERROR0;
10773
226k
      if (op->value)
10774
220k
    equal = xmlXPathEqualValues(ctxt);
10775
5.53k
      else
10776
5.53k
    equal = xmlXPathNotEqualValues(ctxt);
10777
226k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10778
226k
            break;
10779
237k
        case XPATH_OP_CMP:
10780
237k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10781
237k
      CHECK_ERROR0;
10782
237k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10783
237k
      CHECK_ERROR0;
10784
237k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10785
237k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10786
237k
            break;
10787
190k
        case XPATH_OP_PLUS:
10788
190k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10789
190k
      CHECK_ERROR0;
10790
188k
            if (op->ch2 != -1) {
10791
156k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10792
156k
      }
10793
188k
      CHECK_ERROR0;
10794
188k
            if (op->value == 0)
10795
153k
                xmlXPathSubValues(ctxt);
10796
34.9k
            else if (op->value == 1)
10797
2.26k
                xmlXPathAddValues(ctxt);
10798
32.6k
            else if (op->value == 2)
10799
31.1k
                xmlXPathValueFlipSign(ctxt);
10800
1.50k
            else if (op->value == 3) {
10801
1.50k
                CAST_TO_NUMBER;
10802
1.50k
                CHECK_TYPE0(XPATH_NUMBER);
10803
1.49k
            }
10804
188k
            break;
10805
188k
        case XPATH_OP_MULT:
10806
32.8k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10807
32.8k
      CHECK_ERROR0;
10808
27.2k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10809
27.2k
      CHECK_ERROR0;
10810
27.1k
            if (op->value == 0)
10811
24.0k
                xmlXPathMultValues(ctxt);
10812
3.02k
            else if (op->value == 1)
10813
2.17k
                xmlXPathDivValues(ctxt);
10814
855
            else if (op->value == 2)
10815
855
                xmlXPathModValues(ctxt);
10816
27.1k
            break;
10817
65.3k
        case XPATH_OP_UNION:
10818
65.3k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10819
65.3k
      CHECK_ERROR0;
10820
63.8k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10821
63.8k
      CHECK_ERROR0;
10822
10823
63.7k
            arg2 = xmlXPathValuePop(ctxt);
10824
63.7k
            arg1 = xmlXPathValuePop(ctxt);
10825
63.7k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10826
63.7k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10827
11
          xmlXPathReleaseObject(ctxt->context, arg1);
10828
11
          xmlXPathReleaseObject(ctxt->context, arg2);
10829
11
                XP_ERROR0(XPATH_INVALID_TYPE);
10830
0
            }
10831
63.7k
            if ((ctxt->context->opLimit != 0) &&
10832
63.7k
                (((arg1->nodesetval != NULL) &&
10833
63.7k
                  (xmlXPathCheckOpLimit(ctxt,
10834
63.7k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10835
63.7k
                 ((arg2->nodesetval != NULL) &&
10836
63.7k
                  (xmlXPathCheckOpLimit(ctxt,
10837
63.7k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10838
4
          xmlXPathReleaseObject(ctxt->context, arg1);
10839
4
          xmlXPathReleaseObject(ctxt->context, arg2);
10840
4
                break;
10841
4
            }
10842
10843
63.7k
      if (((arg2->nodesetval != NULL) &&
10844
63.7k
     (arg2->nodesetval->nodeNr != 0)))
10845
55.1k
      {
10846
55.1k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10847
55.1k
              arg2->nodesetval);
10848
55.1k
                if (arg1->nodesetval == NULL)
10849
32
                    xmlXPathPErrMemory(ctxt);
10850
55.1k
      }
10851
10852
63.7k
            xmlXPathValuePush(ctxt, arg1);
10853
63.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
10854
63.7k
            break;
10855
193k
        case XPATH_OP_ROOT:
10856
193k
            xmlXPathRoot(ctxt);
10857
193k
            break;
10858
1.13M
        case XPATH_OP_NODE:
10859
1.13M
            if (op->ch1 != -1)
10860
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10861
1.13M
      CHECK_ERROR0;
10862
1.13M
            if (op->ch2 != -1)
10863
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10864
1.13M
      CHECK_ERROR0;
10865
1.13M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10866
1.13M
                                                    ctxt->context->node));
10867
1.13M
            break;
10868
771k
        case XPATH_OP_COLLECT:{
10869
771k
                if (op->ch1 == -1)
10870
0
                    break;
10871
10872
771k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10873
771k
    CHECK_ERROR0;
10874
10875
770k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10876
770k
                break;
10877
771k
            }
10878
529k
        case XPATH_OP_VALUE:
10879
529k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10880
529k
            break;
10881
67
        case XPATH_OP_VARIABLE:{
10882
67
    xmlXPathObjectPtr val;
10883
10884
67
                if (op->ch1 != -1)
10885
0
                    total +=
10886
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10887
67
                if (op->value5 == NULL) {
10888
64
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10889
64
        if (val == NULL) {
10890
64
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10891
64
                                       "Undefined variable: %s\n", op->value4);
10892
64
                        return 0;
10893
64
                    }
10894
0
                    xmlXPathValuePush(ctxt, val);
10895
3
    } else {
10896
3
                    const xmlChar *URI;
10897
10898
3
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10899
3
                    if (URI == NULL) {
10900
2
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10901
2
                                       "Undefined namespace prefix: %s\n",
10902
2
                                       op->value5);
10903
2
                        return 0;
10904
2
                    }
10905
1
        val = xmlXPathVariableLookupNS(ctxt->context,
10906
1
                                                       op->value4, URI);
10907
1
        if (val == NULL) {
10908
1
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10909
1
                                       "Undefined variable: %s:%s\n",
10910
1
                                       op->value5, op->value4);
10911
1
                        return 0;
10912
1
                    }
10913
0
                    xmlXPathValuePush(ctxt, val);
10914
0
                }
10915
0
                break;
10916
67
            }
10917
493k
        case XPATH_OP_FUNCTION:{
10918
493k
                xmlXPathFunction func;
10919
493k
                const xmlChar *oldFunc, *oldFuncURI;
10920
493k
    int i;
10921
493k
                int frame;
10922
10923
493k
                frame = ctxt->valueNr;
10924
493k
                if (op->ch1 != -1) {
10925
59.7k
                    total +=
10926
59.7k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10927
59.7k
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10928
398
                        break;
10929
59.7k
                }
10930
493k
    if (ctxt->valueNr < frame + op->value)
10931
493k
        XP_ERROR0(XPATH_INVALID_OPERAND);
10932
575k
    for (i = 0; i < op->value; i++) {
10933
82.6k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10934
82.6k
      XP_ERROR0(XPATH_INVALID_OPERAND);
10935
82.6k
                }
10936
493k
                if (op->cache != NULL)
10937
489k
                    func = op->cache;
10938
3.88k
                else {
10939
3.88k
                    const xmlChar *URI = NULL;
10940
10941
3.88k
                    if (op->value5 == NULL) {
10942
3.87k
                        func = xmlXPathFunctionLookup(ctxt->context,
10943
3.87k
                                                      op->value4);
10944
3.87k
                        if (func == NULL) {
10945
314
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10946
314
                                           "Unregistered function: %s\n",
10947
314
                                           op->value4);
10948
314
                            return 0;
10949
314
                        }
10950
3.87k
                    } else {
10951
4
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10952
4
                        if (URI == NULL) {
10953
3
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10954
3
                                           "Undefined namespace prefix: %s\n",
10955
3
                                           op->value5);
10956
3
                            return 0;
10957
3
                        }
10958
1
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10959
1
                                                        op->value4, URI);
10960
1
                        if (func == NULL) {
10961
1
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10962
1
                                           "Unregistered function: %s:%s\n",
10963
1
                                           op->value5, op->value4);
10964
1
                            return 0;
10965
1
                        }
10966
1
                    }
10967
3.56k
                    op->cache = func;
10968
3.56k
                    op->cacheURI = (void *) URI;
10969
3.56k
                }
10970
492k
                oldFunc = ctxt->context->function;
10971
492k
                oldFuncURI = ctxt->context->functionURI;
10972
492k
                ctxt->context->function = op->value4;
10973
492k
                ctxt->context->functionURI = op->cacheURI;
10974
492k
                func(ctxt, op->value);
10975
492k
                ctxt->context->function = oldFunc;
10976
492k
                ctxt->context->functionURI = oldFuncURI;
10977
492k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
10978
492k
                    (ctxt->valueNr != frame + 1))
10979
492k
                    XP_ERROR0(XPATH_STACK_ERROR);
10980
492k
                break;
10981
492k
            }
10982
91.9k
        case XPATH_OP_ARG:
10983
91.9k
            if (op->ch1 != -1) {
10984
32.1k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10985
32.1k
          CHECK_ERROR0;
10986
32.1k
            }
10987
84.9k
            if (op->ch2 != -1) {
10988
84.9k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10989
84.9k
          CHECK_ERROR0;
10990
84.9k
      }
10991
84.5k
            break;
10992
84.5k
        case XPATH_OP_PREDICATE:
10993
64.1k
        case XPATH_OP_FILTER:{
10994
64.1k
                xmlXPathObjectPtr obj;
10995
64.1k
                xmlNodeSetPtr set;
10996
10997
                /*
10998
                 * Optimization for ()[1] selection i.e. the first elem
10999
                 */
11000
64.1k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11001
64.1k
#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
64.1k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11012
32.2k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11013
#else
11014
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11015
#endif
11016
57.4k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11017
25.8k
                    xmlXPathObjectPtr val;
11018
11019
25.8k
                    val = comp->steps[op->ch2].value4;
11020
25.8k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11021
25.6k
                        (val->floatval == 1.0)) {
11022
19.5k
                        xmlNodePtr first = NULL;
11023
11024
19.5k
                        total +=
11025
19.5k
                            xmlXPathCompOpEvalFirst(ctxt,
11026
19.5k
                                                    &comp->steps[op->ch1],
11027
19.5k
                                                    &first);
11028
19.5k
      CHECK_ERROR0;
11029
                        /*
11030
                         * The nodeset should be in document order,
11031
                         * Keep only the first value
11032
                         */
11033
19.3k
                        if ((ctxt->value != NULL) &&
11034
19.3k
                            (ctxt->value->type == XPATH_NODESET) &&
11035
18.9k
                            (ctxt->value->nodesetval != NULL) &&
11036
18.9k
                            (ctxt->value->nodesetval->nodeNr > 1))
11037
6.59k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11038
6.59k
                                                        1, 1);
11039
19.3k
                        break;
11040
19.5k
                    }
11041
25.8k
                }
11042
                /*
11043
                 * Optimization for ()[last()] selection i.e. the last elem
11044
                 */
11045
44.5k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11046
44.5k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
23.4k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11048
19.6k
                    int f = comp->steps[op->ch2].ch1;
11049
11050
19.6k
                    if ((f != -1) &&
11051
19.6k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11052
14.0k
                        (comp->steps[f].value5 == NULL) &&
11053
13.8k
                        (comp->steps[f].value == 0) &&
11054
12.9k
                        (comp->steps[f].value4 != NULL) &&
11055
12.9k
                        (xmlStrEqual
11056
12.9k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11057
11.6k
                        xmlNodePtr last = NULL;
11058
11059
11.6k
                        total +=
11060
11.6k
                            xmlXPathCompOpEvalLast(ctxt,
11061
11.6k
                                                   &comp->steps[op->ch1],
11062
11.6k
                                                   &last);
11063
11.6k
      CHECK_ERROR0;
11064
                        /*
11065
                         * The nodeset should be in document order,
11066
                         * Keep only the last value
11067
                         */
11068
11.5k
                        if ((ctxt->value != NULL) &&
11069
11.5k
                            (ctxt->value->type == XPATH_NODESET) &&
11070
11.3k
                            (ctxt->value->nodesetval != NULL) &&
11071
11.3k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11072
11.0k
                            (ctxt->value->nodesetval->nodeNr > 1))
11073
9.98k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11074
11.5k
                        break;
11075
11.6k
                    }
11076
19.6k
                }
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
32.9k
                if (op->ch1 != -1)
11089
32.9k
                    total +=
11090
32.9k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11091
32.9k
    CHECK_ERROR0;
11092
32.4k
                if (op->ch2 == -1)
11093
0
                    break;
11094
32.4k
                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
32.4k
                CHECK_TYPE0(XPATH_NODESET);
11104
32.4k
                obj = xmlXPathValuePop(ctxt);
11105
32.4k
                set = obj->nodesetval;
11106
32.4k
                if (set != NULL)
11107
32.4k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11108
32.4k
                                          1, set->nodeNr, 1);
11109
32.4k
                xmlXPathValuePush(ctxt, obj);
11110
32.4k
                break;
11111
32.4k
            }
11112
98.1k
        case XPATH_OP_SORT:
11113
98.1k
            if (op->ch1 != -1)
11114
98.1k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11115
98.1k
      CHECK_ERROR0;
11116
95.8k
            if ((ctxt->value != NULL) &&
11117
95.8k
                (ctxt->value->type == XPATH_NODESET) &&
11118
88.6k
                (ctxt->value->nodesetval != NULL) &&
11119
88.6k
    (ctxt->value->nodesetval->nodeNr > 1))
11120
39.5k
      {
11121
39.5k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11122
39.5k
      }
11123
95.8k
            break;
11124
0
        default:
11125
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11126
0
            break;
11127
4.22M
    }
11128
11129
4.19M
    ctxt->context->depth -= 1;
11130
4.19M
    return (total);
11131
4.22M
}
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
1.77M
{
11146
1.77M
    xmlXPathObjectPtr resObj = NULL;
11147
11148
2.02M
start:
11149
2.02M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11150
2
        return(0);
11151
    /* comp = ctxt->comp; */
11152
2.02M
    switch (op->op) {
11153
0
        case XPATH_OP_END:
11154
0
            return (0);
11155
251k
  case XPATH_OP_VALUE:
11156
251k
      resObj = (xmlXPathObjectPtr) op->value4;
11157
251k
      if (isPredicate)
11158
251k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11159
0
      return(xmlXPathCastToBoolean(resObj));
11160
247k
  case XPATH_OP_SORT:
11161
      /*
11162
      * We don't need sorting for boolean results. Skip this one.
11163
      */
11164
247k
            if (op->ch1 != -1) {
11165
247k
    op = &ctxt->comp->steps[op->ch1];
11166
247k
    goto start;
11167
247k
      }
11168
0
      return(0);
11169
383k
  case XPATH_OP_COLLECT:
11170
383k
      if (op->ch1 == -1)
11171
0
    return(0);
11172
11173
383k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11174
383k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11175
53
    return(-1);
11176
11177
383k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11178
383k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11179
336
    return(-1);
11180
11181
382k
      resObj = xmlXPathValuePop(ctxt);
11182
382k
      if (resObj == NULL)
11183
0
    return(-1);
11184
382k
      break;
11185
1.13M
  default:
11186
      /*
11187
      * Fallback to call xmlXPathCompOpEval().
11188
      */
11189
1.13M
      xmlXPathCompOpEval(ctxt, op);
11190
1.13M
      if (ctxt->error != XPATH_EXPRESSION_OK)
11191
609
    return(-1);
11192
11193
1.13M
      resObj = xmlXPathValuePop(ctxt);
11194
1.13M
      if (resObj == NULL)
11195
0
    return(-1);
11196
1.13M
      break;
11197
2.02M
    }
11198
11199
1.52M
    if (resObj) {
11200
1.52M
  int res;
11201
11202
1.52M
  if (resObj->type == XPATH_BOOLEAN) {
11203
359k
      res = resObj->boolval;
11204
1.16M
  } 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.16M
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11214
1.16M
  } else {
11215
0
      res = xmlXPathCastToBoolean(resObj);
11216
0
  }
11217
1.52M
  xmlXPathReleaseObject(ctxt->context, resObj);
11218
1.52M
  return(res);
11219
1.52M
    }
11220
11221
0
    return(0);
11222
1.52M
}
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
11.7k
{
11465
11.7k
    xmlXPathCompExprPtr comp;
11466
11.7k
    int oldDepth;
11467
11468
11.7k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11469
0
  return(-1);
11470
11471
11.7k
    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
11.7k
    comp = ctxt->comp;
11521
11.7k
    if (comp->last < 0) {
11522
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11523
0
  return(-1);
11524
0
    }
11525
11.7k
    oldDepth = ctxt->context->depth;
11526
11.7k
    if (toBool)
11527
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11528
0
      &comp->steps[comp->last], 0));
11529
11.7k
    else
11530
11.7k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11531
11.7k
    ctxt->context->depth = oldDepth;
11532
11533
11.7k
    return(0);
11534
11.7k
}
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
1.41M
                                xmlXPathObject *res) {
11595
1.41M
    if ((ctxt == NULL) || (res == NULL)) return(0);
11596
1.41M
    switch (res->type) {
11597
0
        case XPATH_BOOLEAN:
11598
0
      return(res->boolval);
11599
832k
        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
832k
      return(res->floatval == ctxt->context->proximityPosition);
11605
0
#endif
11606
554k
        case XPATH_NODESET:
11607
554k
        case XPATH_XSLT_TREE:
11608
554k
      if (res->nodesetval == NULL)
11609
0
    return(0);
11610
554k
      return(res->nodesetval->nodeNr != 0);
11611
26.0k
        case XPATH_STRING:
11612
26.0k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11613
0
        default:
11614
0
      break;
11615
1.41M
    }
11616
0
    return(0);
11617
1.41M
}
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
301k
{
11709
301k
    xmlXPathCompExprPtr comp = pctxt->comp;
11710
301k
    xmlXPathContextPtr ctxt;
11711
11712
    /*
11713
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11714
    * internal representation.
11715
    */
11716
11717
301k
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11718
78.1k
        (op->ch1 != -1) &&
11719
78.1k
        (op->ch2 == -1 /* no predicate */))
11720
68.9k
    {
11721
68.9k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11722
11723
68.9k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11724
15.0k
            ((xmlXPathAxisVal) prevop->value ==
11725
15.0k
                AXIS_DESCENDANT_OR_SELF) &&
11726
8.11k
            (prevop->ch2 == -1) &&
11727
8.05k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11728
7.98k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11729
7.92k
        {
11730
            /*
11731
            * This is a "descendant-or-self::node()" without predicates.
11732
            * Try to eliminate it.
11733
            */
11734
11735
7.92k
            switch ((xmlXPathAxisVal) op->value) {
11736
5.65k
                case AXIS_CHILD:
11737
5.65k
                case AXIS_DESCENDANT:
11738
                    /*
11739
                    * Convert "descendant-or-self::node()/child::" or
11740
                    * "descendant-or-self::node()/descendant::" to
11741
                    * "descendant::"
11742
                    */
11743
5.65k
                    op->ch1   = prevop->ch1;
11744
5.65k
                    op->value = AXIS_DESCENDANT;
11745
5.65k
                    break;
11746
1
                case AXIS_SELF:
11747
291
                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
291
                    op->ch1   = prevop->ch1;
11754
291
                    op->value = AXIS_DESCENDANT_OR_SELF;
11755
291
                    break;
11756
1.97k
                default:
11757
1.97k
                    break;
11758
7.92k
            }
11759
7.92k
  }
11760
68.9k
    }
11761
11762
    /* OP_VALUE has invalid ch1. */
11763
301k
    if (op->op == XPATH_OP_VALUE)
11764
10.7k
        return;
11765
11766
    /* Recurse */
11767
290k
    ctxt = pctxt->context;
11768
290k
    if (ctxt != NULL) {
11769
290k
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11770
127
            return;
11771
290k
        ctxt->depth += 1;
11772
290k
    }
11773
290k
    if (op->ch1 != -1)
11774
191k
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11775
290k
    if (op->ch2 != -1)
11776
98.0k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11777
290k
    if (ctxt != NULL)
11778
290k
        ctxt->depth -= 1;
11779
290k
}
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
0
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11791
0
    xmlXPathParserContextPtr pctxt;
11792
0
    xmlXPathContextPtr tmpctxt = NULL;
11793
0
    xmlXPathCompExprPtr comp;
11794
0
    int oldDepth = 0;
11795
11796
0
    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
0
    xmlInitParser();
11806
11807
    /*
11808
     * We need an xmlXPathContext for the depth check.
11809
     */
11810
0
    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
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
11818
0
    if (pctxt == NULL) {
11819
0
        if (tmpctxt != NULL)
11820
0
            xmlXPathFreeContext(tmpctxt);
11821
0
        return NULL;
11822
0
    }
11823
11824
0
    oldDepth = ctxt->depth;
11825
0
    xmlXPathCompileExpr(pctxt, 1);
11826
0
    ctxt->depth = oldDepth;
11827
11828
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
11829
0
    {
11830
0
        xmlXPathFreeParserContext(pctxt);
11831
0
        if (tmpctxt != NULL)
11832
0
            xmlXPathFreeContext(tmpctxt);
11833
0
        return(NULL);
11834
0
    }
11835
11836
0
    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
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11844
0
  comp = NULL;
11845
0
    } else {
11846
0
  comp = pctxt->comp;
11847
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11848
0
            if (ctxt != NULL)
11849
0
                oldDepth = ctxt->depth;
11850
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11851
0
            if (ctxt != NULL)
11852
0
                ctxt->depth = oldDepth;
11853
0
  }
11854
0
  pctxt->comp = NULL;
11855
0
    }
11856
0
    xmlXPathFreeParserContext(pctxt);
11857
0
    if (tmpctxt != NULL)
11858
0
        xmlXPathFreeContext(tmpctxt);
11859
11860
0
    if (comp != NULL) {
11861
0
  comp->expr = xmlStrdup(str);
11862
0
    }
11863
0
    return(comp);
11864
0
}
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
0
{
11895
0
    xmlXPathParserContextPtr pctxt;
11896
0
    xmlXPathObjectPtr resObj = NULL;
11897
0
    int res;
11898
11899
0
    if (comp == NULL)
11900
0
  return(-1);
11901
0
    xmlInitParser();
11902
11903
0
    xmlResetError(&ctxt->lastError);
11904
11905
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11906
0
    if (pctxt == NULL)
11907
0
        return(-1);
11908
0
    res = xmlXPathRunEval(pctxt, toBool);
11909
11910
0
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11911
0
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11912
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11913
0
        else if (!toBool)
11914
0
            resObj = xmlXPathValuePop(pctxt);
11915
0
    }
11916
11917
0
    if (resObjPtr)
11918
0
        *resObjPtr = resObj;
11919
0
    else
11920
0
        xmlXPathReleaseObject(ctxt, resObj);
11921
11922
0
    pctxt->comp = NULL;
11923
0
    xmlXPathFreeParserContext(pctxt);
11924
11925
0
    return(res);
11926
0
}
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
0
{
11939
0
    xmlXPathObjectPtr res = NULL;
11940
11941
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11942
0
    return(res);
11943
0
}
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
13.3k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
11971
#ifdef XPATH_STREAMING
11972
    xmlXPathCompExprPtr comp;
11973
#endif
11974
13.3k
    int oldDepth = 0;
11975
11976
13.3k
    if ((ctxt == NULL) || (ctxt->context == NULL))
11977
0
        return;
11978
13.3k
    if (ctxt->context->lastError.code != 0)
11979
320
        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
13.0k
    {
11995
13.0k
        if (ctxt->context != NULL)
11996
13.0k
            oldDepth = ctxt->context->depth;
11997
13.0k
  xmlXPathCompileExpr(ctxt, 1);
11998
13.0k
        if (ctxt->context != NULL)
11999
13.0k
            ctxt->context->depth = oldDepth;
12000
13.0k
        CHECK_ERROR;
12001
12002
        /* Check for trailing characters. */
12003
11.9k
        if (*ctxt->cur != 0)
12004
11.7k
            XP_ERROR(XPATH_EXPR_ERROR);
12005
12006
11.7k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12007
11.6k
            if (ctxt->context != NULL)
12008
11.6k
                oldDepth = ctxt->context->depth;
12009
11.6k
      xmlXPathOptimizeExpression(ctxt,
12010
11.6k
    &ctxt->comp->steps[ctxt->comp->last]);
12011
11.6k
            if (ctxt->context != NULL)
12012
11.6k
                ctxt->context->depth = oldDepth;
12013
11.6k
        }
12014
11.7k
    }
12015
12016
0
    xmlXPathRunEval(ctxt, 0);
12017
11.7k
}
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 */