Coverage Report

Created: 2025-07-11 06:13

/src/libxml2/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: Daniel Veillard
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
3.03M
#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
2.44M
#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
16.3M
#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
45.6M
#define XPATH_MAX_RECURSION_DEPTH 500
113
#elif defined(_WIN32)
114
/* Windows typically limits stack size to 1MB. */
115
#define XPATH_MAX_RECURSION_DEPTH 1000
116
#else
117
#define XPATH_MAX_RECURSION_DEPTH 5000
118
#endif
119
120
/*
121
 * TODO:
122
 * There are a few spots where some tests are done which depend upon ascii
123
 * data.  These should be enhanced for full UTF8 support (see particularly
124
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
125
 */
126
127
#if defined(LIBXML_XPATH_ENABLED)
128
129
static void
130
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs);
131
132
static const struct {
133
    const char *name;
134
    xmlXPathFunction func;
135
} xmlXPathStandardFunctions[] = {
136
    { "boolean", xmlXPathBooleanFunction },
137
    { "ceiling", xmlXPathCeilingFunction },
138
    { "count", xmlXPathCountFunction },
139
    { "concat", xmlXPathConcatFunction },
140
    { "contains", xmlXPathContainsFunction },
141
    { "id", xmlXPathIdFunction },
142
    { "false", xmlXPathFalseFunction },
143
    { "floor", xmlXPathFloorFunction },
144
    { "last", xmlXPathLastFunction },
145
    { "lang", xmlXPathLangFunction },
146
    { "local-name", xmlXPathLocalNameFunction },
147
    { "not", xmlXPathNotFunction },
148
    { "name", xmlXPathNameFunction },
149
    { "namespace-uri", xmlXPathNamespaceURIFunction },
150
    { "normalize-space", xmlXPathNormalizeFunction },
151
    { "number", xmlXPathNumberFunction },
152
    { "position", xmlXPathPositionFunction },
153
    { "round", xmlXPathRoundFunction },
154
    { "string", xmlXPathStringFunction },
155
    { "string-length", xmlXPathStringLengthFunction },
156
    { "starts-with", xmlXPathStartsWithFunction },
157
    { "substring", xmlXPathSubstringFunction },
158
    { "substring-before", xmlXPathSubstringBeforeFunction },
159
    { "substring-after", xmlXPathSubstringAfterFunction },
160
    { "sum", xmlXPathSumFunction },
161
    { "true", xmlXPathTrueFunction },
162
    { "translate", xmlXPathTranslateFunction }
163
};
164
165
#define NUM_STANDARD_FUNCTIONS \
166
112
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
236k
#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
137k
xmlXPathSFComputeHash(const xmlChar *name) {
187
137k
    unsigned hashValue = 5381;
188
137k
    const xmlChar *ptr;
189
190
818k
    for (ptr = name; *ptr; ptr++)
191
680k
        hashValue = hashValue * 33 + *ptr;
192
193
137k
    return(hashValue);
194
137k
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
4
xmlInitXPathInternal(void) {
202
4
    size_t i;
203
204
4
#if defined(NAN) && defined(INFINITY)
205
4
    xmlXPathNAN = NAN;
206
4
    xmlXPathPINF = INFINITY;
207
4
    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
260
    for (i = 0; i < SF_HASH_SIZE; i++)
221
256
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
112
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
108
        const char *name = xmlXPathStandardFunctions[i].name;
225
108
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
136
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
28
            bucketIndex += 1;
229
28
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
28
        }
232
233
108
        xmlXPathSFHash[bucketIndex] = i;
234
108
    }
235
4
}
236
237
/************************************************************************
238
 *                  *
239
 *      Floating point stuff        *
240
 *                  *
241
 ************************************************************************/
242
243
/**
244
 * Checks whether a double is a NaN.
245
 *
246
 * @param val  a double value
247
 * @returns 1 if the value is a NaN, 0 otherwise
248
 */
249
int
250
2.50M
xmlXPathIsNaN(double val) {
251
2.50M
#ifdef isnan
252
2.50M
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
2.50M
}
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
1.19M
xmlXPathIsInf(double val) {
266
1.19M
#ifdef isinf
267
1.19M
    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
1.19M
}
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
228M
#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
78.9M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
78.9M
    int depth1, depth2;
311
78.9M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
78.9M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
78.9M
    xmlNodePtr cur, root;
314
78.9M
    XML_INTPTR_T l1, l2;
315
316
78.9M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
78.9M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
78.9M
    switch (node1->type) {
326
59.2M
  case XML_ELEMENT_NODE:
327
59.2M
      if (node2->type == XML_ELEMENT_NODE) {
328
45.6M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
45.6M
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
45.6M
        (node1->doc == node2->doc))
331
22.3M
    {
332
22.3M
        l1 = -XML_NODE_SORT_VALUE(node1);
333
22.3M
        l2 = -XML_NODE_SORT_VALUE(node2);
334
22.3M
        if (l1 < l2)
335
17.2M
      return(1);
336
5.05M
        if (l1 > l2)
337
5.05M
      return(-1);
338
5.05M
    } else
339
23.3M
        goto turtle_comparison;
340
45.6M
      }
341
13.5M
      break;
342
13.5M
  case XML_ATTRIBUTE_NODE:
343
123k
      precedence1 = 1; /* element is owner */
344
123k
      miscNode1 = node1;
345
123k
      node1 = node1->parent;
346
123k
      misc = 1;
347
123k
      break;
348
16.4M
  case XML_TEXT_NODE:
349
16.5M
  case XML_CDATA_SECTION_NODE:
350
17.2M
  case XML_COMMENT_NODE:
351
18.1M
  case XML_PI_NODE: {
352
18.1M
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
18.1M
      if (node1->prev != NULL) {
357
16.6M
    do {
358
16.6M
        node1 = node1->prev;
359
16.6M
        if (node1->type == XML_ELEMENT_NODE) {
360
10.7M
      precedence1 = 3; /* element in prev-sibl axis */
361
10.7M
      break;
362
10.7M
        }
363
5.89M
        if (node1->prev == NULL) {
364
1.08M
      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
1.08M
      node1 = node1->parent;
370
1.08M
      break;
371
1.08M
        }
372
5.89M
    } while (1);
373
11.8M
      } else {
374
6.30M
    precedence1 = 2; /* element is parent */
375
6.30M
    node1 = node1->parent;
376
6.30M
      }
377
18.1M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
18.1M
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
621k
    node1 = miscNode1;
383
621k
    precedence1 = 0;
384
621k
      } else
385
17.5M
    misc = 1;
386
18.1M
  }
387
0
      break;
388
1.17M
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
1.17M
      return(1);
393
268k
  default:
394
268k
      break;
395
78.9M
    }
396
32.1M
    switch (node2->type) {
397
12.4M
  case XML_ELEMENT_NODE:
398
12.4M
      break;
399
116k
  case XML_ATTRIBUTE_NODE:
400
116k
      precedence2 = 1; /* element is owner */
401
116k
      miscNode2 = node2;
402
116k
      node2 = node2->parent;
403
116k
      misc = 1;
404
116k
      break;
405
17.6M
  case XML_TEXT_NODE:
406
17.7M
  case XML_CDATA_SECTION_NODE:
407
18.5M
  case XML_COMMENT_NODE:
408
19.3M
  case XML_PI_NODE: {
409
19.3M
      miscNode2 = node2;
410
19.3M
      if (node2->prev != NULL) {
411
17.1M
    do {
412
17.1M
        node2 = node2->prev;
413
17.1M
        if (node2->type == XML_ELEMENT_NODE) {
414
11.6M
      precedence2 = 3; /* element in prev-sibl axis */
415
11.6M
      break;
416
11.6M
        }
417
5.49M
        if (node2->prev == NULL) {
418
1.04M
      precedence2 = 2; /* element is parent */
419
1.04M
      node2 = node2->parent;
420
1.04M
      break;
421
1.04M
        }
422
5.49M
    } while (1);
423
12.7M
      } else {
424
6.61M
    precedence2 = 2; /* element is parent */
425
6.61M
    node2 = node2->parent;
426
6.61M
      }
427
19.3M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
19.3M
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
844k
      {
430
844k
    node2 = miscNode2;
431
844k
    precedence2 = 0;
432
844k
      } else
433
18.4M
    misc = 1;
434
19.3M
  }
435
0
      break;
436
31.5k
  case XML_NAMESPACE_DECL:
437
31.5k
      return(1);
438
211k
  default:
439
211k
      break;
440
32.1M
    }
441
32.0M
    if (misc) {
442
30.6M
  if (node1 == node2) {
443
9.99M
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
1.58M
    cur = miscNode2->prev;
449
1.69M
    while (cur != NULL) {
450
1.62M
        if (cur == miscNode1)
451
1.37M
      return(1);
452
256k
        if (cur->type == XML_ELEMENT_NODE)
453
150k
      return(-1);
454
105k
        cur = cur->prev;
455
105k
    }
456
62.3k
    return (-1);
457
8.40M
      } 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
8.40M
    if (precedence1 < precedence2)
464
6.96M
        return(1);
465
1.44M
    else
466
1.44M
        return(-1);
467
8.40M
      }
468
9.99M
  }
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
20.6M
  if ((precedence2 == 3) && (precedence1 > 1)) {
479
2.10M
      cur = node1->parent;
480
63.6M
      while (cur) {
481
62.1M
    if (cur == node2)
482
597k
        return(1);
483
61.5M
    cur = cur->parent;
484
61.5M
      }
485
2.10M
  }
486
20.0M
  if ((precedence1 == 3) && (precedence2 > 1)) {
487
1.64M
      cur = node2->parent;
488
56.1M
      while (cur) {
489
54.6M
    if (cur == node1)
490
137k
        return(-1);
491
54.5M
    cur = cur->parent;
492
54.5M
      }
493
1.64M
  }
494
20.0M
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
21.3M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
21.3M
  (node2->type == XML_ELEMENT_NODE) &&
501
21.3M
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
21.3M
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
21.3M
  (node1->doc == node2->doc)) {
504
505
19.6M
  l1 = -XML_NODE_SORT_VALUE(node1);
506
19.6M
  l2 = -XML_NODE_SORT_VALUE(node2);
507
19.6M
  if (l1 < l2)
508
13.9M
      return(1);
509
5.70M
  if (l1 > l2)
510
5.70M
      return(-1);
511
5.70M
    }
512
513
25.0M
turtle_comparison:
514
515
25.0M
    if (node1 == node2->prev)
516
21.8M
  return(1);
517
3.18M
    if (node1 == node2->next)
518
131k
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
9.28M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
6.62M
  if (cur->parent == node1)
524
395k
      return(1);
525
6.22M
  depth2++;
526
6.22M
    }
527
2.66M
    root = cur;
528
10.9M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
8.51M
  if (cur->parent == node2)
530
243k
      return(-1);
531
8.27M
  depth1++;
532
8.27M
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
2.41M
    if (root != cur) {
537
1.44M
  return(-2);
538
1.44M
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
1.98M
    while (depth1 > depth2) {
543
1.01M
  depth1--;
544
1.01M
  node1 = node1->parent;
545
1.01M
    }
546
1.78M
    while (depth2 > depth1) {
547
809k
  depth2--;
548
809k
  node2 = node2->parent;
549
809k
    }
550
1.28M
    while (node1->parent != node2->parent) {
551
316k
  node1 = node1->parent;
552
316k
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
316k
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
316k
    }
557
    /*
558
     * Find who's first.
559
     */
560
971k
    if (node1 == node2->prev)
561
145k
  return(1);
562
826k
    if (node1 == node2->next)
563
350k
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
476k
    if ((node1->type == XML_ELEMENT_NODE) &&
568
476k
  (node2->type == XML_ELEMENT_NODE) &&
569
476k
  (0 > XML_NODE_SORT_VALUE(node1)) &&
570
476k
  (0 > XML_NODE_SORT_VALUE(node2)) &&
571
476k
  (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
6.39M
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
6.17M
  if (cur == node2)
583
249k
      return(1);
584
226k
    return(-1); /* assume there is no sibling list corruption */
585
476k
}
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
23.7M
#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
78.9M
    {
607
78.9M
        int res = xmlXPathCmpNodesExt(x, y);
608
78.9M
        return res == -2 ? res : -res;
609
78.9M
    }
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
78.9M
#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
51.3k
    { 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
1.66M
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
1.66M
       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
124k
{
678
124k
    if (ctxt == NULL)
679
0
        return;
680
124k
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
124k
                        &ctxt->lastError);
682
124k
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
37.1k
{
692
37.1k
    if (ctxt == NULL)
693
3
        return;
694
37.1k
    ctxt->error = XPATH_MEMORY_ERROR;
695
37.1k
    xmlXPathErrMemory(ctxt->context);
696
37.1k
}
697
698
/**
699
 * Handle an XPath error
700
 *
701
 * @param ctxt  a XPath parser context
702
 * @param code  the error code
703
 * @param fmt  format string for error message
704
 * @param ...  extra args
705
 */
706
static void
707
1.66M
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
1.66M
    va_list ap;
709
1.66M
    xmlStructuredErrorFunc schannel = NULL;
710
1.66M
    xmlGenericErrorFunc channel = NULL;
711
1.66M
    void *data = NULL;
712
1.66M
    xmlNodePtr node = NULL;
713
1.66M
    int res;
714
715
1.66M
    if (ctxt == NULL)
716
0
        return;
717
1.66M
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
1.66M
    if (ctxt->error != 0)
721
8.11k
        return;
722
723
1.65M
    ctxt->error = code;
724
725
1.65M
    if (ctxt->context != NULL) {
726
1.65M
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
1.65M
        if (err->code == XML_ERR_NO_MEMORY)
730
2.98k
            return;
731
732
        /* cleanup current last error */
733
1.65M
        xmlResetError(err);
734
735
1.65M
        err->domain = XML_FROM_XPATH;
736
1.65M
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
1.65M
        err->level = XML_ERR_ERROR;
738
1.65M
        if (ctxt->base != NULL) {
739
476k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
476k
            if (err->str1 == NULL) {
741
22
                xmlXPathPErrMemory(ctxt);
742
22
                return;
743
22
            }
744
476k
        }
745
1.65M
        err->int1 = ctxt->cur - ctxt->base;
746
1.65M
        err->node = ctxt->context->debugNode;
747
748
1.65M
        schannel = ctxt->context->error;
749
1.65M
        data = ctxt->context->userData;
750
1.65M
        node = ctxt->context->debugNode;
751
1.65M
    }
752
753
1.65M
    if (schannel == NULL) {
754
1.65M
        channel = xmlGenericError;
755
1.65M
        data = xmlGenericErrorContext;
756
1.65M
    }
757
758
1.65M
    va_start(ap, fmt);
759
1.65M
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
1.65M
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
1.65M
                         XML_ERR_ERROR, NULL, 0,
762
1.65M
                         (const char *) ctxt->base, NULL, NULL,
763
1.65M
                         ctxt->cur - ctxt->base, 0,
764
1.65M
                         fmt, ap);
765
1.65M
    va_end(ap);
766
1.65M
    if (res < 0)
767
223
        xmlXPathPErrMemory(ctxt);
768
1.65M
}
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
1.42M
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
1.42M
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
1.42M
}
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
168k
              int line ATTRIBUTE_UNUSED, int no) {
792
168k
    xmlXPathErr(ctxt, no);
793
168k
}
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
99.3M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
99.3M
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
99.3M
    if ((opCount > xpctxt->opLimit) ||
807
99.3M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
847k
        xpctxt->opCount = xpctxt->opLimit;
809
847k
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
847k
        return(-1);
811
847k
    }
812
813
98.4M
    xpctxt->opCount += opCount;
814
98.4M
    return(0);
815
99.3M
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
95.4M
    ((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
937k
xmlXPathNewCompExpr(void) {
941
937k
    xmlXPathCompExprPtr cur;
942
943
937k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
937k
    if (cur == NULL)
945
47
  return(NULL);
946
937k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
937k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
937k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
937k
    cur->nbStep = 0;
953
937k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
937k
                                     sizeof(xmlXPathStepOp));
955
937k
    if (cur->steps == NULL) {
956
53
  xmlFree(cur);
957
53
  return(NULL);
958
53
    }
959
937k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
937k
    cur->last = -1;
961
937k
    return(cur);
962
937k
}
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
938k
{
972
938k
    xmlXPathStepOpPtr op;
973
938k
    int i;
974
975
938k
    if (comp == NULL)
976
557
        return;
977
937k
    if (comp->dict == NULL) {
978
11.4M
  for (i = 0; i < comp->nbStep; i++) {
979
10.7M
      op = &comp->steps[i];
980
10.7M
      if (op->value4 != NULL) {
981
893k
    if (op->op == XPATH_OP_VALUE)
982
365k
        xmlXPathFreeObject(op->value4);
983
527k
    else
984
527k
        xmlFree(op->value4);
985
893k
      }
986
10.7M
      if (op->value5 != NULL)
987
1.75M
    xmlFree(op->value5);
988
10.7M
  }
989
737k
    } else {
990
1.59M
  for (i = 0; i < comp->nbStep; i++) {
991
1.39M
      op = &comp->steps[i];
992
1.39M
      if (op->value4 != NULL) {
993
181k
    if (op->op == XPATH_OP_VALUE)
994
62.0k
        xmlXPathFreeObject(op->value4);
995
181k
      }
996
1.39M
  }
997
200k
        xmlDictFree(comp->dict);
998
200k
    }
999
937k
    if (comp->steps != NULL) {
1000
937k
        xmlFree(comp->steps);
1001
937k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
937k
    if (comp->expr != NULL) {
1008
441k
        xmlFree(comp->expr);
1009
441k
    }
1010
1011
937k
    xmlFree(comp);
1012
937k
}
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
12.1M
   int value2, int value3, void *value4, void *value5) {
1032
12.1M
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
12.1M
    if (comp->nbStep >= comp->maxStep) {
1034
3.03M
  xmlXPathStepOp *real;
1035
3.03M
        int newSize;
1036
1037
3.03M
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
3.03M
                                  10, XPATH_MAX_STEPS);
1039
3.03M
        if (newSize < 0) {
1040
0
      xmlXPathPErrMemory(ctxt);
1041
0
      return(-1);
1042
0
        }
1043
3.03M
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
3.03M
  if (real == NULL) {
1045
592
      xmlXPathPErrMemory(ctxt);
1046
592
      return(-1);
1047
592
  }
1048
3.03M
  comp->steps = real;
1049
3.03M
  comp->maxStep = newSize;
1050
3.03M
    }
1051
12.1M
    comp->last = comp->nbStep;
1052
12.1M
    comp->steps[comp->nbStep].ch1 = ch1;
1053
12.1M
    comp->steps[comp->nbStep].ch2 = ch2;
1054
12.1M
    comp->steps[comp->nbStep].op = op;
1055
12.1M
    comp->steps[comp->nbStep].value = value;
1056
12.1M
    comp->steps[comp->nbStep].value2 = value2;
1057
12.1M
    comp->steps[comp->nbStep].value3 = value3;
1058
12.1M
    if ((comp->dict != NULL) &&
1059
12.1M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1060
1.39M
   (op == XPATH_OP_COLLECT))) {
1061
484k
        if (value4 != NULL) {
1062
119k
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1063
119k
          (void *)xmlDictLookup(comp->dict, value4, -1);
1064
119k
      xmlFree(value4);
1065
119k
  } else
1066
365k
      comp->steps[comp->nbStep].value4 = NULL;
1067
484k
        if (value5 != NULL) {
1068
234k
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1069
234k
          (void *)xmlDictLookup(comp->dict, value5, -1);
1070
234k
      xmlFree(value5);
1071
234k
  } else
1072
250k
      comp->steps[comp->nbStep].value5 = NULL;
1073
11.6M
    } else {
1074
11.6M
  comp->steps[comp->nbStep].value4 = value4;
1075
11.6M
  comp->steps[comp->nbStep].value5 = value5;
1076
11.6M
    }
1077
12.1M
    comp->steps[comp->nbStep].cache = NULL;
1078
12.1M
    return(comp->nbStep++);
1079
12.1M
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
2.53M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
2.53M
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
1.40M
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
1.40M
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
3.61M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
3.61M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
1.58M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
1.58M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
2.97M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
2.97M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
2.97M
      (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
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1126
0
    int i;
1127
0
    char shift[100];
1128
1129
0
    for (i = 0;((i < depth) && (i < 25));i++)
1130
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1131
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1132
0
    if (cur == NULL) {
1133
0
  fprintf(output, "%s", shift);
1134
0
  fprintf(output, "Node is NULL !\n");
1135
0
  return;
1136
1137
0
    }
1138
1139
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1140
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1141
0
  fprintf(output, "%s", shift);
1142
0
  fprintf(output, " /\n");
1143
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1144
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1145
0
    else
1146
0
  xmlDebugDumpOneNode(output, cur, depth);
1147
0
}
1148
static void
1149
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1150
0
    xmlNodePtr tmp;
1151
0
    int i;
1152
0
    char shift[100];
1153
1154
0
    for (i = 0;((i < depth) && (i < 25));i++)
1155
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1156
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1157
0
    if (cur == NULL) {
1158
0
  fprintf(output, "%s", shift);
1159
0
  fprintf(output, "Node is NULL !\n");
1160
0
  return;
1161
1162
0
    }
1163
1164
0
    while (cur != NULL) {
1165
0
  tmp = cur;
1166
0
  cur = cur->next;
1167
0
  xmlDebugDumpOneNode(output, tmp, depth);
1168
0
    }
1169
0
}
1170
1171
static void
1172
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1173
0
    int i;
1174
0
    char shift[100];
1175
1176
0
    for (i = 0;((i < depth) && (i < 25));i++)
1177
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1178
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1179
1180
0
    if (cur == NULL) {
1181
0
  fprintf(output, "%s", shift);
1182
0
  fprintf(output, "NodeSet is NULL !\n");
1183
0
  return;
1184
1185
0
    }
1186
1187
0
    if (cur != NULL) {
1188
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1189
0
  for (i = 0;i < cur->nodeNr;i++) {
1190
0
      fprintf(output, "%s", shift);
1191
0
      fprintf(output, "%d", i + 1);
1192
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1193
0
  }
1194
0
    }
1195
0
}
1196
1197
static void
1198
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1199
0
    int i;
1200
0
    char shift[100];
1201
1202
0
    for (i = 0;((i < depth) && (i < 25));i++)
1203
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1204
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1205
1206
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1207
0
  fprintf(output, "%s", shift);
1208
0
  fprintf(output, "Value Tree is NULL !\n");
1209
0
  return;
1210
1211
0
    }
1212
1213
0
    fprintf(output, "%s", shift);
1214
0
    fprintf(output, "%d", i + 1);
1215
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1216
0
}
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
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObject *cur, int depth) {
1227
0
    int i;
1228
0
    char shift[100];
1229
1230
0
    if (output == NULL) return;
1231
1232
0
    for (i = 0;((i < depth) && (i < 25));i++)
1233
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1234
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1235
1236
1237
0
    fprintf(output, "%s", shift);
1238
1239
0
    if (cur == NULL) {
1240
0
        fprintf(output, "Object is empty (NULL)\n");
1241
0
  return;
1242
0
    }
1243
0
    switch(cur->type) {
1244
0
        case XPATH_UNDEFINED:
1245
0
      fprintf(output, "Object is uninitialized\n");
1246
0
      break;
1247
0
        case XPATH_NODESET:
1248
0
      fprintf(output, "Object is a Node Set :\n");
1249
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250
0
      break;
1251
0
  case XPATH_XSLT_TREE:
1252
0
      fprintf(output, "Object is an XSLT value tree :\n");
1253
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254
0
      break;
1255
0
        case XPATH_BOOLEAN:
1256
0
      fprintf(output, "Object is a Boolean : ");
1257
0
      if (cur->boolval) fprintf(output, "true\n");
1258
0
      else fprintf(output, "false\n");
1259
0
      break;
1260
0
        case XPATH_NUMBER:
1261
0
      switch (xmlXPathIsInf(cur->floatval)) {
1262
0
      case 1:
1263
0
    fprintf(output, "Object is a number : Infinity\n");
1264
0
    break;
1265
0
      case -1:
1266
0
    fprintf(output, "Object is a number : -Infinity\n");
1267
0
    break;
1268
0
      default:
1269
0
    if (xmlXPathIsNaN(cur->floatval)) {
1270
0
        fprintf(output, "Object is a number : NaN\n");
1271
0
    } else if (cur->floatval == 0) {
1272
                    /* Omit sign for negative zero. */
1273
0
        fprintf(output, "Object is a number : 0\n");
1274
0
    } else {
1275
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276
0
    }
1277
0
      }
1278
0
      break;
1279
0
        case XPATH_STRING:
1280
0
      fprintf(output, "Object is a string : ");
1281
0
      xmlDebugDumpString(output, cur->stringval);
1282
0
      fprintf(output, "\n");
1283
0
      break;
1284
0
  case XPATH_USERS:
1285
0
      fprintf(output, "Object is user defined\n");
1286
0
      break;
1287
0
    }
1288
0
}
1289
1290
static void
1291
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1292
0
                       xmlXPathStepOpPtr op, int depth) {
1293
0
    int i;
1294
0
    char shift[100];
1295
1296
0
    for (i = 0;((i < depth) && (i < 25));i++)
1297
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1298
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300
0
    fprintf(output, "%s", shift);
1301
0
    if (op == NULL) {
1302
0
  fprintf(output, "Step is NULL\n");
1303
0
  return;
1304
0
    }
1305
0
    switch (op->op) {
1306
0
        case XPATH_OP_END:
1307
0
      fprintf(output, "END"); break;
1308
0
        case XPATH_OP_AND:
1309
0
      fprintf(output, "AND"); break;
1310
0
        case XPATH_OP_OR:
1311
0
      fprintf(output, "OR"); break;
1312
0
        case XPATH_OP_EQUAL:
1313
0
       if (op->value)
1314
0
     fprintf(output, "EQUAL =");
1315
0
       else
1316
0
     fprintf(output, "EQUAL !=");
1317
0
       break;
1318
0
        case XPATH_OP_CMP:
1319
0
       if (op->value)
1320
0
     fprintf(output, "CMP <");
1321
0
       else
1322
0
     fprintf(output, "CMP >");
1323
0
       if (!op->value2)
1324
0
     fprintf(output, "=");
1325
0
       break;
1326
0
        case XPATH_OP_PLUS:
1327
0
       if (op->value == 0)
1328
0
     fprintf(output, "PLUS -");
1329
0
       else if (op->value == 1)
1330
0
     fprintf(output, "PLUS +");
1331
0
       else if (op->value == 2)
1332
0
     fprintf(output, "PLUS unary -");
1333
0
       else if (op->value == 3)
1334
0
     fprintf(output, "PLUS unary - -");
1335
0
       break;
1336
0
        case XPATH_OP_MULT:
1337
0
       if (op->value == 0)
1338
0
     fprintf(output, "MULT *");
1339
0
       else if (op->value == 1)
1340
0
     fprintf(output, "MULT div");
1341
0
       else
1342
0
     fprintf(output, "MULT mod");
1343
0
       break;
1344
0
        case XPATH_OP_UNION:
1345
0
       fprintf(output, "UNION"); break;
1346
0
        case XPATH_OP_ROOT:
1347
0
       fprintf(output, "ROOT"); break;
1348
0
        case XPATH_OP_NODE:
1349
0
       fprintf(output, "NODE"); break;
1350
0
        case XPATH_OP_SORT:
1351
0
       fprintf(output, "SORT"); break;
1352
0
        case XPATH_OP_COLLECT: {
1353
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1354
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1355
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1356
0
      const xmlChar *prefix = op->value4;
1357
0
      const xmlChar *name = op->value5;
1358
1359
0
      fprintf(output, "COLLECT ");
1360
0
      switch (axis) {
1361
0
    case AXIS_ANCESTOR:
1362
0
        fprintf(output, " 'ancestors' "); break;
1363
0
    case AXIS_ANCESTOR_OR_SELF:
1364
0
        fprintf(output, " 'ancestors-or-self' "); break;
1365
0
    case AXIS_ATTRIBUTE:
1366
0
        fprintf(output, " 'attributes' "); break;
1367
0
    case AXIS_CHILD:
1368
0
        fprintf(output, " 'child' "); break;
1369
0
    case AXIS_DESCENDANT:
1370
0
        fprintf(output, " 'descendant' "); break;
1371
0
    case AXIS_DESCENDANT_OR_SELF:
1372
0
        fprintf(output, " 'descendant-or-self' "); break;
1373
0
    case AXIS_FOLLOWING:
1374
0
        fprintf(output, " 'following' "); break;
1375
0
    case AXIS_FOLLOWING_SIBLING:
1376
0
        fprintf(output, " 'following-siblings' "); break;
1377
0
    case AXIS_NAMESPACE:
1378
0
        fprintf(output, " 'namespace' "); break;
1379
0
    case AXIS_PARENT:
1380
0
        fprintf(output, " 'parent' "); break;
1381
0
    case AXIS_PRECEDING:
1382
0
        fprintf(output, " 'preceding' "); break;
1383
0
    case AXIS_PRECEDING_SIBLING:
1384
0
        fprintf(output, " 'preceding-sibling' "); break;
1385
0
    case AXIS_SELF:
1386
0
        fprintf(output, " 'self' "); break;
1387
0
      }
1388
0
      switch (test) {
1389
0
                case NODE_TEST_NONE:
1390
0
        fprintf(output, "'none' "); break;
1391
0
                case NODE_TEST_TYPE:
1392
0
        fprintf(output, "'type' "); break;
1393
0
                case NODE_TEST_PI:
1394
0
        fprintf(output, "'PI' "); break;
1395
0
                case NODE_TEST_ALL:
1396
0
        fprintf(output, "'all' "); break;
1397
0
                case NODE_TEST_NS:
1398
0
        fprintf(output, "'namespace' "); break;
1399
0
                case NODE_TEST_NAME:
1400
0
        fprintf(output, "'name' "); break;
1401
0
      }
1402
0
      switch (type) {
1403
0
                case NODE_TYPE_NODE:
1404
0
        fprintf(output, "'node' "); break;
1405
0
                case NODE_TYPE_COMMENT:
1406
0
        fprintf(output, "'comment' "); break;
1407
0
                case NODE_TYPE_TEXT:
1408
0
        fprintf(output, "'text' "); break;
1409
0
                case NODE_TYPE_PI:
1410
0
        fprintf(output, "'PI' "); break;
1411
0
      }
1412
0
      if (prefix != NULL)
1413
0
    fprintf(output, "%s:", prefix);
1414
0
      if (name != NULL)
1415
0
    fprintf(output, "%s", (const char *) name);
1416
0
      break;
1417
1418
0
        }
1419
0
  case XPATH_OP_VALUE: {
1420
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1421
1422
0
      fprintf(output, "ELEM ");
1423
0
      xmlXPathDebugDumpObject(output, object, 0);
1424
0
      goto finish;
1425
0
  }
1426
0
  case XPATH_OP_VARIABLE: {
1427
0
      const xmlChar *prefix = op->value5;
1428
0
      const xmlChar *name = op->value4;
1429
1430
0
      if (prefix != NULL)
1431
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1432
0
      else
1433
0
    fprintf(output, "VARIABLE %s", name);
1434
0
      break;
1435
0
  }
1436
0
  case XPATH_OP_FUNCTION: {
1437
0
      int nbargs = op->value;
1438
0
      const xmlChar *prefix = op->value5;
1439
0
      const xmlChar *name = op->value4;
1440
1441
0
      if (prefix != NULL)
1442
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1443
0
      prefix, name, nbargs);
1444
0
      else
1445
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1446
0
      break;
1447
0
  }
1448
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1449
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1450
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1451
0
  default:
1452
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1453
0
    }
1454
0
    fprintf(output, "\n");
1455
0
finish:
1456
    /* OP_VALUE has invalid ch1. */
1457
0
    if (op->op == XPATH_OP_VALUE)
1458
0
        return;
1459
1460
0
    if (op->ch1 >= 0)
1461
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1462
0
    if (op->ch2 >= 0)
1463
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1464
0
}
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
0
                    int depth) {
1476
0
    int i;
1477
0
    char shift[100];
1478
1479
0
    if ((output == NULL) || (comp == NULL)) return;
1480
1481
0
    for (i = 0;((i < depth) && (i < 25));i++)
1482
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1483
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1484
1485
0
    fprintf(output, "%s", shift);
1486
1487
#ifdef XPATH_STREAMING
1488
    if (comp->stream) {
1489
        fprintf(output, "Streaming Expression\n");
1490
    } else
1491
#endif
1492
0
    {
1493
0
        fprintf(output, "Compiled Expression : %d elements\n",
1494
0
                comp->nbStep);
1495
0
        i = comp->last;
1496
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1497
0
    }
1498
0
}
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
44.4k
{
1516
44.4k
    xmlXPathContextCachePtr ret;
1517
1518
44.4k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
44.4k
    if (ret == NULL)
1520
5
  return(NULL);
1521
44.4k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
44.4k
    ret->maxNodeset = 100;
1523
44.4k
    ret->maxMisc = 100;
1524
44.4k
    return(ret);
1525
44.4k
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
19.4k
{
1530
475k
    while (list != NULL) {
1531
455k
        xmlXPathObjectPtr next;
1532
1533
455k
        next = (void *) list->stringval;
1534
1535
455k
  if (list->nodesetval != NULL) {
1536
390k
      if (list->nodesetval->nodeTab != NULL)
1537
346k
    xmlFree(list->nodesetval->nodeTab);
1538
390k
      xmlFree(list->nodesetval);
1539
390k
  }
1540
455k
  xmlFree(list);
1541
1542
455k
        list = next;
1543
455k
    }
1544
19.4k
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
44.4k
{
1549
44.4k
    if (cache == NULL)
1550
0
  return;
1551
44.4k
    if (cache->nodesetObjs)
1552
13.0k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
44.4k
    if (cache->miscObjs)
1554
6.33k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
44.4k
    xmlFree(cache);
1556
44.4k
}
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
44.4k
{
1582
44.4k
    if (ctxt == NULL)
1583
0
  return(-1);
1584
44.4k
    if (active) {
1585
44.4k
  xmlXPathContextCachePtr cache;
1586
1587
44.4k
  if (ctxt->cache == NULL) {
1588
44.4k
      ctxt->cache = xmlXPathNewCache();
1589
44.4k
      if (ctxt->cache == NULL) {
1590
5
                xmlXPathErrMemory(ctxt);
1591
5
    return(-1);
1592
5
            }
1593
44.4k
  }
1594
44.4k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
44.4k
  if (options == 0) {
1596
44.4k
      if (value < 0)
1597
44.4k
    value = 100;
1598
44.4k
      cache->maxNodeset = value;
1599
44.4k
      cache->maxMisc = value;
1600
44.4k
  }
1601
44.4k
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
44.4k
    return(0);
1606
44.4k
}
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
6.96M
{
1621
6.96M
    xmlXPathObjectPtr ret;
1622
6.96M
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
6.96M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
6.94M
  xmlXPathContextCachePtr cache =
1626
6.94M
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
6.94M
  if (cache->miscObjs != NULL) {
1629
4.26M
      ret = cache->miscObjs;
1630
4.26M
            cache->miscObjs = (void *) ret->stringval;
1631
4.26M
            cache->numMisc -= 1;
1632
4.26M
            ret->stringval = NULL;
1633
4.26M
      ret->type = XPATH_NODESET;
1634
4.26M
      ret->nodesetval = val;
1635
4.26M
      return(ret);
1636
4.26M
  }
1637
6.94M
    }
1638
1639
2.70M
    ret = xmlXPathWrapNodeSet(val);
1640
2.70M
    if (ret == NULL)
1641
2.51k
        xmlXPathPErrMemory(pctxt);
1642
2.70M
    return(ret);
1643
6.96M
}
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
1.82M
{
1656
1.82M
    xmlXPathObjectPtr ret;
1657
1.82M
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
1.82M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
1.82M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
1.82M
  if (cache->miscObjs != NULL) {
1663
1.77M
      ret = cache->miscObjs;
1664
1.77M
            cache->miscObjs = (void *) ret->stringval;
1665
1.77M
            cache->numMisc -= 1;
1666
1.77M
      ret->type = XPATH_STRING;
1667
1.77M
      ret->stringval = val;
1668
1.77M
      return(ret);
1669
1.77M
  }
1670
1.82M
    }
1671
1672
51.8k
    ret = xmlXPathWrapString(val);
1673
51.8k
    if (ret == NULL)
1674
792
        xmlXPathPErrMemory(pctxt);
1675
51.8k
    return(ret);
1676
1.82M
}
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
8.84M
{
1690
8.84M
    xmlXPathObjectPtr ret;
1691
8.84M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
8.84M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
8.82M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
8.82M
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
8.62M
      ret = cache->nodesetObjs;
1701
8.62M
            cache->nodesetObjs = (void *) ret->stringval;
1702
8.62M
            cache->numNodeset -= 1;
1703
8.62M
            ret->stringval = NULL;
1704
8.62M
      ret->type = XPATH_NODESET;
1705
8.62M
      ret->boolval = 0;
1706
8.62M
      if (val) {
1707
8.62M
    if ((ret->nodesetval->nodeMax == 0) ||
1708
8.62M
        (val->type == XML_NAMESPACE_DECL))
1709
633k
    {
1710
633k
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
1.14k
                        xmlXPathPErrMemory(pctxt);
1712
7.99M
    } else {
1713
7.99M
        ret->nodesetval->nodeTab[0] = val;
1714
7.99M
        ret->nodesetval->nodeNr = 1;
1715
7.99M
    }
1716
8.62M
      }
1717
8.62M
      return(ret);
1718
8.62M
  } else if (cache->miscObjs != NULL) {
1719
31.6k
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
31.6k
      set = xmlXPathNodeSetCreate(val);
1725
31.6k
      if (set == NULL) {
1726
86
                xmlXPathPErrMemory(pctxt);
1727
86
    return(NULL);
1728
86
      }
1729
1730
31.5k
      ret = cache->miscObjs;
1731
31.5k
            cache->miscObjs = (void *) ret->stringval;
1732
31.5k
            cache->numMisc -= 1;
1733
31.5k
            ret->stringval = NULL;
1734
31.5k
      ret->type = XPATH_NODESET;
1735
31.5k
      ret->boolval = 0;
1736
31.5k
      ret->nodesetval = set;
1737
31.5k
      return(ret);
1738
31.6k
  }
1739
8.82M
    }
1740
184k
    ret = xmlXPathNewNodeSet(val);
1741
184k
    if (ret == NULL)
1742
261
        xmlXPathPErrMemory(pctxt);
1743
184k
    return(ret);
1744
8.84M
}
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
738k
{
1757
738k
    xmlXPathObjectPtr ret;
1758
738k
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
738k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
738k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
738k
  if (cache->miscObjs != NULL) {
1764
580k
            xmlChar *copy;
1765
1766
580k
            if (val == NULL)
1767
176
                val = BAD_CAST "";
1768
580k
            copy = xmlStrdup(val);
1769
580k
            if (copy == NULL) {
1770
156
                xmlXPathPErrMemory(pctxt);
1771
156
                return(NULL);
1772
156
            }
1773
1774
580k
      ret = cache->miscObjs;
1775
580k
            cache->miscObjs = (void *) ret->stringval;
1776
580k
            cache->numMisc -= 1;
1777
580k
      ret->type = XPATH_STRING;
1778
580k
            ret->stringval = copy;
1779
580k
      return(ret);
1780
580k
  }
1781
738k
    }
1782
1783
157k
    ret = xmlXPathNewString(val);
1784
157k
    if (ret == NULL)
1785
221
        xmlXPathPErrMemory(pctxt);
1786
157k
    return(ret);
1787
738k
}
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
51.7k
{
1800
51.7k
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
51.7k
}
1802
1803
/**
1804
 * This is the cached version of #xmlXPathNewBoolean.
1805
 * Acquires an xmlXPathObject of type boolean and of value `val`
1806
 *
1807
 * @param pctxt  the XPath context
1808
 * @param val  the boolean value
1809
 * @returns the created or reused object.
1810
 */
1811
static xmlXPathObjectPtr
1812
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1813
1.61M
{
1814
1.61M
    xmlXPathObjectPtr ret;
1815
1.61M
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
1.61M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
1.60M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
1.60M
  if (cache->miscObjs != NULL) {
1821
1.38M
      ret = cache->miscObjs;
1822
1.38M
            cache->miscObjs = (void *) ret->stringval;
1823
1.38M
            cache->numMisc -= 1;
1824
1.38M
            ret->stringval = NULL;
1825
1.38M
      ret->type = XPATH_BOOLEAN;
1826
1.38M
      ret->boolval = (val != 0);
1827
1.38M
      return(ret);
1828
1.38M
  }
1829
1.60M
    }
1830
1831
231k
    ret = xmlXPathNewBoolean(val);
1832
231k
    if (ret == NULL)
1833
1.39k
        xmlXPathPErrMemory(pctxt);
1834
231k
    return(ret);
1835
1.61M
}
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.99M
{
1848
2.99M
    xmlXPathObjectPtr ret;
1849
2.99M
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
2.99M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
2.98M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
2.98M
  if (cache->miscObjs != NULL) {
1855
2.40M
      ret = cache->miscObjs;
1856
2.40M
            cache->miscObjs = (void *) ret->stringval;
1857
2.40M
            cache->numMisc -= 1;
1858
2.40M
            ret->stringval = NULL;
1859
2.40M
      ret->type = XPATH_NUMBER;
1860
2.40M
      ret->floatval = val;
1861
2.40M
      return(ret);
1862
2.40M
  }
1863
2.98M
    }
1864
1865
587k
    ret = xmlXPathNewFloat(val);
1866
587k
    if (ret == NULL)
1867
1.64k
        xmlXPathPErrMemory(pctxt);
1868
587k
    return(ret);
1869
2.99M
}
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.24M
{
1882
1.24M
    xmlXPathObjectPtr ret;
1883
1.24M
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
1.24M
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
1.24M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
1.23M
  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
193k
      case XPATH_STRING:
1901
193k
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
1.04M
      case XPATH_NUMBER:
1905
1.04M
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
1.23M
  }
1909
1.23M
    }
1910
6.17k
    ret = xmlXPathObjectCopy(val);
1911
6.17k
    if (ret == NULL)
1912
2
        xmlXPathPErrMemory(pctxt);
1913
6.17k
    return(ret);
1914
1.24M
}
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
2.38M
                             xmlXPathObjectPtr val) {
1932
2.38M
    double ret = 0.0;
1933
1934
2.38M
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
2.38M
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
1.34M
    case XPATH_NODESET:
1941
1.34M
    case XPATH_XSLT_TREE: {
1942
1.34M
        xmlChar *str;
1943
1944
1.34M
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
1.34M
        if (str == NULL) {
1946
2.21k
            xmlXPathPErrMemory(ctxt);
1947
2.21k
            ret = xmlXPathNAN;
1948
1.34M
        } else {
1949
1.34M
      ret = xmlXPathCastStringToNumber(str);
1950
1.34M
            xmlFree(str);
1951
1.34M
        }
1952
1.34M
  break;
1953
1.34M
    }
1954
731k
    case XPATH_STRING:
1955
731k
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
731k
  break;
1957
220k
    case XPATH_NUMBER:
1958
220k
  ret = val->floatval;
1959
220k
  break;
1960
92.2k
    case XPATH_BOOLEAN:
1961
92.2k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
92.2k
  break;
1963
496
    case XPATH_USERS:
1964
  /* TODO */
1965
496
  ret = xmlXPathNAN;
1966
496
  break;
1967
2.38M
    }
1968
2.38M
    return(ret);
1969
2.38M
}
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
33.5M
{
1980
33.5M
    xmlXPathObjectPtr ret;
1981
1982
33.5M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
8.87k
        return (NULL);
1984
1985
33.5M
    ctxt->valueNr--;
1986
33.5M
    if (ctxt->valueNr > 0)
1987
17.3M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
16.1M
    else
1989
16.1M
        ctxt->value = NULL;
1990
33.5M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
33.5M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
33.5M
    return (ret);
1993
33.5M
}
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
34.1M
{
2008
34.1M
    if (ctxt == NULL) return(-1);
2009
34.1M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
12.1k
        xmlXPathPErrMemory(ctxt);
2014
12.1k
        return(-1);
2015
12.1k
    }
2016
34.1M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
2.44M
        xmlXPathObjectPtr *tmp;
2018
2.44M
        int newSize;
2019
2020
2.44M
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
2.44M
                                  10, XPATH_MAX_STACK_DEPTH);
2022
2.44M
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
2.44M
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
2.44M
        if (tmp == NULL) {
2029
419
            xmlXPathPErrMemory(ctxt);
2030
419
            xmlXPathFreeObject(value);
2031
419
            return (-1);
2032
419
        }
2033
2.44M
  ctxt->valueTab = tmp;
2034
2.44M
        ctxt->valueMax = newSize;
2035
2.44M
    }
2036
34.1M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
34.1M
    ctxt->value = value;
2038
34.1M
    return (ctxt->valueNr++);
2039
34.1M
}
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
2.18k
xmlXPathPopBoolean (xmlXPathParserContext *ctxt) {
2050
2.18k
    xmlXPathObjectPtr obj;
2051
2.18k
    int ret;
2052
2053
2.18k
    obj = xmlXPathValuePop(ctxt);
2054
2.18k
    if (obj == NULL) {
2055
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2056
0
  return(0);
2057
0
    }
2058
2.18k
    if (obj->type != XPATH_BOOLEAN)
2059
1.52k
  ret = xmlXPathCastToBoolean(obj);
2060
661
    else
2061
661
        ret = obj->boolval;
2062
2.18k
    xmlXPathReleaseObject(ctxt->context, obj);
2063
2.18k
    return(ret);
2064
2.18k
}
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
8.59k
xmlXPathPopNumber (xmlXPathParserContext *ctxt) {
2075
8.59k
    xmlXPathObjectPtr obj;
2076
8.59k
    double ret;
2077
2078
8.59k
    obj = xmlXPathValuePop(ctxt);
2079
8.59k
    if (obj == NULL) {
2080
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2081
0
  return(0);
2082
0
    }
2083
8.59k
    if (obj->type != XPATH_NUMBER)
2084
7.29k
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2085
1.30k
    else
2086
1.30k
        ret = obj->floatval;
2087
8.59k
    xmlXPathReleaseObject(ctxt->context, obj);
2088
8.59k
    return(ret);
2089
8.59k
}
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
1.15M
xmlXPathPopString (xmlXPathParserContext *ctxt) {
2100
1.15M
    xmlXPathObjectPtr obj;
2101
1.15M
    xmlChar * ret;
2102
2103
1.15M
    obj = xmlXPathValuePop(ctxt);
2104
1.15M
    if (obj == NULL) {
2105
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2106
0
  return(NULL);
2107
0
    }
2108
1.15M
    ret = xmlXPathCastToString(obj);
2109
1.15M
    if (ret == NULL)
2110
237
        xmlXPathPErrMemory(ctxt);
2111
1.15M
    xmlXPathReleaseObject(ctxt->context, obj);
2112
1.15M
    return(ret);
2113
1.15M
}
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
918k
xmlXPathPopNodeSet (xmlXPathParserContext *ctxt) {
2124
918k
    xmlXPathObjectPtr obj;
2125
918k
    xmlNodeSetPtr ret;
2126
2127
918k
    if (ctxt == NULL) return(NULL);
2128
918k
    if (ctxt->value == NULL) {
2129
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2130
0
  return(NULL);
2131
0
    }
2132
918k
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2133
5.63k
  xmlXPathSetTypeError(ctxt);
2134
5.63k
  return(NULL);
2135
5.63k
    }
2136
912k
    obj = xmlXPathValuePop(ctxt);
2137
912k
    ret = obj->nodesetval;
2138
912k
    obj->nodesetval = NULL;
2139
912k
    xmlXPathReleaseObject(ctxt->context, obj);
2140
912k
    return(ret);
2141
918k
}
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
2.26k
xmlXPathPopExternal (xmlXPathParserContext *ctxt) {
2152
2.26k
    xmlXPathObjectPtr obj;
2153
2.26k
    void * ret;
2154
2155
2.26k
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2156
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2157
0
  return(NULL);
2158
0
    }
2159
2.26k
    if (ctxt->value->type != XPATH_USERS) {
2160
0
  xmlXPathSetTypeError(ctxt);
2161
0
  return(NULL);
2162
0
    }
2163
2.26k
    obj = xmlXPathValuePop(ctxt);
2164
2.26k
    ret = obj->user;
2165
2.26k
    obj->user = NULL;
2166
2.26k
    xmlXPathReleaseObject(ctxt->context, obj);
2167
2.26k
    return(ret);
2168
2.26k
}
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
123M
#define CUR (*ctxt->cur)
2194
624k
#define SKIP(val) ctxt->cur += (val)
2195
14.3M
#define NXT(val) ctxt->cur[(val)]
2196
4.56M
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
60.0M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
51.4M
#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
55.2k
#define UPPER_DOUBLE 1E9
2213
23.8k
#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
34.9k
#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
259k
{
2230
259k
    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
259k
    default:
2240
259k
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
259k
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
259k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
259k
                   (number == (int) number)) {
2248
204k
      char work[30];
2249
204k
      char *ptr, *cur;
2250
204k
      int value = (int) number;
2251
2252
204k
            ptr = &buffer[0];
2253
204k
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
204k
      } else {
2256
204k
    snprintf(work, 29, "%d", value);
2257
204k
    cur = &work[0];
2258
579k
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
375k
        *ptr++ = *cur++;
2260
375k
    }
2261
204k
      }
2262
204k
      if (ptr - buffer < buffersize) {
2263
204k
    *ptr = 0;
2264
204k
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
204k
  } 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
55.2k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
55.2k
      int integer_place, fraction_place;
2280
55.2k
      char *ptr;
2281
55.2k
      char *after_fraction;
2282
55.2k
      double absolute_value;
2283
55.2k
      int size;
2284
2285
55.2k
      absolute_value = fabs(number);
2286
2287
      /*
2288
       * First choose format - scientific or regular floating point.
2289
       * In either case, result is in work, and after_fraction points
2290
       * just past the fractional part.
2291
      */
2292
55.2k
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
55.2k
      (absolute_value < LOWER_DOUBLE)) &&
2294
55.2k
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
34.9k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
34.9k
    fraction_place = DBL_DIG - 1;
2298
34.9k
    size = snprintf(work, sizeof(work),"%*.*e",
2299
34.9k
       integer_place, fraction_place, number);
2300
174k
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
34.9k
      }
2303
20.2k
      else {
2304
    /* Use regular notation */
2305
20.2k
    if (absolute_value > 0.0) {
2306
20.2k
        integer_place = (int)log10(absolute_value);
2307
20.2k
        if (integer_place > 0)
2308
3.49k
            fraction_place = DBL_DIG - integer_place - 1;
2309
16.7k
        else
2310
16.7k
            fraction_place = DBL_DIG - integer_place;
2311
20.2k
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
20.2k
    size = snprintf(work, sizeof(work), "%0.*f",
2315
20.2k
        fraction_place, number);
2316
20.2k
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
86.7k
      while (work[0] == ' ') {
2320
661k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
31.5k
    size--;
2322
31.5k
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
55.2k
      after_fraction = work + size;
2326
55.2k
      ptr = after_fraction;
2327
330k
      while (*(--ptr) == '0')
2328
275k
    ;
2329
55.2k
      if (*ptr != '.')
2330
52.8k
          ptr++;
2331
194k
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
55.2k
      size = strlen(work) + 1;
2335
55.2k
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
55.2k
      memmove(buffer, work, size);
2340
55.2k
  }
2341
259k
  break;
2342
259k
    }
2343
259k
}
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
17.5k
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
17.5k
    XML_INTPTR_T count = 0;
2366
17.5k
    xmlNodePtr cur;
2367
2368
17.5k
    if (doc == NULL)
2369
0
  return(-1);
2370
17.5k
    cur = doc->children;
2371
3.35M
    while (cur != NULL) {
2372
3.33M
  if (cur->type == XML_ELEMENT_NODE) {
2373
2.82M
            count += 1;
2374
2.82M
            cur->content = XML_INT_TO_PTR(-count);
2375
2.82M
      if (cur->children != NULL) {
2376
169k
    cur = cur->children;
2377
169k
    continue;
2378
169k
      }
2379
2.82M
  }
2380
3.16M
  if (cur->next != NULL) {
2381
3.06M
      cur = cur->next;
2382
3.06M
      continue;
2383
3.06M
  }
2384
186k
  do {
2385
186k
      cur = cur->parent;
2386
186k
      if (cur == NULL)
2387
0
    break;
2388
186k
      if (cur == (xmlNodePtr) doc) {
2389
17.5k
    cur = NULL;
2390
17.5k
    break;
2391
17.5k
      }
2392
169k
      if (cur->next != NULL) {
2393
85.4k
    cur = cur->next;
2394
85.4k
    break;
2395
85.4k
      }
2396
169k
  } while (cur != NULL);
2397
102k
    }
2398
17.5k
    return(count);
2399
17.5k
}
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
37.1k
xmlXPathCmpNodes(xmlNode *node1, xmlNode *node2) {
2411
37.1k
    int depth1, depth2;
2412
37.1k
    int attr1 = 0, attr2 = 0;
2413
37.1k
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2414
37.1k
    xmlNodePtr cur, root;
2415
2416
37.1k
    if ((node1 == NULL) || (node2 == NULL))
2417
0
  return(-2);
2418
    /*
2419
     * a couple of optimizations which will avoid computations in most cases
2420
     */
2421
37.1k
    if (node1 == node2)    /* trivial case */
2422
0
  return(0);
2423
37.1k
    if (node1->type == XML_ATTRIBUTE_NODE) {
2424
93
  attr1 = 1;
2425
93
  attrNode1 = node1;
2426
93
  node1 = node1->parent;
2427
93
    }
2428
37.1k
    if (node2->type == XML_ATTRIBUTE_NODE) {
2429
80
  attr2 = 1;
2430
80
  attrNode2 = node2;
2431
80
  node2 = node2->parent;
2432
80
    }
2433
37.1k
    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
37.1k
    if ((node1->type == XML_NAMESPACE_DECL) ||
2452
37.1k
        (node2->type == XML_NAMESPACE_DECL))
2453
1.47k
  return(1);
2454
35.7k
    if (node1 == node2->prev)
2455
593
  return(1);
2456
35.1k
    if (node1 == node2->next)
2457
0
  return(-1);
2458
2459
    /*
2460
     * Speedup using document order if available.
2461
     */
2462
35.1k
    if ((node1->type == XML_ELEMENT_NODE) &&
2463
35.1k
  (node2->type == XML_ELEMENT_NODE) &&
2464
35.1k
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2465
35.1k
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2466
35.1k
  (node1->doc == node2->doc)) {
2467
1.39k
  XML_INTPTR_T l1, l2;
2468
2469
1.39k
  l1 = -XML_NODE_SORT_VALUE(node1);
2470
1.39k
  l2 = -XML_NODE_SORT_VALUE(node2);
2471
1.39k
  if (l1 < l2)
2472
1.35k
      return(1);
2473
35
  if (l1 > l2)
2474
35
      return(-1);
2475
35
    }
2476
2477
    /*
2478
     * compute depth to root
2479
     */
2480
142k
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2481
111k
  if (cur->parent == node1)
2482
2.60k
      return(1);
2483
109k
  depth2++;
2484
109k
    }
2485
31.1k
    root = cur;
2486
70.8k
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2487
39.7k
  if (cur->parent == node2)
2488
102
      return(-1);
2489
39.6k
  depth1++;
2490
39.6k
    }
2491
    /*
2492
     * Distinct document (or distinct entities :-( ) case.
2493
     */
2494
31.0k
    if (root != cur) {
2495
18.5k
  return(-2);
2496
18.5k
    }
2497
    /*
2498
     * get the nearest common ancestor.
2499
     */
2500
13.6k
    while (depth1 > depth2) {
2501
1.18k
  depth1--;
2502
1.18k
  node1 = node1->parent;
2503
1.18k
    }
2504
45.3k
    while (depth2 > depth1) {
2505
32.8k
  depth2--;
2506
32.8k
  node2 = node2->parent;
2507
32.8k
    }
2508
14.2k
    while (node1->parent != node2->parent) {
2509
1.77k
  node1 = node1->parent;
2510
1.77k
  node2 = node2->parent;
2511
  /* should not happen but just in case ... */
2512
1.77k
  if ((node1 == NULL) || (node2 == NULL))
2513
0
      return(-2);
2514
1.77k
    }
2515
    /*
2516
     * Find who's first.
2517
     */
2518
12.4k
    if (node1 == node2->prev)
2519
9.10k
  return(1);
2520
3.34k
    if (node1 == node2->next)
2521
359
  return(-1);
2522
    /*
2523
     * Speedup using document order if available.
2524
     */
2525
2.98k
    if ((node1->type == XML_ELEMENT_NODE) &&
2526
2.98k
  (node2->type == XML_ELEMENT_NODE) &&
2527
2.98k
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2528
2.98k
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2529
2.98k
  (node1->doc == node2->doc)) {
2530
1.90k
  XML_INTPTR_T l1, l2;
2531
2532
1.90k
  l1 = -XML_NODE_SORT_VALUE(node1);
2533
1.90k
  l2 = -XML_NODE_SORT_VALUE(node2);
2534
1.90k
  if (l1 < l2)
2535
1.82k
      return(1);
2536
73
  if (l1 > l2)
2537
73
      return(-1);
2538
73
    }
2539
2540
4.71k
    for (cur = node1->next;cur != NULL;cur = cur->next)
2541
4.67k
  if (cur == node2)
2542
1.04k
      return(1);
2543
44
    return(-1); /* assume there is no sibling list corruption */
2544
1.08k
}
2545
2546
/**
2547
 * Sort the node set in document order
2548
 *
2549
 * @param set  the node set
2550
 */
2551
void
2552
1.38M
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
1.38M
    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
1.38M
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
1.38M
#endif /* WITH_TIM_SORT */
2591
1.38M
}
2592
2593
26.2M
#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
2.64M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
2.64M
    xmlNsPtr cur;
2606
2607
2.64M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
2.64M
    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
2.64M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
2.64M
    if (cur == NULL)
2617
442
  return(NULL);
2618
2.64M
    memset(cur, 0, sizeof(xmlNs));
2619
2.64M
    cur->type = XML_NAMESPACE_DECL;
2620
2.64M
    if (ns->href != NULL) {
2621
2.64M
  cur->href = xmlStrdup(ns->href);
2622
2.64M
        if (cur->href == NULL) {
2623
66
            xmlFree(cur);
2624
66
            return(NULL);
2625
66
        }
2626
2.64M
    }
2627
2.64M
    if (ns->prefix != NULL) {
2628
2.48M
  cur->prefix = xmlStrdup(ns->prefix);
2629
2.48M
        if (cur->prefix == NULL) {
2630
73
            xmlFree((xmlChar *) cur->href);
2631
73
            xmlFree(cur);
2632
73
            return(NULL);
2633
73
        }
2634
2.48M
    }
2635
2.64M
    cur->next = (xmlNsPtr) node;
2636
2.64M
    return((xmlNodePtr) cur);
2637
2.64M
}
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
2.64M
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
2.64M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
2.64M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
2.64M
  if (ns->href != NULL)
2653
2.64M
      xmlFree((xmlChar *)ns->href);
2654
2.64M
  if (ns->prefix != NULL)
2655
2.48M
      xmlFree((xmlChar *)ns->prefix);
2656
2.64M
  xmlFree(ns);
2657
2.64M
    }
2658
2.64M
}
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
13.9M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
13.9M
    xmlNodeSetPtr ret;
2669
2670
13.9M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
13.9M
    if (ret == NULL)
2672
3.77k
  return(NULL);
2673
13.9M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
13.9M
    if (val != NULL) {
2675
3.16M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
3.16M
               sizeof(xmlNodePtr));
2677
3.16M
  if (ret->nodeTab == NULL) {
2678
124
      xmlFree(ret);
2679
124
      return(NULL);
2680
124
  }
2681
3.16M
  memset(ret->nodeTab, 0 ,
2682
3.16M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
3.16M
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
3.16M
  if (val->type == XML_NAMESPACE_DECL) {
2685
24.3k
      xmlNsPtr ns = (xmlNsPtr) val;
2686
24.3k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2687
2688
24.3k
            if (nsNode == NULL) {
2689
10
                xmlXPathFreeNodeSet(ret);
2690
10
                return(NULL);
2691
10
            }
2692
24.3k
      ret->nodeTab[ret->nodeNr++] = nsNode;
2693
24.3k
  } else
2694
3.13M
      ret->nodeTab[ret->nodeNr++] = val;
2695
3.16M
    }
2696
13.9M
    return(ret);
2697
13.9M
}
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
16.2k
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2708
16.2k
    int i;
2709
2710
16.2k
    if ((cur == NULL) || (val == NULL)) return(0);
2711
16.2k
    if (val->type == XML_NAMESPACE_DECL) {
2712
65.5k
  for (i = 0; i < cur->nodeNr; i++) {
2713
60.1k
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2714
39.8k
    xmlNsPtr ns1, ns2;
2715
2716
39.8k
    ns1 = (xmlNsPtr) val;
2717
39.8k
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2718
39.8k
    if (ns1 == ns2)
2719
0
        return(1);
2720
39.8k
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2721
39.8k
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2722
3.19k
        return(1);
2723
39.8k
      }
2724
60.1k
  }
2725
8.62k
    } else {
2726
57.7k
  for (i = 0; i < cur->nodeNr; i++) {
2727
52.8k
      if (cur->nodeTab[i] == val)
2728
2.84k
    return(1);
2729
52.8k
  }
2730
7.65k
    }
2731
10.2k
    return(0);
2732
16.2k
}
2733
2734
static int
2735
16.3M
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
16.3M
    xmlNodePtr *temp;
2737
16.3M
    int newSize;
2738
2739
16.3M
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
16.3M
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
16.3M
    if (newSize < 0)
2742
0
        return(-1);
2743
16.3M
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
16.3M
    if (temp == NULL)
2745
8.79k
        return(-1);
2746
16.3M
    cur->nodeMax = newSize;
2747
16.3M
    cur->nodeTab = temp;
2748
2749
16.3M
    return(0);
2750
16.3M
}
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.40M
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
1.40M
    int i;
2763
1.40M
    xmlNodePtr nsNode;
2764
2765
1.40M
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
1.40M
        (ns->type != XML_NAMESPACE_DECL) ||
2767
1.40M
  (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
5.07M
    for (i = 0;i < cur->nodeNr;i++) {
2775
3.67M
        if ((cur->nodeTab[i] != NULL) &&
2776
3.67M
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
3.67M
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
3.67M
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
3.67M
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
1.40M
    if (cur->nodeNr >= cur->nodeMax) {
2786
314k
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
18
            return(-1);
2788
314k
    }
2789
1.40M
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
1.40M
    if(nsNode == NULL)
2791
100
        return(-1);
2792
1.40M
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
1.40M
    return(0);
2794
1.40M
}
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
23.5M
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
23.5M
    int i;
2806
2807
23.5M
    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
25.2G
    for (i = 0;i < cur->nodeNr;i++)
2814
25.2G
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
23.0M
    if (cur->nodeNr >= cur->nodeMax) {
2820
532k
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
6.33k
            return(-1);
2822
532k
    }
2823
2824
23.0M
    if (val->type == XML_NAMESPACE_DECL) {
2825
232k
  xmlNsPtr ns = (xmlNsPtr) val;
2826
232k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2827
2828
232k
        if (nsNode == NULL)
2829
283
            return(-1);
2830
232k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2831
232k
    } else
2832
22.8M
  cur->nodeTab[cur->nodeNr++] = val;
2833
23.0M
    return(0);
2834
23.0M
}
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
39.4M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
39.4M
    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
39.4M
    if (cur->nodeNr >= cur->nodeMax) {
2853
11.0M
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
1.92k
            return(-1);
2855
11.0M
    }
2856
2857
39.4M
    if (val->type == XML_NAMESPACE_DECL) {
2858
560k
  xmlNsPtr ns = (xmlNsPtr) val;
2859
560k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
560k
        if (nsNode == NULL)
2862
146
            return(-1);
2863
560k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
560k
    } else
2865
38.8M
  cur->nodeTab[cur->nodeNr++] = val;
2866
39.4M
    return(0);
2867
39.4M
}
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
3.48M
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
3.48M
    int i, j, initNr, skip;
2882
3.48M
    xmlNodePtr n1, n2;
2883
2884
3.48M
    if (val1 == NULL) {
2885
703k
  val1 = xmlXPathNodeSetCreate(NULL);
2886
703k
        if (val1 == NULL)
2887
283
            return (NULL);
2888
703k
    }
2889
3.48M
    if (val2 == NULL)
2890
26.9k
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
3.45M
    initNr = val1->nodeNr;
2894
2895
21.3M
    for (i = 0;i < val2->nodeNr;i++) {
2896
17.9M
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
17.9M
  skip = 0;
2901
217M
  for (j = 0; j < initNr; j++) {
2902
200M
      n1 = val1->nodeTab[j];
2903
200M
      if (n1 == n2) {
2904
841k
    skip = 1;
2905
841k
    break;
2906
199M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
199M
           (n2->type == XML_NAMESPACE_DECL)) {
2908
121k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2909
121k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2910
15.0k
      ((xmlNsPtr) n2)->prefix)))
2911
5.57k
    {
2912
5.57k
        skip = 1;
2913
5.57k
        break;
2914
5.57k
    }
2915
121k
      }
2916
200M
  }
2917
17.9M
  if (skip)
2918
846k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
17.0M
        if (val1->nodeNr >= val1->nodeMax) {
2924
4.28M
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
407
                goto error;
2926
4.28M
        }
2927
17.0M
  if (n2->type == XML_NAMESPACE_DECL) {
2928
426k
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
426k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
426k
            if (nsNode == NULL)
2932
42
                goto error;
2933
426k
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
426k
  } else
2935
16.6M
      val1->nodeTab[val1->nodeNr++] = n2;
2936
17.0M
    }
2937
2938
3.45M
    return(val1);
2939
2940
449
error:
2941
449
    xmlXPathFreeNodeSet(val1);
2942
449
    return(NULL);
2943
3.45M
}
2944
2945
2946
/**
2947
 * Merges two nodesets, all nodes from `set2` are added to `set1`.
2948
 * Checks for duplicate nodes. Clears set2.
2949
 *
2950
 * Frees `set1` in case of error.
2951
 *
2952
 * @param set1  the first NodeSet or NULL
2953
 * @param set2  the second NodeSet
2954
 * @returns `set1` once extended or NULL in case of error.
2955
 */
2956
static xmlNodeSetPtr
2957
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
2958
1.07M
{
2959
1.07M
    {
2960
1.07M
  int i, j, initNbSet1;
2961
1.07M
  xmlNodePtr n1, n2;
2962
2963
1.07M
  initNbSet1 = set1->nodeNr;
2964
2.39M
  for (i = 0;i < set2->nodeNr;i++) {
2965
1.31M
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
546M
      for (j = 0; j < initNbSet1; j++) {
2970
546M
    n1 = set1->nodeTab[j];
2971
546M
    if (n1 == n2) {
2972
735k
        goto skip_node;
2973
545M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
545M
        (n2->type == XML_NAMESPACE_DECL))
2975
447M
    {
2976
447M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
447M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
1.79M
      ((xmlNsPtr) n2)->prefix)))
2979
5.53k
        {
2980
      /*
2981
      * Free the namespace node.
2982
      */
2983
5.53k
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
2984
5.53k
      goto skip_node;
2985
5.53k
        }
2986
447M
    }
2987
546M
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
577k
            if (set1->nodeNr >= set1->nodeMax) {
2992
57.6k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
49
                    goto error;
2994
57.6k
            }
2995
577k
      set1->nodeTab[set1->nodeNr++] = n2;
2996
1.31M
skip_node:
2997
1.31M
            set2->nodeTab[i] = NULL;
2998
1.31M
  }
2999
1.07M
    }
3000
1.07M
    set2->nodeNr = 0;
3001
1.07M
    return(set1);
3002
3003
49
error:
3004
49
    xmlXPathFreeNodeSet(set1);
3005
49
    xmlXPathNodeSetClear(set2, 1);
3006
49
    return(NULL);
3007
1.07M
}
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
489k
{
3022
489k
    {
3023
489k
  int i;
3024
489k
  xmlNodePtr n2;
3025
3026
2.60M
  for (i = 0;i < set2->nodeNr;i++) {
3027
2.11M
      n2 = set2->nodeTab[i];
3028
2.11M
            if (set1->nodeNr >= set1->nodeMax) {
3029
198k
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
66
                    goto error;
3031
198k
            }
3032
2.11M
      set1->nodeTab[set1->nodeNr++] = n2;
3033
2.11M
            set2->nodeTab[i] = NULL;
3034
2.11M
  }
3035
489k
    }
3036
488k
    set2->nodeNr = 0;
3037
488k
    return(set1);
3038
3039
66
error:
3040
66
    xmlXPathFreeNodeSet(set1);
3041
66
    xmlXPathNodeSetClear(set2, 1);
3042
66
    return(NULL);
3043
489k
}
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
13.5M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
13.5M
    if (obj == NULL) return;
3103
13.5M
    if (obj->nodeTab != NULL) {
3104
7.18M
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
83.1M
  for (i = 0;i < obj->nodeNr;i++)
3108
75.9M
      if ((obj->nodeTab[i] != NULL) &&
3109
75.9M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
2.37M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
7.18M
  xmlFree(obj->nodeTab);
3112
7.18M
    }
3113
13.5M
    xmlFree(obj);
3114
13.5M
}
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
18.4k
{
3128
18.4k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
18.4k
    else if ((hasNsNodes)) {
3131
13.0k
  int i;
3132
13.0k
  xmlNodePtr node;
3133
3134
243k
  for (i = pos; i < set->nodeNr; i++) {
3135
230k
      node = set->nodeTab[i];
3136
230k
      if ((node != NULL) &&
3137
230k
    (node->type == XML_NAMESPACE_DECL))
3138
21.3k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
230k
  }
3140
13.0k
    }
3141
18.4k
    set->nodeNr = pos;
3142
18.4k
}
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
11.7k
{
3155
11.7k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
11.7k
}
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
6.20k
{
3168
6.20k
    int i;
3169
6.20k
    xmlNodePtr node;
3170
3171
6.20k
    if ((set == NULL) || (set->nodeNr <= 1))
3172
0
  return;
3173
21.3k
    for (i = 0; i < set->nodeNr - 1; i++) {
3174
15.1k
        node = set->nodeTab[i];
3175
15.1k
        if ((node != NULL) &&
3176
15.1k
            (node->type == XML_NAMESPACE_DECL))
3177
4.23k
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3178
15.1k
    }
3179
6.20k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3180
6.20k
    set->nodeNr = 1;
3181
6.20k
}
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
5.34M
xmlXPathNewNodeSet(xmlNode *val) {
3192
5.34M
    xmlXPathObjectPtr ret;
3193
3194
5.34M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
5.34M
    if (ret == NULL)
3196
2.17k
  return(NULL);
3197
5.33M
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
5.33M
    ret->type = XPATH_NODESET;
3199
5.33M
    ret->boolval = 0;
3200
5.33M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
5.33M
    if (ret->nodesetval == NULL) {
3202
275
        xmlFree(ret);
3203
275
        return(NULL);
3204
275
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
5.33M
    return(ret);
3207
5.33M
}
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
31.6k
xmlXPathNewValueTree(xmlNode *val) {
3218
31.6k
    xmlXPathObjectPtr ret;
3219
3220
31.6k
    ret = xmlXPathNewNodeSet(val);
3221
31.6k
    if (ret == NULL)
3222
1.18k
  return(NULL);
3223
30.4k
    ret->type = XPATH_XSLT_TREE;
3224
3225
30.4k
    return(ret);
3226
31.6k
}
3227
3228
/**
3229
 * Create a new xmlXPathObject of type NodeSet and initialize
3230
 * it with the Nodeset `val`
3231
 *
3232
 * @param val  an existing NodeSet
3233
 * @returns the newly created object.
3234
 */
3235
xmlXPathObject *
3236
xmlXPathNewNodeSetList(xmlNodeSet *val)
3237
0
{
3238
0
    xmlXPathObjectPtr ret;
3239
3240
0
    if (val == NULL)
3241
0
        ret = NULL;
3242
0
    else if (val->nodeTab == NULL)
3243
0
        ret = xmlXPathNewNodeSet(NULL);
3244
0
    else {
3245
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3246
0
        if (ret) {
3247
0
            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3248
0
            if (ret->nodesetval == NULL) {
3249
0
                xmlFree(ret);
3250
0
                return(NULL);
3251
0
            }
3252
0
        }
3253
0
    }
3254
3255
0
    return (ret);
3256
0
}
3257
3258
/**
3259
 * Wrap the Nodeset `val` in a new xmlXPathObject
3260
 *
3261
 * In case of error the node set is destroyed and NULL is returned.
3262
 *
3263
 * @param val  the NodePtr value
3264
 * @returns the newly created object.
3265
 */
3266
xmlXPathObject *
3267
2.75M
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
2.75M
    xmlXPathObjectPtr ret;
3269
3270
2.75M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
2.75M
    if (ret == NULL) {
3272
2.73k
        xmlXPathFreeNodeSet(val);
3273
2.73k
  return(NULL);
3274
2.73k
    }
3275
2.74M
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
2.74M
    ret->type = XPATH_NODESET;
3277
2.74M
    ret->nodesetval = val;
3278
2.74M
    return(ret);
3279
2.75M
}
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
618
xmlXPathDifference (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3304
618
    xmlNodeSetPtr ret;
3305
618
    int i, l1;
3306
618
    xmlNodePtr cur;
3307
3308
618
    if (xmlXPathNodeSetIsEmpty(nodes2))
3309
94
  return(nodes1);
3310
3311
524
    ret = xmlXPathNodeSetCreate(NULL);
3312
524
    if (ret == NULL)
3313
1
        return(NULL);
3314
523
    if (xmlXPathNodeSetIsEmpty(nodes1))
3315
95
  return(ret);
3316
3317
428
    l1 = xmlXPathNodeSetGetLength(nodes1);
3318
3319
3.07k
    for (i = 0; i < l1; i++) {
3320
2.65k
  cur = xmlXPathNodeSetItem(nodes1, i);
3321
2.65k
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3322
1.21k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3323
9
                xmlXPathFreeNodeSet(ret);
3324
9
          return(NULL);
3325
9
            }
3326
1.21k
  }
3327
2.65k
    }
3328
419
    return(ret);
3329
428
}
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
971
xmlXPathIntersection (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3342
971
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3343
971
    int i, l1;
3344
971
    xmlNodePtr cur;
3345
3346
971
    if (ret == NULL)
3347
1
        return(ret);
3348
970
    if (xmlXPathNodeSetIsEmpty(nodes1))
3349
77
  return(ret);
3350
893
    if (xmlXPathNodeSetIsEmpty(nodes2))
3351
72
  return(ret);
3352
3353
821
    l1 = xmlXPathNodeSetGetLength(nodes1);
3354
3355
2.91k
    for (i = 0; i < l1; i++) {
3356
2.09k
  cur = xmlXPathNodeSetItem(nodes1, i);
3357
2.09k
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3358
996
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3359
5
                xmlXPathFreeNodeSet(ret);
3360
5
          return(NULL);
3361
5
            }
3362
996
  }
3363
2.09k
    }
3364
816
    return(ret);
3365
821
}
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
311
xmlXPathDistinctSorted (xmlNodeSet *nodes) {
3377
311
    xmlNodeSetPtr ret;
3378
311
    xmlHashTablePtr hash;
3379
311
    int i, l;
3380
311
    xmlChar * strval;
3381
311
    xmlNodePtr cur;
3382
3383
311
    if (xmlXPathNodeSetIsEmpty(nodes))
3384
77
  return(nodes);
3385
3386
234
    ret = xmlXPathNodeSetCreate(NULL);
3387
234
    if (ret == NULL)
3388
1
        return(ret);
3389
233
    l = xmlXPathNodeSetGetLength(nodes);
3390
233
    hash = xmlHashCreate (l);
3391
12.3k
    for (i = 0; i < l; i++) {
3392
12.1k
  cur = xmlXPathNodeSetItem(nodes, i);
3393
12.1k
  strval = xmlXPathCastNodeToString(cur);
3394
12.1k
  if (xmlHashLookup(hash, strval) == NULL) {
3395
3.36k
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3396
9
                xmlFree(strval);
3397
9
                goto error;
3398
9
            }
3399
3.35k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3400
1
          goto error;
3401
8.76k
  } else {
3402
8.76k
      xmlFree(strval);
3403
8.76k
  }
3404
12.1k
    }
3405
223
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3406
223
    return(ret);
3407
3408
10
error:
3409
10
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3410
10
    xmlXPathFreeNodeSet(ret);
3411
10
    return(NULL);
3412
233
}
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
898
xmlXPathHasSameNodes (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3444
898
    int i, l;
3445
898
    xmlNodePtr cur;
3446
3447
898
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3448
898
  xmlXPathNodeSetIsEmpty(nodes2))
3449
429
  return(0);
3450
3451
469
    l = xmlXPathNodeSetGetLength(nodes1);
3452
2.74k
    for (i = 0; i < l; i++) {
3453
2.45k
  cur = xmlXPathNodeSetItem(nodes1, i);
3454
2.45k
  if (xmlXPathNodeSetContains(nodes2, cur))
3455
179
      return(1);
3456
2.45k
    }
3457
290
    return(0);
3458
469
}
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
1.55k
xmlXPathNodeLeadingSorted (xmlNodeSet *nodes, xmlNode *node) {
3472
1.55k
    int i, l;
3473
1.55k
    xmlNodePtr cur;
3474
1.55k
    xmlNodeSetPtr ret;
3475
3476
1.55k
    if (node == NULL)
3477
0
  return(nodes);
3478
3479
1.55k
    ret = xmlXPathNodeSetCreate(NULL);
3480
1.55k
    if (ret == NULL)
3481
1
        return(ret);
3482
1.55k
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3483
1.55k
  (!xmlXPathNodeSetContains(nodes, node)))
3484
1.39k
  return(ret);
3485
3486
153
    l = xmlXPathNodeSetGetLength(nodes);
3487
620
    for (i = 0; i < l; i++) {
3488
590
  cur = xmlXPathNodeSetItem(nodes, i);
3489
590
  if (cur == node)
3490
122
      break;
3491
468
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3492
1
            xmlXPathFreeNodeSet(ret);
3493
1
      return(NULL);
3494
1
        }
3495
468
    }
3496
152
    return(ret);
3497
153
}
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
12.1k
xmlXPathNodeTrailingSorted (xmlNodeSet *nodes, xmlNode *node) {
3571
12.1k
    int i, l;
3572
12.1k
    xmlNodePtr cur;
3573
12.1k
    xmlNodeSetPtr ret;
3574
3575
12.1k
    if (node == NULL)
3576
0
  return(nodes);
3577
3578
12.1k
    ret = xmlXPathNodeSetCreate(NULL);
3579
12.1k
    if (ret == NULL)
3580
1
        return(ret);
3581
12.1k
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3582
12.1k
  (!xmlXPathNodeSetContains(nodes, node)))
3583
8.92k
  return(ret);
3584
3585
3.27k
    l = xmlXPathNodeSetGetLength(nodes);
3586
1.66M
    for (i = l - 1; i >= 0; i--) {
3587
1.66M
  cur = xmlXPathNodeSetItem(nodes, i);
3588
1.66M
  if (cur == node)
3589
1.08k
      break;
3590
1.66M
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3591
1
            xmlXPathFreeNodeSet(ret);
3592
1
      return(NULL);
3593
1
        }
3594
1.66M
    }
3595
3.27k
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3596
3.27k
    return(ret);
3597
3.27k
}
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
157k
         xmlXPathFunction f) {
3676
157k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3677
157k
}
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
159k
           const xmlChar *ns_uri, xmlXPathFunction f) {
3691
159k
    int ret;
3692
159k
    void *payload;
3693
3694
159k
    if (ctxt == NULL)
3695
0
  return(-1);
3696
159k
    if (name == NULL)
3697
0
  return(-1);
3698
3699
159k
    if (ctxt->funcHash == NULL)
3700
17.5k
  ctxt->funcHash = xmlHashCreate(0);
3701
159k
    if (ctxt->funcHash == NULL) {
3702
18
        xmlXPathErrMemory(ctxt);
3703
18
  return(-1);
3704
18
    }
3705
159k
    if (f == NULL)
3706
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3707
159k
    memcpy(&payload, &f, sizeof(f));
3708
159k
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3709
159k
    if (ret < 0) {
3710
119
        xmlXPathErrMemory(ctxt);
3711
119
        return(-1);
3712
119
    }
3713
3714
158k
    return(0);
3715
159k
}
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
17.5k
          void *funcCtxt) {
3728
17.5k
    if (ctxt == NULL)
3729
0
  return;
3730
17.5k
    ctxt->funcLookupFunc = f;
3731
17.5k
    ctxt->funcLookupData = funcCtxt;
3732
17.5k
}
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
136k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
136k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
136k
}
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
306k
       const xmlChar *ns_uri) {
3759
306k
    xmlXPathFunction ret;
3760
306k
    void *payload;
3761
3762
306k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
306k
    if (name == NULL)
3765
3
  return(NULL);
3766
3767
306k
    if (ns_uri == NULL) {
3768
137k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
236k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
147k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
147k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
147k
                       (char *) name) == 0)
3775
48.8k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
98.7k
            bucketIndex += 1;
3778
98.7k
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
98.7k
        }
3781
137k
    }
3782
3783
257k
    if (ctxt->funcLookupFunc != NULL) {
3784
257k
  xmlXPathFuncLookupFunc f;
3785
3786
257k
  f = ctxt->funcLookupFunc;
3787
257k
  ret = f(ctxt->funcLookupData, name, ns_uri);
3788
257k
  if (ret != NULL)
3789
157k
      return(ret);
3790
257k
    }
3791
3792
99.8k
    if (ctxt->funcHash == NULL)
3793
295
  return(NULL);
3794
3795
99.5k
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3796
99.5k
    memcpy(&ret, &payload, sizeof(payload));
3797
3798
99.5k
    return(ret);
3799
99.8k
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
82.3k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
82.3k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
82.3k
    xmlHashFree(ctxt->funcHash, NULL);
3812
82.3k
    ctxt->funcHash = NULL;
3813
82.3k
}
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
1.20k
       xmlXPathObject *value) {
3833
1.20k
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3834
1.20k
}
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
1.20k
         xmlXPathObject *value) {
3850
1.20k
    if (ctxt == NULL)
3851
0
  return(-1);
3852
1.20k
    if (name == NULL)
3853
0
  return(-1);
3854
3855
1.20k
    if (ctxt->varHash == NULL)
3856
300
  ctxt->varHash = xmlHashCreate(0);
3857
1.20k
    if (ctxt->varHash == NULL)
3858
0
  return(-1);
3859
1.20k
    if (value == NULL)
3860
4
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3861
4
                             xmlXPathFreeObjectEntry));
3862
1.19k
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3863
1.19k
             (void *) value, xmlXPathFreeObjectEntry));
3864
1.20k
}
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
17.5k
   xmlXPathVariableLookupFunc f, void *data) {
3876
17.5k
    if (ctxt == NULL)
3877
0
  return;
3878
17.5k
    ctxt->varLookupFunc = f;
3879
17.5k
    ctxt->varLookupData = data;
3880
17.5k
}
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
132k
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
132k
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
132k
    if (ctxt->varLookupFunc != NULL) {
3896
131k
  xmlXPathObjectPtr ret;
3897
3898
131k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3899
131k
          (ctxt->varLookupData, name, NULL);
3900
131k
  return(ret);
3901
131k
    }
3902
908
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
132k
}
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
10.6k
       const xmlChar *ns_uri) {
3917
10.6k
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
10.6k
    if (ctxt->varLookupFunc != NULL) {
3921
9.65k
  xmlXPathObjectPtr ret;
3922
3923
9.65k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3924
9.65k
          (ctxt->varLookupData, name, ns_uri);
3925
9.65k
  if (ret != NULL) return(ret);
3926
9.65k
    }
3927
3928
10.6k
    if (ctxt->varHash == NULL)
3929
10.6k
  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
82.3k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
82.3k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
82.3k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
82.3k
    ctxt->varHash = NULL;
3948
82.3k
}
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
7.66k
         const xmlChar *ns_uri) {
3962
7.66k
    xmlChar *copy;
3963
3964
7.66k
    if (ctxt == NULL)
3965
0
  return(-1);
3966
7.66k
    if (prefix == NULL)
3967
0
  return(-1);
3968
7.66k
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
7.66k
    if (ctxt->nsHash == NULL)
3972
3.91k
  ctxt->nsHash = xmlHashCreate(10);
3973
7.66k
    if (ctxt->nsHash == NULL) {
3974
3
        xmlXPathErrMemory(ctxt);
3975
3
  return(-1);
3976
3
    }
3977
7.65k
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
7.65k
    copy = xmlStrdup(ns_uri);
3982
7.65k
    if (copy == NULL) {
3983
2
        xmlXPathErrMemory(ctxt);
3984
2
        return(-1);
3985
2
    }
3986
7.65k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
7.65k
                           xmlHashDefaultDeallocator) < 0) {
3988
1
        xmlXPathErrMemory(ctxt);
3989
1
        xmlFree(copy);
3990
1
        return(-1);
3991
1
    }
3992
3993
7.65k
    return(0);
3994
7.65k
}
3995
3996
/**
3997
 * Search in the namespace declaration array of the context for the given
3998
 * namespace name associated to the given prefix
3999
 *
4000
 * @param ctxt  the XPath context
4001
 * @param prefix  the namespace prefix value
4002
 * @returns the value or NULL if not found
4003
 */
4004
const xmlChar *
4005
797k
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
797k
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
797k
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
797k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
7.55k
  return(XML_XML_NAMESPACE);
4013
4014
790k
    if (ctxt->namespaces != NULL) {
4015
786k
  int i;
4016
4017
5.74M
  for (i = 0;i < ctxt->nsNr;i++) {
4018
5.64M
      if ((ctxt->namespaces[i] != NULL) &&
4019
5.64M
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4020
689k
    return(ctxt->namespaces[i]->href);
4021
5.64M
  }
4022
786k
    }
4023
4024
101k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
790k
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
82.6k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
82.6k
    if (ctxt == NULL)
4035
2
  return;
4036
4037
82.6k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
82.6k
    ctxt->nsHash = NULL;
4039
82.6k
}
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
771k
xmlXPathNewFloat(double val) {
4057
771k
    xmlXPathObjectPtr ret;
4058
4059
771k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
771k
    if (ret == NULL)
4061
1.69k
  return(NULL);
4062
770k
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
770k
    ret->type = XPATH_NUMBER;
4064
770k
    ret->floatval = val;
4065
770k
    return(ret);
4066
771k
}
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
238k
xmlXPathNewBoolean(int val) {
4076
238k
    xmlXPathObjectPtr ret;
4077
4078
238k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
238k
    if (ret == NULL)
4080
1.39k
  return(NULL);
4081
237k
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
237k
    ret->type = XPATH_BOOLEAN;
4083
237k
    ret->boolval = (val != 0);
4084
237k
    return(ret);
4085
238k
}
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
228k
xmlXPathNewString(const xmlChar *val) {
4095
228k
    xmlXPathObjectPtr ret;
4096
4097
228k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
228k
    if (ret == NULL)
4099
6.35k
  return(NULL);
4100
222k
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
222k
    ret->type = XPATH_STRING;
4102
222k
    if (val == NULL)
4103
30
        val = BAD_CAST "";
4104
222k
    ret->stringval = xmlStrdup(val);
4105
222k
    if (ret->stringval == NULL) {
4106
67
        xmlFree(ret);
4107
67
        return(NULL);
4108
67
    }
4109
222k
    return(ret);
4110
222k
}
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
538k
xmlXPathWrapString (xmlChar *val) {
4122
538k
    xmlXPathObjectPtr ret;
4123
4124
538k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
538k
    if (ret == NULL) {
4126
881
        xmlFree(val);
4127
881
  return(NULL);
4128
881
    }
4129
537k
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
537k
    ret->type = XPATH_STRING;
4131
537k
    ret->stringval = val;
4132
537k
    return(ret);
4133
538k
}
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
64.6k
xmlXPathNewCString(const char *val) {
4143
64.6k
    return(xmlXPathNewString(BAD_CAST val));
4144
64.6k
}
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
5.15k
xmlXPathWrapExternal (void *val) {
4165
5.15k
    xmlXPathObjectPtr ret;
4166
4167
5.15k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4168
5.15k
    if (ret == NULL)
4169
2
  return(NULL);
4170
5.15k
    memset(ret, 0 , sizeof(xmlXPathObject));
4171
5.15k
    ret->type = XPATH_USERS;
4172
5.15k
    ret->user = val;
4173
5.15k
    return(ret);
4174
5.15k
}
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
727k
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
727k
    xmlXPathObjectPtr ret;
4185
4186
727k
    if (val == NULL)
4187
1
  return(NULL);
4188
4189
727k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
727k
    if (ret == NULL)
4191
367
  return(NULL);
4192
727k
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
727k
    switch (val->type) {
4194
653
  case XPATH_BOOLEAN:
4195
15.6k
  case XPATH_NUMBER:
4196
15.6k
      break;
4197
34.6k
  case XPATH_STRING:
4198
34.6k
      ret->stringval = xmlStrdup(val->stringval);
4199
34.6k
            if (ret->stringval == NULL) {
4200
8
                xmlFree(ret);
4201
8
                return(NULL);
4202
8
            }
4203
34.5k
      break;
4204
39.0k
  case XPATH_XSLT_TREE:
4205
676k
  case XPATH_NODESET:
4206
676k
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4207
676k
            if (ret->nodesetval == NULL) {
4208
47
                xmlFree(ret);
4209
47
                return(NULL);
4210
47
            }
4211
      /* Do not deallocate the copied tree value */
4212
676k
      ret->boolval = 0;
4213
676k
      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
727k
    }
4222
726k
    return(ret);
4223
727k
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
10.0M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
10.0M
    if (obj == NULL) return;
4233
9.72M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
6.05M
        if (obj->nodesetval != NULL)
4235
5.97M
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
6.05M
    } else if (obj->type == XPATH_STRING) {
4237
2.04M
  if (obj->stringval != NULL)
4238
2.03M
      xmlFree(obj->stringval);
4239
2.04M
    }
4240
9.72M
    xmlFree(obj);
4241
9.72M
}
4242
4243
static void
4244
1.19k
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4245
1.19k
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4246
1.19k
}
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
20.0M
{
4258
20.0M
    if (obj == NULL)
4259
20.0k
  return;
4260
19.9M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
54.0k
   xmlXPathFreeObject(obj);
4262
19.9M
    } else {
4263
19.9M
  xmlXPathContextCachePtr cache =
4264
19.9M
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
19.9M
  switch (obj->type) {
4267
15.6M
      case XPATH_NODESET:
4268
15.6M
      case XPATH_XSLT_TREE:
4269
15.6M
    if (obj->nodesetval != NULL) {
4270
14.7M
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
14.7M
      (cache->numNodeset < cache->maxNodeset)) {
4272
9.02M
                        obj->stringval = (void *) cache->nodesetObjs;
4273
9.02M
                        cache->nodesetObjs = obj;
4274
9.02M
                        cache->numNodeset += 1;
4275
9.02M
      goto obj_cached;
4276
9.02M
        } else {
4277
5.69M
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
5.69M
      obj->nodesetval = NULL;
4279
5.69M
        }
4280
14.7M
    }
4281
6.61M
    break;
4282
6.61M
      case XPATH_STRING:
4283
1.10M
    if (obj->stringval != NULL)
4284
1.10M
        xmlFree(obj->stringval);
4285
1.10M
                obj->stringval = NULL;
4286
1.10M
    break;
4287
903k
      case XPATH_BOOLEAN:
4288
3.18M
      case XPATH_NUMBER:
4289
3.18M
    break;
4290
4.71k
      default:
4291
4.71k
    goto free_obj;
4292
19.9M
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
10.9M
        if (cache->numMisc >= cache->maxMisc)
4298
401k
      goto free_obj;
4299
10.5M
        obj->stringval = (void *) cache->miscObjs;
4300
10.5M
        cache->miscObjs = obj;
4301
10.5M
        cache->numMisc += 1;
4302
4303
19.5M
obj_cached:
4304
19.5M
        obj->boolval = 0;
4305
19.5M
  if (obj->nodesetval != NULL) {
4306
9.02M
      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
9.02M
      if (tmpset->nodeNr > 0) {
4313
8.48M
    int i;
4314
8.48M
    xmlNodePtr node;
4315
4316
20.7M
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
12.2M
        node = tmpset->nodeTab[i];
4318
12.2M
        if ((node != NULL) &&
4319
12.2M
      (node->type == XML_NAMESPACE_DECL))
4320
174k
        {
4321
174k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
174k
        }
4323
12.2M
    }
4324
8.48M
      }
4325
9.02M
      tmpset->nodeNr = 0;
4326
9.02M
        }
4327
4328
19.5M
  return;
4329
4330
405k
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
405k
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
405k
  xmlFree(obj);
4337
405k
    }
4338
19.9M
}
4339
4340
4341
/************************************************************************
4342
 *                  *
4343
 *      Type Casting Routines       *
4344
 *                  *
4345
 ************************************************************************/
4346
4347
/**
4348
 * Converts a boolean to its string value.
4349
 *
4350
 * @param val  a boolean
4351
 * @returns a newly allocated string.
4352
 */
4353
xmlChar *
4354
36.5k
xmlXPathCastBooleanToString (int val) {
4355
36.5k
    xmlChar *ret;
4356
36.5k
    if (val)
4357
8.58k
  ret = xmlStrdup((const xmlChar *) "true");
4358
27.9k
    else
4359
27.9k
  ret = xmlStrdup((const xmlChar *) "false");
4360
36.5k
    return(ret);
4361
36.5k
}
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
571k
xmlXPathCastNumberToString (double val) {
4371
571k
    xmlChar *ret;
4372
571k
    switch (xmlXPathIsInf(val)) {
4373
4.42k
    case 1:
4374
4.42k
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
4.42k
  break;
4376
1.79k
    case -1:
4377
1.79k
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
1.79k
  break;
4379
565k
    default:
4380
565k
  if (xmlXPathIsNaN(val)) {
4381
290k
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
290k
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
15.0k
      ret = xmlStrdup((const xmlChar *) "0");
4385
259k
  } else {
4386
      /* could be improved */
4387
259k
      char buf[100];
4388
259k
      xmlXPathFormatNumber(val, buf, 99);
4389
259k
      buf[99] = 0;
4390
259k
      ret = xmlStrdup((const xmlChar *) buf);
4391
259k
  }
4392
571k
    }
4393
571k
    return(ret);
4394
571k
}
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
4.23M
xmlXPathCastNodeToString (xmlNode *node) {
4404
4.23M
    return(xmlNodeGetContent(node));
4405
4.23M
}
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
4.33M
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
4.33M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
1.03M
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
3.29M
    if (ns->nodeNr > 1)
4419
80.1k
  xmlXPathNodeSetSort(ns);
4420
3.29M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
4.33M
}
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
3.27M
xmlXPathCastToString(xmlXPathObject *val) {
4432
3.27M
    xmlChar *ret = NULL;
4433
4434
3.27M
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
3.27M
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
2.87M
        case XPATH_NODESET:
4441
2.87M
        case XPATH_XSLT_TREE:
4442
2.87M
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
2.87M
      break;
4444
151k
  case XPATH_STRING:
4445
151k
      return(xmlStrdup(val->stringval));
4446
34.6k
        case XPATH_BOOLEAN:
4447
34.6k
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
34.6k
      break;
4449
207k
  case XPATH_NUMBER: {
4450
207k
      ret = xmlXPathCastNumberToString(val->floatval);
4451
207k
      break;
4452
2.87M
  }
4453
434
  case XPATH_USERS:
4454
      /* TODO */
4455
434
      ret = xmlStrdup((const xmlChar *) "");
4456
434
      break;
4457
3.27M
    }
4458
3.12M
    return(ret);
4459
3.27M
}
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
118k
xmlXPathConvertString(xmlXPathObject *val) {
4470
118k
    xmlChar *res = NULL;
4471
4472
118k
    if (val == NULL)
4473
0
  return(xmlXPathNewCString(""));
4474
4475
118k
    switch (val->type) {
4476
0
    case XPATH_UNDEFINED:
4477
0
  break;
4478
116k
    case XPATH_NODESET:
4479
116k
    case XPATH_XSLT_TREE:
4480
116k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4481
116k
  break;
4482
0
    case XPATH_STRING:
4483
0
  return(val);
4484
1.88k
    case XPATH_BOOLEAN:
4485
1.88k
  res = xmlXPathCastBooleanToString(val->boolval);
4486
1.88k
  break;
4487
674
    case XPATH_NUMBER:
4488
674
  res = xmlXPathCastNumberToString(val->floatval);
4489
674
  break;
4490
0
    case XPATH_USERS:
4491
  /* TODO */
4492
0
  break;
4493
118k
    }
4494
118k
    xmlXPathFreeObject(val);
4495
118k
    if (res == NULL)
4496
120
  return(xmlXPathNewCString(""));
4497
118k
    return(xmlXPathWrapString(res));
4498
118k
}
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
92.2k
xmlXPathCastBooleanToNumber(int val) {
4508
92.2k
    if (val)
4509
10.0k
  return(1.0);
4510
82.2k
    return(0.0);
4511
92.2k
}
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
2.19M
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
2.19M
    return(xmlXPathStringEvalNumber(val));
4522
2.19M
}
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
123k
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
123k
    xmlChar *strval;
4534
123k
    double ret;
4535
4536
123k
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
123k
    strval = xmlXPathCastNodeToString(node);
4539
123k
    if (strval == NULL) {
4540
1.33k
        xmlXPathPErrMemory(ctxt);
4541
1.33k
  return(xmlXPathNAN);
4542
1.33k
    }
4543
122k
    ret = xmlXPathCastStringToNumber(strval);
4544
122k
    xmlFree(strval);
4545
4546
122k
    return(ret);
4547
123k
}
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
25.5k
xmlXPathCastNodeToNumber (xmlNode *node) {
4557
25.5k
    return(xmlXPathNodeToNumberInternal(NULL, node));
4558
25.5k
}
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
178k
xmlXPathCastNumberToBoolean (double val) {
4618
178k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
114k
   return(0);
4620
63.8k
     return(1);
4621
178k
}
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
15.9k
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
15.9k
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
5.38k
  return(0);
4633
10.5k
    return(1);
4634
15.9k
}
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
255k
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
255k
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
217k
  return(0);
4646
38.1k
    return(1);
4647
255k
}
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
369k
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
369k
    int ret = 0;
4658
4659
369k
    if (val == NULL)
4660
0
  return(0);
4661
369k
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
255k
    case XPATH_NODESET:
4666
255k
    case XPATH_XSLT_TREE:
4667
255k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
255k
  break;
4669
15.9k
    case XPATH_STRING:
4670
15.9k
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
15.9k
  break;
4672
96.9k
    case XPATH_NUMBER:
4673
96.9k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
96.9k
  break;
4675
0
    case XPATH_BOOLEAN:
4676
0
  ret = val->boolval;
4677
0
  break;
4678
1.05k
    case XPATH_USERS:
4679
  /* TODO */
4680
1.05k
  ret = 0;
4681
1.05k
  break;
4682
369k
    }
4683
369k
    return(ret);
4684
369k
}
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
82.3k
xmlXPathNewContext(xmlDoc *doc) {
4721
82.3k
    xmlXPathContextPtr ret;
4722
4723
82.3k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
82.3k
    if (ret == NULL)
4725
23
  return(NULL);
4726
82.3k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
82.3k
    ret->doc = doc;
4728
82.3k
    ret->node = NULL;
4729
4730
82.3k
    ret->varHash = NULL;
4731
4732
82.3k
    ret->nb_types = 0;
4733
82.3k
    ret->max_types = 0;
4734
82.3k
    ret->types = NULL;
4735
4736
82.3k
    ret->nb_axis = 0;
4737
82.3k
    ret->max_axis = 0;
4738
82.3k
    ret->axis = NULL;
4739
4740
82.3k
    ret->nsHash = NULL;
4741
82.3k
    ret->user = NULL;
4742
4743
82.3k
    ret->contextSize = -1;
4744
82.3k
    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
82.3k
    return(ret);
4754
82.3k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
82.3k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
82.3k
    if (ctxt == NULL) return;
4764
4765
82.3k
    if (ctxt->cache != NULL)
4766
44.4k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
82.3k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
82.3k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
82.3k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
82.3k
    xmlResetError(&ctxt->lastError);
4771
82.3k
    xmlFree(ctxt);
4772
82.3k
}
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
939k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
939k
    xmlXPathParserContextPtr ret;
4809
4810
939k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
939k
    if (ret == NULL) {
4812
1.31k
        xmlXPathErrMemory(ctxt);
4813
1.31k
  return(NULL);
4814
1.31k
    }
4815
937k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
937k
    ret->cur = ret->base = str;
4817
937k
    ret->context = ctxt;
4818
4819
937k
    ret->comp = xmlXPathNewCompExpr();
4820
937k
    if (ret->comp == NULL) {
4821
100
        xmlXPathErrMemory(ctxt);
4822
100
  xmlFree(ret->valueTab);
4823
100
  xmlFree(ret);
4824
100
  return(NULL);
4825
100
    }
4826
937k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
200k
        ret->comp->dict = ctxt->dict;
4828
200k
  xmlDictReference(ret->comp->dict);
4829
200k
    }
4830
4831
937k
    return(ret);
4832
937k
}
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
4.78M
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
4.78M
    xmlXPathParserContextPtr ret;
4844
4845
4.78M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
4.78M
    if (ret == NULL) {
4847
85.7k
        xmlXPathErrMemory(ctxt);
4848
85.7k
  return(NULL);
4849
85.7k
    }
4850
4.70M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
4.70M
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
4.70M
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
4.70M
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
4.70M
    if (ret->valueTab == NULL) {
4860
337
  xmlFree(ret);
4861
337
  xmlXPathErrMemory(ctxt);
4862
337
  return(NULL);
4863
337
    }
4864
4.70M
    ret->valueNr = 0;
4865
4.70M
    ret->value = NULL;
4866
4867
4.70M
    ret->context = ctxt;
4868
4.70M
    ret->comp = comp;
4869
4870
4.70M
    return(ret);
4871
4.70M
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
5.64M
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
5.64M
    int i;
4881
4882
5.64M
    if (ctxt == NULL)
4883
0
        return;
4884
4885
5.64M
    if (ctxt->valueTab != NULL) {
4886
5.38M
        for (i = 0; i < ctxt->valueNr; i++) {
4887
623k
            if (ctxt->context)
4888
623k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
623k
        }
4892
4.75M
        xmlFree(ctxt->valueTab);
4893
4.75M
    }
4894
5.64M
    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
496k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
496k
    }
4903
5.64M
    xmlFree(ctxt);
4904
5.64M
}
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
301k
xmlXPathNodeValHash(xmlNodePtr node) {
4921
301k
    int len = 2;
4922
301k
    const xmlChar * string = NULL;
4923
301k
    xmlNodePtr tmp = NULL;
4924
301k
    unsigned int ret = 0;
4925
4926
301k
    if (node == NULL)
4927
0
  return(0);
4928
4929
301k
    if (node->type == XML_DOCUMENT_NODE) {
4930
105k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
105k
  if (tmp == NULL)
4932
18.2k
      node = node->children;
4933
87.0k
  else
4934
87.0k
      node = tmp;
4935
4936
105k
  if (node == NULL)
4937
699
      return(0);
4938
105k
    }
4939
4940
300k
    switch (node->type) {
4941
1.29k
  case XML_COMMENT_NODE:
4942
2.27k
  case XML_PI_NODE:
4943
2.53k
  case XML_CDATA_SECTION_NODE:
4944
67.3k
  case XML_TEXT_NODE:
4945
67.3k
      string = node->content;
4946
67.3k
      if (string == NULL)
4947
978
    return(0);
4948
66.4k
      if (string[0] == 0)
4949
32.2k
    return(0);
4950
34.1k
      return(string[0] + (string[1] << 8));
4951
27.7k
  case XML_NAMESPACE_DECL:
4952
27.7k
      string = ((xmlNsPtr)node)->href;
4953
27.7k
      if (string == NULL)
4954
0
    return(0);
4955
27.7k
      if (string[0] == 0)
4956
1.86k
    return(0);
4957
25.8k
      return(string[0] + (string[1] << 8));
4958
24.2k
  case XML_ATTRIBUTE_NODE:
4959
24.2k
      tmp = ((xmlAttrPtr) node)->children;
4960
24.2k
      break;
4961
181k
  case XML_ELEMENT_NODE:
4962
181k
      tmp = node->children;
4963
181k
      break;
4964
0
  default:
4965
0
      return(0);
4966
300k
    }
4967
379k
    while (tmp != NULL) {
4968
296k
  switch (tmp->type) {
4969
2
      case XML_CDATA_SECTION_NODE:
4970
187k
      case XML_TEXT_NODE:
4971
187k
    string = tmp->content;
4972
187k
    break;
4973
108k
      default:
4974
108k
                string = NULL;
4975
108k
    break;
4976
296k
  }
4977
296k
  if ((string != NULL) && (string[0] != 0)) {
4978
142k
      if (len == 1) {
4979
2.17k
    return(ret + (string[0] << 8));
4980
2.17k
      }
4981
140k
      if (string[1] == 0) {
4982
19.8k
    len = 1;
4983
19.8k
    ret = string[0];
4984
120k
      } else {
4985
120k
    return(string[0] + (string[1] << 8));
4986
120k
      }
4987
140k
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
173k
        if ((tmp->children != NULL) &&
4992
173k
            (tmp->type != XML_DTD_NODE) &&
4993
173k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
173k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
60.6k
            tmp = tmp->children;
4996
60.6k
            continue;
4997
60.6k
  }
4998
113k
  if (tmp == node)
4999
0
      break;
5000
5001
113k
  if (tmp->next != NULL) {
5002
46.7k
      tmp = tmp->next;
5003
46.7k
      continue;
5004
46.7k
  }
5005
5006
67.2k
  do {
5007
67.2k
      tmp = tmp->parent;
5008
67.2k
      if (tmp == NULL)
5009
0
    break;
5010
67.2k
      if (tmp == node) {
5011
64.6k
    tmp = NULL;
5012
64.6k
    break;
5013
64.6k
      }
5014
2.63k
      if (tmp->next != NULL) {
5015
1.80k
    tmp = tmp->next;
5016
1.80k
    break;
5017
1.80k
      }
5018
2.63k
  } while (tmp != NULL);
5019
66.4k
    }
5020
83.0k
    return(ret);
5021
205k
}
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
103k
xmlXPathStringHash(const xmlChar * string) {
5032
103k
    if (string == NULL)
5033
0
  return(0);
5034
103k
    if (string[0] == 0)
5035
32.1k
  return(0);
5036
71.5k
    return(string[0] + (string[1] << 8));
5037
103k
}
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
220k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
220k
    int i, ret = 0;
5063
220k
    xmlNodeSetPtr ns;
5064
220k
    xmlChar *str2;
5065
5066
220k
    if ((f == NULL) || (arg == NULL) ||
5067
220k
  ((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
220k
    ns = arg->nodesetval;
5073
220k
    if (ns != NULL) {
5074
416k
  for (i = 0;i < ns->nodeNr;i++) {
5075
195k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
195k
       if (str2 != NULL) {
5077
195k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
195k
     xmlFree(str2);
5079
195k
     xmlXPathNumberFunction(ctxt, 1);
5080
195k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
195k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
195k
     if (ret)
5083
291
         break;
5084
195k
       } else {
5085
586
                 xmlXPathPErrMemory(ctxt);
5086
586
             }
5087
195k
  }
5088
220k
    }
5089
220k
    xmlXPathReleaseObject(ctxt->context, arg);
5090
220k
    xmlXPathReleaseObject(ctxt->context, f);
5091
220k
    return(ret);
5092
220k
}
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
21.5k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
21.5k
    int i, ret = 0;
5117
21.5k
    xmlNodeSetPtr ns;
5118
21.5k
    xmlChar *str2;
5119
5120
21.5k
    if ((s == NULL) || (arg == NULL) ||
5121
21.5k
  ((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
21.5k
    ns = arg->nodesetval;
5127
21.5k
    if (ns != NULL) {
5128
37.5k
  for (i = 0;i < ns->nodeNr;i++) {
5129
16.0k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
16.0k
       if (str2 != NULL) {
5131
15.8k
     xmlXPathValuePush(ctxt,
5132
15.8k
         xmlXPathCacheNewString(ctxt, str2));
5133
15.8k
     xmlFree(str2);
5134
15.8k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
15.8k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
15.8k
     if (ret)
5137
33
         break;
5138
15.8k
       } else {
5139
222
                 xmlXPathPErrMemory(ctxt);
5140
222
             }
5141
16.0k
  }
5142
21.5k
    }
5143
21.5k
    xmlXPathReleaseObject(ctxt->context, arg);
5144
21.5k
    xmlXPathReleaseObject(ctxt->context, s);
5145
21.5k
    return(ret);
5146
21.5k
}
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
279k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
279k
    int i, j, init = 0;
5180
279k
    double val1;
5181
279k
    double *values2;
5182
279k
    int ret = 0;
5183
279k
    xmlNodeSetPtr ns1;
5184
279k
    xmlNodeSetPtr ns2;
5185
5186
279k
    if ((arg1 == NULL) ||
5187
279k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
279k
    if ((arg2 == NULL) ||
5192
279k
  ((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
279k
    ns1 = arg1->nodesetval;
5199
279k
    ns2 = arg2->nodesetval;
5200
5201
279k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
230k
  xmlXPathFreeObject(arg1);
5203
230k
  xmlXPathFreeObject(arg2);
5204
230k
  return(0);
5205
230k
    }
5206
48.9k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
16.6k
  xmlXPathFreeObject(arg1);
5208
16.6k
  xmlXPathFreeObject(arg2);
5209
16.6k
  return(0);
5210
16.6k
    }
5211
5212
32.3k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
32.3k
    if (values2 == NULL) {
5214
342
        xmlXPathPErrMemory(ctxt);
5215
342
  xmlXPathFreeObject(arg1);
5216
342
  xmlXPathFreeObject(arg2);
5217
342
  return(0);
5218
342
    }
5219
91.7k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
60.4k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
60.4k
  if (xmlXPathIsNaN(val1))
5222
45.2k
      continue;
5223
637k
  for (j = 0;j < ns2->nodeNr;j++) {
5224
623k
      if (init == 0) {
5225
30.4k
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
30.4k
                                                          ns2->nodeTab[j]);
5227
30.4k
      }
5228
623k
      if (xmlXPathIsNaN(values2[j]))
5229
170k
    continue;
5230
452k
      if (inf && strict)
5231
0
    ret = (val1 < values2[j]);
5232
452k
      else if (inf && !strict)
5233
0
    ret = (val1 <= values2[j]);
5234
452k
      else if (!inf && strict)
5235
452k
    ret = (val1 > values2[j]);
5236
141
      else if (!inf && !strict)
5237
141
    ret = (val1 >= values2[j]);
5238
452k
      if (ret)
5239
733
    break;
5240
452k
  }
5241
15.2k
  if (ret)
5242
733
      break;
5243
14.4k
  init = 1;
5244
14.4k
    }
5245
32.0k
    xmlFree(values2);
5246
32.0k
    xmlXPathFreeObject(arg1);
5247
32.0k
    xmlXPathFreeObject(arg2);
5248
32.0k
    return(ret);
5249
32.3k
}
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
271k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
271k
    if ((val == NULL) || (arg == NULL) ||
5274
271k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
271k
    switch(val->type) {
5278
220k
        case XPATH_NUMBER:
5279
220k
      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
21.5k
        case XPATH_STRING:
5284
21.5k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
29.6k
        case XPATH_BOOLEAN:
5286
29.6k
      xmlXPathValuePush(ctxt, arg);
5287
29.6k
      xmlXPathBooleanFunction(ctxt, 1);
5288
29.6k
      xmlXPathValuePush(ctxt, val);
5289
29.6k
      return(xmlXPathCompareValues(ctxt, inf, strict));
5290
1
  default:
5291
1
            xmlXPathReleaseObject(ctxt->context, arg);
5292
1
            xmlXPathReleaseObject(ctxt->context, val);
5293
1
            XP_ERROR0(XPATH_INVALID_TYPE);
5294
271k
    }
5295
0
    return(0);
5296
271k
}
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
135k
{
5315
135k
    int i;
5316
135k
    xmlNodeSetPtr ns;
5317
135k
    xmlChar *str2;
5318
135k
    unsigned int hash;
5319
5320
135k
    if ((str == NULL) || (arg == NULL) ||
5321
135k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
135k
    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
135k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
32.0k
        return (0);
5330
103k
    hash = xmlXPathStringHash(str);
5331
117k
    for (i = 0; i < ns->nodeNr; i++) {
5332
105k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
17.4k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
17.4k
            if (str2 == NULL) {
5335
6
                xmlXPathPErrMemory(ctxt);
5336
6
                return(0);
5337
6
            }
5338
17.3k
            if (xmlStrEqual(str, str2)) {
5339
9.07k
                xmlFree(str2);
5340
9.07k
    if (neq)
5341
6.23k
        continue;
5342
2.84k
                return (1);
5343
9.07k
            } else if (neq) {
5344
7.96k
    xmlFree(str2);
5345
7.96k
    return (1);
5346
7.96k
      }
5347
363
            xmlFree(str2);
5348
88.5k
        } else if (neq)
5349
81.0k
      return (1);
5350
105k
    }
5351
11.8k
    return (0);
5352
103k
}
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
59.6k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
59.6k
  int i, ret=0;
5372
59.6k
  xmlNodeSetPtr ns;
5373
59.6k
  xmlChar *str2;
5374
59.6k
  xmlXPathObjectPtr val;
5375
59.6k
  double v;
5376
5377
59.6k
    if ((arg == NULL) ||
5378
59.6k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
59.6k
    ns = arg->nodesetval;
5382
59.6k
    if (ns != NULL) {
5383
198k
  for (i=0;i<ns->nodeNr;i++) {
5384
139k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
139k
      if (str2 != NULL) {
5386
139k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
139k
    xmlFree(str2);
5388
139k
    xmlXPathNumberFunction(ctxt, 1);
5389
139k
                CHECK_ERROR0;
5390
139k
    val = xmlXPathValuePop(ctxt);
5391
139k
    v = val->floatval;
5392
139k
    xmlXPathReleaseObject(ctxt->context, val);
5393
139k
    if (!xmlXPathIsNaN(v)) {
5394
2.50k
        if ((!neq) && (v==f)) {
5395
923
      ret = 1;
5396
923
      break;
5397
1.57k
        } else if ((neq) && (v!=f)) {
5398
539
      ret = 1;
5399
539
      break;
5400
539
        }
5401
137k
    } else { /* NaN is unequal to any value */
5402
137k
        if (neq)
5403
117k
      ret = 1;
5404
137k
    }
5405
139k
      } else {
5406
247
                xmlXPathPErrMemory(ctxt);
5407
247
            }
5408
139k
  }
5409
59.6k
    }
5410
5411
59.6k
    return(ret);
5412
59.6k
}
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
116k
                      xmlXPathObjectPtr arg2, int neq) {
5434
116k
    int i, j;
5435
116k
    unsigned int *hashs1;
5436
116k
    unsigned int *hashs2;
5437
116k
    xmlChar **values1;
5438
116k
    xmlChar **values2;
5439
116k
    int ret = 0;
5440
116k
    xmlNodeSetPtr ns1;
5441
116k
    xmlNodeSetPtr ns2;
5442
5443
116k
    if ((arg1 == NULL) ||
5444
116k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
116k
    if ((arg2 == NULL) ||
5447
116k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
116k
    ns1 = arg1->nodesetval;
5451
116k
    ns2 = arg2->nodesetval;
5452
5453
116k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
53.0k
  return(0);
5455
63.6k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
24.8k
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
38.8k
    if (neq == 0)
5462
106k
  for (i = 0;i < ns1->nodeNr;i++)
5463
245k
      for (j = 0;j < ns2->nodeNr;j++)
5464
169k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
1.43k
        return(1);
5466
5467
37.3k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
37.3k
    if (values1 == NULL) {
5469
228
        xmlXPathPErrMemory(ctxt);
5470
228
  return(0);
5471
228
    }
5472
37.1k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
37.1k
    if (hashs1 == NULL) {
5474
4
        xmlXPathPErrMemory(ctxt);
5475
4
  xmlFree(values1);
5476
4
  return(0);
5477
4
    }
5478
37.1k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
37.1k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
37.1k
    if (values2 == NULL) {
5481
4
        xmlXPathPErrMemory(ctxt);
5482
4
  xmlFree(hashs1);
5483
4
  xmlFree(values1);
5484
4
  return(0);
5485
4
    }
5486
37.1k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
37.1k
    if (hashs2 == NULL) {
5488
4
        xmlXPathPErrMemory(ctxt);
5489
4
  xmlFree(hashs1);
5490
4
  xmlFree(values1);
5491
4
  xmlFree(values2);
5492
4
  return(0);
5493
4
    }
5494
37.1k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
150k
    for (i = 0;i < ns1->nodeNr;i++) {
5496
129k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
293k
  for (j = 0;j < ns2->nodeNr;j++) {
5498
180k
      if (i == 0)
5499
66.5k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
180k
      if (hashs1[i] != hashs2[j]) {
5501
84.1k
    if (neq) {
5502
3.43k
        ret = 1;
5503
3.43k
        break;
5504
3.43k
    }
5505
84.1k
      }
5506
96.1k
      else {
5507
96.1k
    if (values1[i] == NULL) {
5508
83.2k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
83.2k
                    if (values1[i] == NULL)
5510
1.25k
                        xmlXPathPErrMemory(ctxt);
5511
83.2k
                }
5512
96.1k
    if (values2[j] == NULL) {
5513
20.7k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
20.7k
                    if (values2[j] == NULL)
5515
1.07k
                        xmlXPathPErrMemory(ctxt);
5516
20.7k
                }
5517
96.1k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
96.1k
    if (ret)
5519
11.8k
        break;
5520
96.1k
      }
5521
180k
  }
5522
129k
  if (ret)
5523
15.2k
      break;
5524
129k
    }
5525
208k
    for (i = 0;i < ns1->nodeNr;i++)
5526
171k
  if (values1[i] != NULL)
5527
82.0k
      xmlFree(values1[i]);
5528
132k
    for (j = 0;j < ns2->nodeNr;j++)
5529
95.7k
  if (values2[j] != NULL)
5530
19.6k
      xmlFree(values2[j]);
5531
37.1k
    xmlFree(values1);
5532
37.1k
    xmlFree(values2);
5533
37.1k
    xmlFree(hashs1);
5534
37.1k
    xmlFree(hashs2);
5535
37.1k
    return(ret);
5536
37.1k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
213k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
213k
    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
213k
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
99.4k
        case XPATH_BOOLEAN:
5550
99.4k
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
17.3k
    case XPATH_BOOLEAN:
5554
17.3k
        ret = (arg1->boolval == arg2->boolval);
5555
17.3k
        break;
5556
72.5k
    case XPATH_NUMBER:
5557
72.5k
        ret = (arg1->boolval ==
5558
72.5k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
72.5k
        break;
5560
9.42k
    case XPATH_STRING:
5561
9.42k
        if ((arg2->stringval == NULL) ||
5562
9.42k
      (arg2->stringval[0] == 0)) ret = 0;
5563
9.21k
        else
5564
9.21k
      ret = 1;
5565
9.42k
        ret = (arg1->boolval == ret);
5566
9.42k
        break;
5567
99
    case XPATH_USERS:
5568
        /* TODO */
5569
99
        break;
5570
0
    case XPATH_NODESET:
5571
0
    case XPATH_XSLT_TREE:
5572
0
        break;
5573
99.4k
      }
5574
99.4k
      break;
5575
99.4k
        case XPATH_NUMBER:
5576
59.3k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
8.74k
    case XPATH_BOOLEAN:
5580
8.74k
        ret = (arg2->boolval==
5581
8.74k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
8.74k
        break;
5583
11.6k
    case XPATH_STRING:
5584
11.6k
        xmlXPathValuePush(ctxt, arg2);
5585
11.6k
        xmlXPathNumberFunction(ctxt, 1);
5586
11.6k
        arg2 = xmlXPathValuePop(ctxt);
5587
11.6k
                    if (ctxt->error)
5588
0
                        break;
5589
                    /* Falls through. */
5590
50.4k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
50.4k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
50.4k
          xmlXPathIsNaN(arg2->floatval)) {
5594
27.3k
            ret = 0;
5595
27.3k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
601
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
235
          ret = 1;
5598
366
      else
5599
366
          ret = 0;
5600
22.4k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
3.47k
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
250
          ret = 1;
5603
3.22k
      else
5604
3.22k
          ret = 0;
5605
19.0k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
355
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
355
      else
5609
355
          ret = 0;
5610
18.6k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
2.92k
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
2.92k
      else
5614
2.92k
          ret = 0;
5615
15.7k
        } else {
5616
15.7k
            ret = (arg1->floatval == arg2->floatval);
5617
15.7k
        }
5618
50.4k
        break;
5619
183
    case XPATH_USERS:
5620
        /* TODO */
5621
183
        break;
5622
0
    case XPATH_NODESET:
5623
0
    case XPATH_XSLT_TREE:
5624
0
        break;
5625
59.3k
      }
5626
59.3k
      break;
5627
59.3k
        case XPATH_STRING:
5628
54.0k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
12.9k
    case XPATH_BOOLEAN:
5632
12.9k
        if ((arg1->stringval == NULL) ||
5633
12.9k
      (arg1->stringval[0] == 0)) ret = 0;
5634
2.49k
        else
5635
2.49k
      ret = 1;
5636
12.9k
        ret = (arg2->boolval == ret);
5637
12.9k
        break;
5638
1.23k
    case XPATH_STRING:
5639
1.23k
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
1.23k
        break;
5641
39.9k
    case XPATH_NUMBER:
5642
39.9k
        xmlXPathValuePush(ctxt, arg1);
5643
39.9k
        xmlXPathNumberFunction(ctxt, 1);
5644
39.9k
        arg1 = xmlXPathValuePop(ctxt);
5645
39.9k
                    if (ctxt->error)
5646
0
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
39.9k
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
39.9k
          xmlXPathIsNaN(arg2->floatval)) {
5650
25.5k
            ret = 0;
5651
25.5k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
181
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
71
          ret = 1;
5654
110
      else
5655
110
          ret = 0;
5656
14.1k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
684
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
614
          ret = 1;
5659
70
      else
5660
70
          ret = 0;
5661
13.4k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
68
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
68
      else
5665
68
          ret = 0;
5666
13.4k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
69
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
69
      else
5670
69
          ret = 0;
5671
13.3k
        } else {
5672
13.3k
            ret = (arg1->floatval == arg2->floatval);
5673
13.3k
        }
5674
39.9k
        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
54.0k
      }
5682
54.0k
      break;
5683
54.0k
        case XPATH_USERS:
5684
      /* TODO */
5685
317
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
213k
    }
5690
213k
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
213k
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
213k
    return(ret);
5693
213k
}
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
322k
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
322k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
322k
    int ret = 0;
5705
5706
322k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
322k
    arg2 = xmlXPathValuePop(ctxt);
5708
322k
    arg1 = xmlXPathValuePop(ctxt);
5709
322k
    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
322k
    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
322k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
322k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
170k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
35.2k
    argtmp = arg2;
5732
35.2k
    arg2 = arg1;
5733
35.2k
    arg1 = argtmp;
5734
35.2k
  }
5735
170k
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
61.8k
      case XPATH_NODESET:
5739
80.1k
      case XPATH_XSLT_TREE:
5740
80.1k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
80.1k
    break;
5742
44.1k
      case XPATH_BOOLEAN:
5743
44.1k
    if ((arg1->nodesetval == NULL) ||
5744
44.1k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
4.74k
    else
5746
4.74k
        ret = 1;
5747
44.1k
    ret = (ret == arg2->boolval);
5748
44.1k
    break;
5749
14.5k
      case XPATH_NUMBER:
5750
14.5k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
14.5k
    break;
5752
31.6k
      case XPATH_STRING:
5753
31.6k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
31.6k
                                                 arg2->stringval, 0);
5755
31.6k
    break;
5756
225
      case XPATH_USERS:
5757
    /* TODO */
5758
225
    break;
5759
170k
  }
5760
170k
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
170k
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
170k
  return(ret);
5763
170k
    }
5764
5765
152k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
322k
}
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
284k
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
284k
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
284k
    int ret = 0;
5778
5779
284k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
284k
    arg2 = xmlXPathValuePop(ctxt);
5781
284k
    arg1 = xmlXPathValuePop(ctxt);
5782
284k
    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
284k
    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
284k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
284k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
223k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
156k
    argtmp = arg2;
5805
156k
    arg2 = arg1;
5806
156k
    arg1 = argtmp;
5807
156k
  }
5808
223k
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
36.4k
      case XPATH_NODESET:
5812
36.5k
      case XPATH_XSLT_TREE:
5813
36.5k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
36.5k
    break;
5815
37.7k
      case XPATH_BOOLEAN:
5816
37.7k
    if ((arg1->nodesetval == NULL) ||
5817
37.7k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
6.61k
    else
5819
6.61k
        ret = 1;
5820
37.7k
    ret = (ret != arg2->boolval);
5821
37.7k
    break;
5822
45.1k
      case XPATH_NUMBER:
5823
45.1k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
45.1k
    break;
5825
104k
      case XPATH_STRING:
5826
104k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
104k
                                                 arg2->stringval, 1);
5828
104k
    break;
5829
81
      case XPATH_USERS:
5830
    /* TODO */
5831
81
    break;
5832
223k
  }
5833
223k
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
223k
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
223k
  return(ret);
5836
223k
    }
5837
5838
60.8k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
284k
}
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
852k
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
852k
    int ret = 0, arg1i = 0, arg2i = 0;
5866
852k
    xmlXPathObjectPtr arg1, arg2;
5867
5868
852k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
852k
    arg2 = xmlXPathValuePop(ctxt);
5870
852k
    arg1 = xmlXPathValuePop(ctxt);
5871
852k
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
102
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
102
  else
5875
102
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
102
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
852k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
852k
      (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
551k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
551k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
279k
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
279k
  } else {
5890
271k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
14.8k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
14.8k
                                arg1, arg2);
5893
256k
      } else {
5894
256k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
256k
                                arg2, arg1);
5896
256k
      }
5897
271k
  }
5898
551k
  return(ret);
5899
551k
    }
5900
5901
301k
    if (arg1->type != XPATH_NUMBER) {
5902
60.3k
  xmlXPathValuePush(ctxt, arg1);
5903
60.3k
  xmlXPathNumberFunction(ctxt, 1);
5904
60.3k
  arg1 = xmlXPathValuePop(ctxt);
5905
60.3k
    }
5906
301k
    if (arg2->type != XPATH_NUMBER) {
5907
45.3k
  xmlXPathValuePush(ctxt, arg2);
5908
45.3k
  xmlXPathNumberFunction(ctxt, 1);
5909
45.3k
  arg2 = xmlXPathValuePop(ctxt);
5910
45.3k
    }
5911
301k
    if (ctxt->error)
5912
2
        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
301k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
230k
  ret=0;
5920
230k
    } else {
5921
71.0k
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
71.0k
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
71.0k
  if (inf && strict) {
5924
40.5k
      if ((arg1i == -1 && arg2i != -1) ||
5925
40.5k
    (arg2i == 1 && arg1i != 1)) {
5926
3.84k
    ret = 1;
5927
36.6k
      } else if (arg1i == 0 && arg2i == 0) {
5928
31.3k
    ret = (arg1->floatval < arg2->floatval);
5929
31.3k
      } else {
5930
5.31k
    ret = 0;
5931
5.31k
      }
5932
40.5k
  }
5933
30.5k
  else if (inf && !strict) {
5934
8.97k
      if (arg1i == -1 || arg2i == 1) {
5935
4.45k
    ret = 1;
5936
4.52k
      } else if (arg1i == 0 && arg2i == 0) {
5937
920
    ret = (arg1->floatval <= arg2->floatval);
5938
3.60k
      } else {
5939
3.60k
    ret = 0;
5940
3.60k
      }
5941
8.97k
  }
5942
21.5k
  else if (!inf && strict) {
5943
17.3k
      if ((arg1i == 1 && arg2i != 1) ||
5944
17.3k
    (arg2i == -1 && arg1i != -1)) {
5945
3.60k
    ret = 1;
5946
13.7k
      } else if (arg1i == 0 && arg2i == 0) {
5947
9.48k
    ret = (arg1->floatval > arg2->floatval);
5948
9.48k
      } else {
5949
4.28k
    ret = 0;
5950
4.28k
      }
5951
17.3k
  }
5952
4.19k
  else if (!inf && !strict) {
5953
4.19k
      if (arg1i == 1 || arg2i == -1) {
5954
791
    ret = 1;
5955
3.40k
      } else if (arg1i == 0 && arg2i == 0) {
5956
2.70k
    ret = (arg1->floatval >= arg2->floatval);
5957
2.70k
      } else {
5958
694
    ret = 0;
5959
694
      }
5960
4.19k
  }
5961
71.0k
    }
5962
301k
error:
5963
301k
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
301k
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
301k
    return(ret);
5966
301k
}
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
662k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
662k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
662k
    CAST_TO_NUMBER;
5979
662k
    CHECK_TYPE(XPATH_NUMBER);
5980
662k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
662k
}
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
199k
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
199k
    xmlXPathObjectPtr arg;
5993
199k
    double val;
5994
5995
199k
    arg = xmlXPathValuePop(ctxt);
5996
199k
    if (arg == NULL)
5997
199k
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
199k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
199k
    xmlXPathReleaseObject(ctxt->context, arg);
6000
199k
    CAST_TO_NUMBER;
6001
199k
    CHECK_TYPE(XPATH_NUMBER);
6002
199k
    ctxt->value->floatval += val;
6003
199k
}
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
215k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
215k
    xmlXPathObjectPtr arg;
6015
215k
    double val;
6016
6017
215k
    arg = xmlXPathValuePop(ctxt);
6018
215k
    if (arg == NULL)
6019
215k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
215k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
215k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
215k
    CAST_TO_NUMBER;
6023
215k
    CHECK_TYPE(XPATH_NUMBER);
6024
215k
    ctxt->value->floatval -= val;
6025
215k
}
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
447k
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
447k
    xmlXPathObjectPtr arg;
6037
447k
    double val;
6038
6039
447k
    arg = xmlXPathValuePop(ctxt);
6040
447k
    if (arg == NULL)
6041
447k
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
447k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
447k
    xmlXPathReleaseObject(ctxt->context, arg);
6044
447k
    CAST_TO_NUMBER;
6045
447k
    CHECK_TYPE(XPATH_NUMBER);
6046
447k
    ctxt->value->floatval *= val;
6047
447k
}
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
1.68k
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
1.68k
    xmlXPathObjectPtr arg;
6060
1.68k
    double val;
6061
6062
1.68k
    arg = xmlXPathValuePop(ctxt);
6063
1.68k
    if (arg == NULL)
6064
1.68k
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
1.68k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
1.68k
    xmlXPathReleaseObject(ctxt->context, arg);
6067
1.68k
    CAST_TO_NUMBER;
6068
1.68k
    CHECK_TYPE(XPATH_NUMBER);
6069
1.68k
    ctxt->value->floatval /= val;
6070
1.68k
}
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
31.9k
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
31.9k
    xmlXPathObjectPtr arg;
6082
31.9k
    double arg1, arg2;
6083
6084
31.9k
    arg = xmlXPathValuePop(ctxt);
6085
31.9k
    if (arg == NULL)
6086
31.9k
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
31.9k
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
31.9k
    xmlXPathReleaseObject(ctxt->context, arg);
6089
31.9k
    CAST_TO_NUMBER;
6090
31.9k
    CHECK_TYPE(XPATH_NUMBER);
6091
31.8k
    arg1 = ctxt->value->floatval;
6092
31.8k
    if (arg2 == 0)
6093
1.81k
  ctxt->value->floatval = xmlXPathNAN;
6094
29.9k
    else {
6095
29.9k
  ctxt->value->floatval = fmod(arg1, arg2);
6096
29.9k
    }
6097
31.8k
}
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
3.54k
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
3.54k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
3.54k
    if (cur == NULL)
6141
1.77k
        return(ctxt->context->node);
6142
1.77k
    return(NULL);
6143
3.54k
}
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
2.95M
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
2.95M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
2.95M
    if (cur == NULL) {
6157
1.28M
  if (ctxt->context->node == NULL) return(NULL);
6158
1.28M
  switch (ctxt->context->node->type) {
6159
892k
            case XML_ELEMENT_NODE:
6160
1.14M
            case XML_TEXT_NODE:
6161
1.14M
            case XML_CDATA_SECTION_NODE:
6162
1.14M
            case XML_ENTITY_REF_NODE:
6163
1.14M
            case XML_ENTITY_NODE:
6164
1.14M
            case XML_PI_NODE:
6165
1.16M
            case XML_COMMENT_NODE:
6166
1.16M
            case XML_NOTATION_NODE:
6167
1.16M
            case XML_DTD_NODE:
6168
1.16M
    return(ctxt->context->node->children);
6169
91.2k
            case XML_DOCUMENT_NODE:
6170
91.2k
            case XML_DOCUMENT_TYPE_NODE:
6171
91.2k
            case XML_DOCUMENT_FRAG_NODE:
6172
91.2k
            case XML_HTML_DOCUMENT_NODE:
6173
91.2k
    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
10
            case XML_ATTRIBUTE_NODE:
6178
22.2k
      case XML_NAMESPACE_DECL:
6179
22.2k
      case XML_XINCLUDE_START:
6180
22.2k
      case XML_XINCLUDE_END:
6181
22.2k
    return(NULL);
6182
1.28M
  }
6183
0
  return(NULL);
6184
1.28M
    }
6185
1.66M
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
1.66M
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
1.66M
    return(cur->next);
6189
1.66M
}
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
9.14M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
9.14M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
9.14M
    if (cur == NULL) {
6203
5.32M
  cur = ctxt->context->node;
6204
5.32M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
5.32M
  switch (cur->type) {
6209
2.72M
            case XML_ELEMENT_NODE:
6210
2.72M
      case XML_DOCUMENT_FRAG_NODE:
6211
2.72M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
2.72M
            case XML_ENTITY_NODE:
6213
2.72M
    cur = cur->children;
6214
2.72M
    if (cur != NULL) {
6215
1.42M
        if (cur->type == XML_ELEMENT_NODE)
6216
478k
      return(cur);
6217
1.06M
        do {
6218
1.06M
      cur = cur->next;
6219
1.06M
        } while ((cur != NULL) &&
6220
1.06M
      (cur->type != XML_ELEMENT_NODE));
6221
949k
        return(cur);
6222
1.42M
    }
6223
1.29M
    return(NULL);
6224
640k
            case XML_DOCUMENT_NODE:
6225
640k
            case XML_HTML_DOCUMENT_NODE:
6226
640k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
1.96M
      default:
6228
1.96M
    return(NULL);
6229
5.32M
  }
6230
0
  return(NULL);
6231
5.32M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
3.82M
    switch (cur->type) {
6236
3.82M
  case XML_ELEMENT_NODE:
6237
3.82M
  case XML_TEXT_NODE:
6238
3.82M
  case XML_ENTITY_REF_NODE:
6239
3.82M
  case XML_ENTITY_NODE:
6240
3.82M
  case XML_CDATA_SECTION_NODE:
6241
3.82M
  case XML_PI_NODE:
6242
3.82M
  case XML_COMMENT_NODE:
6243
3.82M
  case XML_XINCLUDE_END:
6244
3.82M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
3.82M
    }
6249
3.82M
    if (cur->next != NULL) {
6250
2.73M
  if (cur->next->type == XML_ELEMENT_NODE)
6251
1.41M
      return(cur->next);
6252
1.32M
  cur = cur->next;
6253
1.48M
  do {
6254
1.48M
      cur = cur->next;
6255
1.48M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
1.32M
  return(cur);
6257
2.73M
    }
6258
1.08M
    return(NULL);
6259
3.82M
}
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
37.2M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
37.2M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
37.2M
    if (cur == NULL) {
6274
1.07M
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
1.07M
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
1.07M
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
5.52k
      return(NULL);
6279
6280
1.06M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
897k
      return(ctxt->context->doc->children);
6282
168k
        return(ctxt->context->node->children);
6283
1.06M
    }
6284
6285
36.2M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
36.2M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
7.45M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
7.45M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
7.45M
      if (cur->type != XML_DTD_NODE)
6297
7.45M
    return(cur);
6298
7.45M
  }
6299
7.45M
    }
6300
6301
28.7M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
28.7M
    while (cur->next != NULL) {
6304
23.7M
  cur = cur->next;
6305
23.7M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
23.7M
      (cur->type != XML_DTD_NODE))
6307
23.7M
      return(cur);
6308
23.7M
    }
6309
6310
8.43M
    do {
6311
8.43M
        cur = cur->parent;
6312
8.43M
  if (cur == NULL) break;
6313
8.43M
  if (cur == ctxt->context->node) return(NULL);
6314
7.21M
  if (cur->next != NULL) {
6315
3.82M
      cur = cur->next;
6316
3.82M
      return(cur);
6317
3.82M
  }
6318
7.21M
    } while (cur != NULL);
6319
0
    return(cur);
6320
5.05M
}
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
13.5M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
13.5M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
13.5M
    if (cur == NULL)
6337
642k
        return(ctxt->context->node);
6338
6339
12.8M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
12.8M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
12.8M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
395k
        return(NULL);
6344
6345
12.4M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
12.8M
}
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
1.54M
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
1.54M
    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
1.54M
    if (cur == NULL) {
6365
782k
  if (ctxt->context->node == NULL) return(NULL);
6366
782k
  switch (ctxt->context->node->type) {
6367
404k
            case XML_ELEMENT_NODE:
6368
714k
            case XML_TEXT_NODE:
6369
724k
            case XML_CDATA_SECTION_NODE:
6370
724k
            case XML_ENTITY_REF_NODE:
6371
724k
            case XML_ENTITY_NODE:
6372
731k
            case XML_PI_NODE:
6373
745k
            case XML_COMMENT_NODE:
6374
745k
            case XML_NOTATION_NODE:
6375
745k
            case XML_DTD_NODE:
6376
745k
      case XML_ELEMENT_DECL:
6377
745k
      case XML_ATTRIBUTE_DECL:
6378
745k
      case XML_XINCLUDE_START:
6379
745k
      case XML_XINCLUDE_END:
6380
745k
      case XML_ENTITY_DECL:
6381
745k
    if (ctxt->context->node->parent == NULL)
6382
0
        return((xmlNodePtr) ctxt->context->doc);
6383
745k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
745k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
701k
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
701k
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
745k
    return(ctxt->context->node->parent);
6389
929
            case XML_ATTRIBUTE_NODE: {
6390
929
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
929
    return(att->parent);
6393
745k
      }
6394
18.2k
            case XML_DOCUMENT_NODE:
6395
18.2k
            case XML_DOCUMENT_TYPE_NODE:
6396
18.2k
            case XML_DOCUMENT_FRAG_NODE:
6397
18.2k
            case XML_HTML_DOCUMENT_NODE:
6398
18.2k
                return(NULL);
6399
18.2k
      case XML_NAMESPACE_DECL: {
6400
18.2k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6401
6402
18.2k
    if ((ns->next != NULL) &&
6403
18.2k
        (ns->next->type != XML_NAMESPACE_DECL))
6404
18.2k
        return((xmlNodePtr) ns->next);
6405
0
                return(NULL);
6406
18.2k
      }
6407
782k
  }
6408
782k
    }
6409
763k
    return(NULL);
6410
1.54M
}
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
213k
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
213k
    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
213k
    if (cur == NULL) {
6433
39.2k
  if (ctxt->context->node == NULL) return(NULL);
6434
39.2k
  switch (ctxt->context->node->type) {
6435
11.4k
            case XML_ELEMENT_NODE:
6436
28.3k
            case XML_TEXT_NODE:
6437
28.4k
            case XML_CDATA_SECTION_NODE:
6438
28.4k
            case XML_ENTITY_REF_NODE:
6439
28.4k
            case XML_ENTITY_NODE:
6440
30.2k
            case XML_PI_NODE:
6441
31.3k
            case XML_COMMENT_NODE:
6442
31.3k
      case XML_DTD_NODE:
6443
31.3k
      case XML_ELEMENT_DECL:
6444
31.3k
      case XML_ATTRIBUTE_DECL:
6445
31.3k
      case XML_ENTITY_DECL:
6446
31.3k
            case XML_NOTATION_NODE:
6447
31.3k
      case XML_XINCLUDE_START:
6448
31.3k
      case XML_XINCLUDE_END:
6449
31.3k
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
31.3k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
31.3k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
29.6k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
29.6k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
31.3k
    return(ctxt->context->node->parent);
6457
0
            case XML_ATTRIBUTE_NODE: {
6458
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
0
    return(tmp->parent);
6461
31.3k
      }
6462
3.91k
            case XML_DOCUMENT_NODE:
6463
3.91k
            case XML_DOCUMENT_TYPE_NODE:
6464
3.91k
            case XML_DOCUMENT_FRAG_NODE:
6465
3.91k
            case XML_HTML_DOCUMENT_NODE:
6466
3.91k
                return(NULL);
6467
3.97k
      case XML_NAMESPACE_DECL: {
6468
3.97k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
3.97k
    if ((ns->next != NULL) &&
6471
3.97k
        (ns->next->type != XML_NAMESPACE_DECL))
6472
3.97k
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
3.97k
      }
6476
39.2k
  }
6477
0
  return(NULL);
6478
39.2k
    }
6479
174k
    if (cur == ctxt->context->doc->children)
6480
47.8k
  return((xmlNodePtr) ctxt->context->doc);
6481
126k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
50.1k
  return(NULL);
6483
76.4k
    switch (cur->type) {
6484
67.4k
  case XML_ELEMENT_NODE:
6485
74.8k
  case XML_TEXT_NODE:
6486
74.8k
  case XML_CDATA_SECTION_NODE:
6487
74.8k
  case XML_ENTITY_REF_NODE:
6488
74.8k
  case XML_ENTITY_NODE:
6489
75.8k
  case XML_PI_NODE:
6490
76.2k
  case XML_COMMENT_NODE:
6491
76.2k
  case XML_NOTATION_NODE:
6492
76.2k
  case XML_DTD_NODE:
6493
76.2k
        case XML_ELEMENT_DECL:
6494
76.2k
        case XML_ATTRIBUTE_DECL:
6495
76.2k
        case XML_ENTITY_DECL:
6496
76.2k
  case XML_XINCLUDE_START:
6497
76.2k
  case XML_XINCLUDE_END:
6498
76.2k
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
76.2k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
76.2k
    ((cur->parent->name[0] == ' ') ||
6502
75.6k
     (xmlStrEqual(cur->parent->name,
6503
75.6k
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
76.2k
      return(cur->parent);
6506
0
  case XML_ATTRIBUTE_NODE: {
6507
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
0
      return(att->parent);
6510
76.2k
  }
6511
236
  case XML_NAMESPACE_DECL: {
6512
236
      xmlNsPtr ns = (xmlNsPtr) cur;
6513
6514
236
      if ((ns->next != NULL) &&
6515
236
          (ns->next->type != XML_NAMESPACE_DECL))
6516
236
          return((xmlNodePtr) ns->next);
6517
      /* Bad, how did that namespace end up here ? */
6518
0
            return(NULL);
6519
236
  }
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
76.4k
    }
6526
0
    return(NULL);
6527
76.4k
}
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
68.8k
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
68.8k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
68.8k
    if (cur == NULL)
6544
14.8k
        return(ctxt->context->node);
6545
54.0k
    return(xmlXPathNextAncestor(ctxt, cur));
6546
68.8k
}
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
0
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
0
  return(NULL);
6563
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6564
0
        return(NULL);
6565
0
    if (cur == NULL)
6566
0
        return(ctxt->context->node->next);
6567
0
    return(cur->next);
6568
0
}
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
26.0k
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6582
26.0k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6583
26.0k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6584
26.0k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6585
0
  return(NULL);
6586
26.0k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6587
0
        return(NULL);
6588
26.0k
    if (cur == NULL)
6589
4.96k
        return(ctxt->context->node->prev);
6590
21.0k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6591
0
  cur = cur->prev;
6592
0
  if (cur == NULL)
6593
0
      return(ctxt->context->node->prev);
6594
0
    }
6595
21.0k
    return(cur->prev);
6596
21.0k
}
6597
6598
/**
6599
 * Traversal function for the "following" direction
6600
 * The following axis contains all nodes in the same document as the context
6601
 * node that are after the context node in document order, excluding any
6602
 * descendants and excluding attribute nodes and namespace nodes; the nodes
6603
 * are ordered in document order
6604
 *
6605
 * @param ctxt  the XPath Parser context
6606
 * @param cur  the current node in the traversal
6607
 * @returns the next element following that axis
6608
 */
6609
xmlNode *
6610
26.7k
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6611
26.7k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6612
26.7k
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6613
26.7k
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6614
1.56k
        return(cur->children);
6615
6616
25.2k
    if (cur == NULL) {
6617
4.17k
        cur = ctxt->context->node;
6618
4.17k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6619
816
            cur = cur->parent;
6620
3.35k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6621
98
            xmlNsPtr ns = (xmlNsPtr) cur;
6622
6623
98
            if ((ns->next == NULL) ||
6624
98
                (ns->next->type == XML_NAMESPACE_DECL))
6625
0
                return (NULL);
6626
98
            cur = (xmlNodePtr) ns->next;
6627
98
        }
6628
4.17k
    }
6629
25.2k
    if (cur == NULL) return(NULL) ; /* ERROR */
6630
25.2k
    if (cur->next != NULL) return(cur->next) ;
6631
12.8k
    do {
6632
12.8k
        cur = cur->parent;
6633
12.8k
        if (cur == NULL) break;
6634
12.6k
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6635
8.69k
        if (cur->next != NULL) return(cur->next);
6636
8.69k
    } while (cur != NULL);
6637
223
    return(cur);
6638
6.87k
}
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
317k
{
6732
317k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6733
317k
    if (cur == NULL) {
6734
37.3k
        cur = ctxt->context->node;
6735
37.3k
        if (cur == NULL)
6736
0
            return (NULL);
6737
37.3k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6738
2.04k
            cur = cur->parent;
6739
35.2k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6740
53
            xmlNsPtr ns = (xmlNsPtr) cur;
6741
6742
53
            if ((ns->next == NULL) ||
6743
53
                (ns->next->type == XML_NAMESPACE_DECL))
6744
0
                return (NULL);
6745
53
            cur = (xmlNodePtr) ns->next;
6746
53
        }
6747
37.3k
        ctxt->ancestor = cur->parent;
6748
37.3k
    }
6749
317k
    if (cur->type == XML_NAMESPACE_DECL)
6750
0
        return(NULL);
6751
317k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6752
0
  cur = cur->prev;
6753
404k
    while (cur->prev == NULL) {
6754
155k
        cur = cur->parent;
6755
155k
        if (cur == NULL)
6756
4.84k
            return (NULL);
6757
150k
        if (cur == ctxt->context->doc->children)
6758
32.4k
            return (NULL);
6759
117k
        if (cur != ctxt->ancestor)
6760
30.3k
            return (cur);
6761
87.4k
        ctxt->ancestor = cur->parent;
6762
87.4k
    }
6763
249k
    cur = cur->prev;
6764
279k
    while (cur->last != NULL)
6765
30.3k
        cur = cur->last;
6766
249k
    return (cur);
6767
317k
}
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
2.05M
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6783
2.05M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6784
2.05M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6785
1.89M
    if (cur == NULL) {
6786
357k
        if (ctxt->context->tmpNsList != NULL)
6787
11.3k
      xmlFree(ctxt->context->tmpNsList);
6788
357k
  ctxt->context->tmpNsNr = 0;
6789
357k
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6790
357k
                             &ctxt->context->tmpNsList) < 0) {
6791
34
            xmlXPathPErrMemory(ctxt);
6792
34
            return(NULL);
6793
34
        }
6794
357k
        if (ctxt->context->tmpNsList != NULL) {
6795
1.58M
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6796
1.23M
                ctxt->context->tmpNsNr++;
6797
1.23M
            }
6798
352k
        }
6799
357k
  return((xmlNodePtr) xmlXPathXMLNamespace);
6800
357k
    }
6801
1.53M
    if (ctxt->context->tmpNsNr > 0) {
6802
1.20M
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6803
1.20M
    } else {
6804
338k
  if (ctxt->context->tmpNsList != NULL)
6805
333k
      xmlFree(ctxt->context->tmpNsList);
6806
338k
  ctxt->context->tmpNsList = NULL;
6807
338k
  return(NULL);
6808
338k
    }
6809
1.53M
}
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
1.51M
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6821
1.51M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6822
1.51M
    if (ctxt->context->node == NULL)
6823
0
  return(NULL);
6824
1.51M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6825
209k
  return(NULL);
6826
1.30M
    if (cur == NULL) {
6827
643k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6828
0
      return(NULL);
6829
643k
        return((xmlNodePtr)ctxt->context->node->properties);
6830
643k
    }
6831
663k
    return((xmlNodePtr)cur->next);
6832
1.30M
}
6833
6834
/************************************************************************
6835
 *                  *
6836
 *    NodeTest Functions          *
6837
 *                  *
6838
 ************************************************************************/
6839
6840
#define IS_FUNCTION     200
6841
6842
6843
/************************************************************************
6844
 *                  *
6845
 *    Implicit tree core function library     *
6846
 *                  *
6847
 ************************************************************************/
6848
6849
/**
6850
 * Initialize the context to the root of the document
6851
 *
6852
 * @param ctxt  the XPath Parser context
6853
 */
6854
void
6855
1.92M
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6856
1.92M
    if ((ctxt == NULL) || (ctxt->context == NULL))
6857
0
  return;
6858
1.92M
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6859
1.92M
                                            (xmlNodePtr) ctxt->context->doc));
6860
1.92M
}
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
59.4k
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6880
177k
    CHECK_ARITY(0);
6881
177k
    if (ctxt->context->contextSize >= 0) {
6882
58.8k
  xmlXPathValuePush(ctxt,
6883
58.8k
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6884
58.8k
    } else {
6885
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6886
0
    }
6887
177k
}
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
64.2k
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6901
190k
    CHECK_ARITY(0);
6902
190k
    if (ctxt->context->proximityPosition >= 0) {
6903
63.2k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6904
63.2k
            (double) ctxt->context->proximityPosition));
6905
63.2k
    } else {
6906
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6907
0
    }
6908
190k
}
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
12.1k
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6919
12.1k
    xmlXPathObjectPtr cur;
6920
6921
36.3k
    CHECK_ARITY(1);
6922
36.3k
    if ((ctxt->value == NULL) ||
6923
12.1k
  ((ctxt->value->type != XPATH_NODESET) &&
6924
12.1k
   (ctxt->value->type != XPATH_XSLT_TREE)))
6925
11.7k
  XP_ERROR(XPATH_INVALID_TYPE);
6926
11.7k
    cur = xmlXPathValuePop(ctxt);
6927
6928
11.7k
    if ((cur == NULL) || (cur->nodesetval == NULL))
6929
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6930
11.7k
    else
6931
11.7k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6932
11.7k
      (double) cur->nodesetval->nodeNr));
6933
11.7k
    xmlXPathReleaseObject(ctxt->context, cur);
6934
11.7k
}
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
54.9k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6945
54.9k
    xmlNodeSetPtr ret;
6946
54.9k
    const xmlChar *cur = ids;
6947
54.9k
    xmlChar *ID;
6948
54.9k
    xmlAttrPtr attr;
6949
54.9k
    xmlNodePtr elem = NULL;
6950
6951
54.9k
    if (ids == NULL) return(NULL);
6952
6953
54.5k
    ret = xmlXPathNodeSetCreate(NULL);
6954
54.5k
    if (ret == NULL)
6955
6
        return(ret);
6956
6957
54.5k
    while (IS_BLANK_CH(*cur)) cur++;
6958
282k
    while (*cur != 0) {
6959
2.38M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6960
2.15M
      cur++;
6961
6962
227k
        ID = xmlStrndup(ids, cur - ids);
6963
227k
  if (ID == NULL) {
6964
24
            xmlXPathFreeNodeSet(ret);
6965
24
            return(NULL);
6966
24
        }
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
227k
        attr = xmlGetID(doc, ID);
6975
227k
        xmlFree(ID);
6976
227k
        if (attr != NULL) {
6977
0
            if (attr->type == XML_ATTRIBUTE_NODE)
6978
0
                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
0
            if (elem != NULL) {
6984
0
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
6985
0
                    xmlXPathFreeNodeSet(ret);
6986
0
                    return(NULL);
6987
0
                }
6988
0
            }
6989
0
        }
6990
6991
588k
  while (IS_BLANK_CH(*cur)) cur++;
6992
227k
  ids = cur;
6993
227k
    }
6994
54.5k
    return(ret);
6995
54.5k
}
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
44.1k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7016
44.1k
    xmlChar *tokens;
7017
44.1k
    xmlNodeSetPtr ret;
7018
44.1k
    xmlXPathObjectPtr obj;
7019
7020
125k
    CHECK_ARITY(1);
7021
125k
    obj = xmlXPathValuePop(ctxt);
7022
125k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7023
40.5k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7024
16.4k
  xmlNodeSetPtr ns;
7025
16.4k
  int i;
7026
7027
16.4k
  ret = xmlXPathNodeSetCreate(NULL);
7028
16.4k
        if (ret == NULL)
7029
89
            xmlXPathPErrMemory(ctxt);
7030
7031
16.4k
  if (obj->nodesetval != NULL) {
7032
47.3k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7033
30.9k
    tokens =
7034
30.9k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7035
30.9k
                if (tokens == NULL)
7036
336
                    xmlXPathPErrMemory(ctxt);
7037
30.9k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7038
30.9k
                if (ns == NULL)
7039
359
                    xmlXPathPErrMemory(ctxt);
7040
30.9k
    ret = xmlXPathNodeSetMerge(ret, ns);
7041
30.9k
                if (ret == NULL)
7042
79
                    xmlXPathPErrMemory(ctxt);
7043
30.9k
    xmlXPathFreeNodeSet(ns);
7044
30.9k
    if (tokens != NULL)
7045
30.5k
        xmlFree(tokens);
7046
30.9k
      }
7047
16.4k
  }
7048
16.4k
  xmlXPathReleaseObject(ctxt->context, obj);
7049
16.4k
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7050
16.4k
  return;
7051
16.4k
    }
7052
24.0k
    tokens = xmlXPathCastToString(obj);
7053
24.0k
    if (tokens == NULL)
7054
82
        xmlXPathPErrMemory(ctxt);
7055
24.0k
    xmlXPathReleaseObject(ctxt->context, obj);
7056
24.0k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7057
24.0k
    if (ret == NULL)
7058
89
        xmlXPathPErrMemory(ctxt);
7059
24.0k
    xmlFree(tokens);
7060
24.0k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7061
24.0k
}
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
20.1k
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7077
20.1k
    xmlXPathObjectPtr cur;
7078
7079
20.1k
    if (ctxt == NULL) return;
7080
7081
20.1k
    if (nargs == 0) {
7082
6.44k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7083
6.44k
  nargs = 1;
7084
6.44k
    }
7085
7086
57.1k
    CHECK_ARITY(1);
7087
57.1k
    if ((ctxt->value == NULL) ||
7088
18.5k
  ((ctxt->value->type != XPATH_NODESET) &&
7089
18.5k
   (ctxt->value->type != XPATH_XSLT_TREE)))
7090
14.5k
  XP_ERROR(XPATH_INVALID_TYPE);
7091
14.5k
    cur = xmlXPathValuePop(ctxt);
7092
7093
14.5k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7094
80
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7095
14.4k
    } else {
7096
14.4k
  int i = 0; /* Should be first in document order !!!!! */
7097
14.4k
  switch (cur->nodesetval->nodeTab[i]->type) {
7098
3.05k
  case XML_ELEMENT_NODE:
7099
3.05k
  case XML_ATTRIBUTE_NODE:
7100
4.00k
  case XML_PI_NODE:
7101
4.00k
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7102
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7103
4.00k
      else
7104
4.00k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7105
4.00k
      cur->nodesetval->nodeTab[i]->name));
7106
4.00k
      break;
7107
1.33k
  case XML_NAMESPACE_DECL:
7108
1.33k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7109
1.33k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7110
1.33k
      break;
7111
9.09k
  default:
7112
9.09k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7113
14.4k
  }
7114
14.4k
    }
7115
14.5k
    xmlXPathReleaseObject(ctxt->context, cur);
7116
14.5k
}
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
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7133
1
    xmlXPathObjectPtr cur;
7134
7135
1
    if (ctxt == NULL) return;
7136
7137
1
    if (nargs == 0) {
7138
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7139
0
  nargs = 1;
7140
0
    }
7141
3
    CHECK_ARITY(1);
7142
3
    if ((ctxt->value == NULL) ||
7143
1
  ((ctxt->value->type != XPATH_NODESET) &&
7144
1
   (ctxt->value->type != XPATH_XSLT_TREE)))
7145
1
  XP_ERROR(XPATH_INVALID_TYPE);
7146
0
    cur = xmlXPathValuePop(ctxt);
7147
7148
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7149
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7150
0
    } else {
7151
0
  int i = 0; /* Should be first in document order !!!!! */
7152
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7153
0
  case XML_ELEMENT_NODE:
7154
0
  case XML_ATTRIBUTE_NODE:
7155
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7156
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7157
0
      else
7158
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7159
0
        cur->nodesetval->nodeTab[i]->ns->href));
7160
0
      break;
7161
0
  default:
7162
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7163
0
  }
7164
0
    }
7165
0
    xmlXPathReleaseObject(ctxt->context, cur);
7166
0
}
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
89.7k
{
7192
89.7k
    xmlXPathObjectPtr cur;
7193
7194
89.7k
    if (nargs == 0) {
7195
50.7k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7196
50.7k
        nargs = 1;
7197
50.7k
    }
7198
7199
268k
    CHECK_ARITY(1);
7200
268k
    if ((ctxt->value == NULL) ||
7201
89.5k
        ((ctxt->value->type != XPATH_NODESET) &&
7202
89.5k
         (ctxt->value->type != XPATH_XSLT_TREE)))
7203
89.2k
        XP_ERROR(XPATH_INVALID_TYPE);
7204
89.2k
    cur = xmlXPathValuePop(ctxt);
7205
7206
89.2k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7207
38.3k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7208
50.9k
    } else {
7209
50.9k
        int i = 0;              /* Should be first in document order !!!!! */
7210
7211
50.9k
        switch (cur->nodesetval->nodeTab[i]->type) {
7212
42.8k
            case XML_ELEMENT_NODE:
7213
42.8k
            case XML_ATTRIBUTE_NODE:
7214
42.8k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7215
0
        xmlXPathValuePush(ctxt,
7216
0
      xmlXPathCacheNewCString(ctxt, ""));
7217
42.8k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7218
42.8k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7219
33.2k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7220
33.2k
          cur->nodesetval->nodeTab[i]->name));
7221
33.2k
    } else {
7222
9.62k
        xmlChar *fullname;
7223
7224
9.62k
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7225
9.62k
             cur->nodesetval->nodeTab[i]->ns->prefix,
7226
9.62k
             NULL, 0);
7227
9.62k
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7228
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7229
9.62k
        if (fullname == NULL)
7230
146
                        xmlXPathPErrMemory(ctxt);
7231
9.62k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7232
9.62k
                }
7233
42.8k
                break;
7234
8.07k
            default:
7235
8.07k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7236
8.07k
        cur->nodesetval->nodeTab[i]));
7237
8.07k
                xmlXPathLocalNameFunction(ctxt, 1);
7238
50.9k
        }
7239
50.9k
    }
7240
89.2k
    xmlXPathReleaseObject(ctxt->context, cur);
7241
89.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
3.37M
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7281
3.37M
    xmlXPathObjectPtr cur;
7282
3.37M
    xmlChar *stringval;
7283
7284
3.37M
    if (ctxt == NULL) return;
7285
3.37M
    if (nargs == 0) {
7286
627
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7287
627
        if (stringval == NULL)
7288
3
            xmlXPathPErrMemory(ctxt);
7289
627
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7290
627
  return;
7291
627
    }
7292
7293
13.4M
    CHECK_ARITY(1);
7294
13.4M
    cur = xmlXPathValuePop(ctxt);
7295
13.4M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7296
3.37M
    if (cur->type != XPATH_STRING) {
7297
1.72M
        stringval = xmlXPathCastToString(cur);
7298
1.72M
        if (stringval == NULL)
7299
1.18k
            xmlXPathPErrMemory(ctxt);
7300
1.72M
        xmlXPathReleaseObject(ctxt->context, cur);
7301
1.72M
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7302
1.72M
    }
7303
3.37M
    xmlXPathValuePush(ctxt, cur);
7304
3.37M
}
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
678
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7319
678
    xmlXPathObjectPtr cur;
7320
7321
678
    if (nargs == 0) {
7322
58
        if ((ctxt == NULL) || (ctxt->context == NULL))
7323
0
      return;
7324
58
  if (ctxt->context->node == NULL) {
7325
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7326
58
  } else {
7327
58
      xmlChar *content;
7328
7329
58
      content = xmlXPathCastNodeToString(ctxt->context->node);
7330
58
            if (content == NULL)
7331
2
                xmlXPathPErrMemory(ctxt);
7332
58
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7333
58
    xmlUTF8Strlen(content)));
7334
58
      xmlFree(content);
7335
58
  }
7336
58
  return;
7337
58
    }
7338
2.48k
    CHECK_ARITY(1);
7339
2.48k
    CAST_TO_STRING;
7340
2.48k
    CHECK_TYPE(XPATH_STRING);
7341
618
    cur = xmlXPathValuePop(ctxt);
7342
618
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7343
618
  xmlUTF8Strlen(cur->stringval)));
7344
618
    xmlXPathReleaseObject(ctxt->context, cur);
7345
618
}
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.00k
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7357
1.00k
    xmlXPathObjectPtr cur, newobj;
7358
1.00k
    xmlChar *tmp;
7359
7360
1.00k
    if (ctxt == NULL) return;
7361
1.00k
    if (nargs < 2) {
7362
67
  CHECK_ARITY(2);
7363
67
    }
7364
7365
935
    CAST_TO_STRING;
7366
935
    cur = xmlXPathValuePop(ctxt);
7367
935
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7368
0
  xmlXPathReleaseObject(ctxt->context, cur);
7369
0
  return;
7370
0
    }
7371
935
    nargs--;
7372
7373
2.21k
    while (nargs > 0) {
7374
1.27k
  CAST_TO_STRING;
7375
1.27k
  newobj = xmlXPathValuePop(ctxt);
7376
1.27k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7377
0
      xmlXPathReleaseObject(ctxt->context, newobj);
7378
0
      xmlXPathReleaseObject(ctxt->context, cur);
7379
0
      XP_ERROR(XPATH_INVALID_TYPE);
7380
0
  }
7381
1.27k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7382
1.27k
        if (tmp == NULL)
7383
16
            xmlXPathPErrMemory(ctxt);
7384
1.27k
  newobj->stringval = cur->stringval;
7385
1.27k
  cur->stringval = tmp;
7386
1.27k
  xmlXPathReleaseObject(ctxt->context, newobj);
7387
1.27k
  nargs--;
7388
1.27k
    }
7389
935
    xmlXPathValuePush(ctxt, cur);
7390
935
}
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
5.26k
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7403
5.26k
    xmlXPathObjectPtr hay, needle;
7404
7405
15.7k
    CHECK_ARITY(2);
7406
15.7k
    CAST_TO_STRING;
7407
15.7k
    CHECK_TYPE(XPATH_STRING);
7408
5.25k
    needle = xmlXPathValuePop(ctxt);
7409
5.25k
    CAST_TO_STRING;
7410
5.25k
    hay = xmlXPathValuePop(ctxt);
7411
7412
5.25k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7413
4
  xmlXPathReleaseObject(ctxt->context, hay);
7414
4
  xmlXPathReleaseObject(ctxt->context, needle);
7415
4
  XP_ERROR(XPATH_INVALID_TYPE);
7416
0
    }
7417
5.24k
    if (xmlStrstr(hay->stringval, needle->stringval))
7418
2.09k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7419
3.15k
    else
7420
3.15k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7421
5.24k
    xmlXPathReleaseObject(ctxt->context, hay);
7422
5.24k
    xmlXPathReleaseObject(ctxt->context, needle);
7423
5.24k
}
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
12.2k
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7436
12.2k
    xmlXPathObjectPtr hay, needle;
7437
12.2k
    int n;
7438
7439
35.8k
    CHECK_ARITY(2);
7440
35.8k
    CAST_TO_STRING;
7441
35.8k
    CHECK_TYPE(XPATH_STRING);
7442
11.8k
    needle = xmlXPathValuePop(ctxt);
7443
11.8k
    CAST_TO_STRING;
7444
11.8k
    hay = xmlXPathValuePop(ctxt);
7445
7446
11.8k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7447
4
  xmlXPathReleaseObject(ctxt->context, hay);
7448
4
  xmlXPathReleaseObject(ctxt->context, needle);
7449
4
  XP_ERROR(XPATH_INVALID_TYPE);
7450
0
    }
7451
11.7k
    n = xmlStrlen(needle->stringval);
7452
11.7k
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7453
9.33k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7454
2.46k
    else
7455
2.46k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7456
11.7k
    xmlXPathReleaseObject(ctxt->context, hay);
7457
11.7k
    xmlXPathReleaseObject(ctxt->context, needle);
7458
11.7k
}
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
8.89k
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7489
8.89k
    xmlXPathObjectPtr str, start, len;
7490
8.89k
    double le=0, in;
7491
8.89k
    int i = 1, j = INT_MAX;
7492
7493
8.89k
    if (nargs < 2) {
7494
650
  CHECK_ARITY(2);
7495
650
    }
7496
8.24k
    if (nargs > 3) {
7497
37
  CHECK_ARITY(3);
7498
37
    }
7499
    /*
7500
     * take care of possible last (position) argument
7501
    */
7502
8.20k
    if (nargs == 3) {
7503
3.10k
  CAST_TO_NUMBER;
7504
3.10k
  CHECK_TYPE(XPATH_NUMBER);
7505
3.10k
  len = xmlXPathValuePop(ctxt);
7506
3.10k
  le = len->floatval;
7507
3.10k
  xmlXPathReleaseObject(ctxt->context, len);
7508
3.10k
    }
7509
7510
8.20k
    CAST_TO_NUMBER;
7511
8.20k
    CHECK_TYPE(XPATH_NUMBER);
7512
8.20k
    start = xmlXPathValuePop(ctxt);
7513
8.20k
    in = start->floatval;
7514
8.20k
    xmlXPathReleaseObject(ctxt->context, start);
7515
8.20k
    CAST_TO_STRING;
7516
8.20k
    CHECK_TYPE(XPATH_STRING);
7517
8.20k
    str = xmlXPathValuePop(ctxt);
7518
7519
8.20k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7520
1.24k
        i = INT_MAX;
7521
6.95k
    } else if (in >= 1.0) {
7522
4.99k
        i = (int)in;
7523
4.99k
        if (in - floor(in) >= 0.5)
7524
191
            i += 1;
7525
4.99k
    }
7526
7527
8.20k
    if (nargs == 3) {
7528
3.10k
        double rin, rle, end;
7529
7530
3.10k
        rin = floor(in);
7531
3.10k
        if (in - rin >= 0.5)
7532
934
            rin += 1.0;
7533
7534
3.10k
        rle = floor(le);
7535
3.10k
        if (le - rle >= 0.5)
7536
84
            rle += 1.0;
7537
7538
3.10k
        end = rin + rle;
7539
3.10k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7540
1.15k
            j = 1;
7541
1.95k
        } else if (end < INT_MAX) {
7542
1.84k
            j = (int)end;
7543
1.84k
        }
7544
3.10k
    }
7545
7546
8.20k
    i -= 1;
7547
8.20k
    j -= 1;
7548
7549
8.20k
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7550
3.96k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7551
3.96k
        if (ret == NULL)
7552
1
            xmlXPathPErrMemory(ctxt);
7553
3.96k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7554
3.96k
  xmlFree(ret);
7555
4.23k
    } else {
7556
4.23k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7557
4.23k
    }
7558
7559
8.20k
    xmlXPathReleaseObject(ctxt->context, str);
7560
8.20k
}
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.67k
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7576
1.67k
    xmlXPathObjectPtr str = NULL;
7577
1.67k
    xmlXPathObjectPtr find = NULL;
7578
1.67k
    const xmlChar *point;
7579
1.67k
    xmlChar *result;
7580
7581
4.26k
    CHECK_ARITY(2);
7582
4.26k
    CAST_TO_STRING;
7583
4.26k
    find = xmlXPathValuePop(ctxt);
7584
4.26k
    CAST_TO_STRING;
7585
4.26k
    str = xmlXPathValuePop(ctxt);
7586
4.26k
    if (ctxt->error != 0)
7587
3
        goto error;
7588
7589
1.28k
    point = xmlStrstr(str->stringval, find->stringval);
7590
1.28k
    if (point == NULL) {
7591
700
        result = xmlStrdup(BAD_CAST "");
7592
700
    } else {
7593
589
        result = xmlStrndup(str->stringval, point - str->stringval);
7594
589
    }
7595
1.28k
    if (result == NULL) {
7596
1
        xmlXPathPErrMemory(ctxt);
7597
1
        goto error;
7598
1
    }
7599
1.28k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7600
7601
1.29k
error:
7602
1.29k
    xmlXPathReleaseObject(ctxt->context, str);
7603
1.29k
    xmlXPathReleaseObject(ctxt->context, find);
7604
1.29k
}
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
11.2k
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7621
11.2k
    xmlXPathObjectPtr str = NULL;
7622
11.2k
    xmlXPathObjectPtr find = NULL;
7623
11.2k
    const xmlChar *point;
7624
11.2k
    xmlChar *result;
7625
7626
32.7k
    CHECK_ARITY(2);
7627
32.7k
    CAST_TO_STRING;
7628
32.7k
    find = xmlXPathValuePop(ctxt);
7629
32.7k
    CAST_TO_STRING;
7630
32.7k
    str = xmlXPathValuePop(ctxt);
7631
32.7k
    if (ctxt->error != 0)
7632
8
        goto error;
7633
7634
10.7k
    point = xmlStrstr(str->stringval, find->stringval);
7635
10.7k
    if (point == NULL) {
7636
2.55k
        result = xmlStrdup(BAD_CAST "");
7637
8.23k
    } else {
7638
8.23k
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7639
8.23k
    }
7640
10.7k
    if (result == NULL) {
7641
2
        xmlXPathPErrMemory(ctxt);
7642
2
        goto error;
7643
2
    }
7644
10.7k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7645
7646
10.7k
error:
7647
10.7k
    xmlXPathReleaseObject(ctxt->context, str);
7648
10.7k
    xmlXPathReleaseObject(ctxt->context, find);
7649
10.7k
}
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
106k
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7666
106k
    xmlChar *source, *target;
7667
106k
    int blank;
7668
7669
106k
    if (ctxt == NULL) return;
7670
106k
    if (nargs == 0) {
7671
        /* Use current context node */
7672
80.6k
        source = xmlXPathCastNodeToString(ctxt->context->node);
7673
80.6k
        if (source == NULL)
7674
325
            xmlXPathPErrMemory(ctxt);
7675
80.6k
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7676
80.6k
        nargs = 1;
7677
80.6k
    }
7678
7679
319k
    CHECK_ARITY(1);
7680
319k
    CAST_TO_STRING;
7681
319k
    CHECK_TYPE(XPATH_STRING);
7682
106k
    source = ctxt->value->stringval;
7683
106k
    if (source == NULL)
7684
540
        return;
7685
105k
    target = source;
7686
7687
    /* Skip leading whitespaces */
7688
105k
    while (IS_BLANK_CH(*source))
7689
83.4k
        source++;
7690
7691
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7692
105k
    blank = 0;
7693
2.15M
    while (*source) {
7694
2.05M
        if (IS_BLANK_CH(*source)) {
7695
264k
      blank = 1;
7696
1.78M
        } else {
7697
1.78M
            if (blank) {
7698
105k
                *target++ = 0x20;
7699
105k
                blank = 0;
7700
105k
            }
7701
1.78M
            *target++ = *source;
7702
1.78M
        }
7703
2.05M
        source++;
7704
2.05M
    }
7705
105k
    *target = 0;
7706
105k
}
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
763
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7731
763
    xmlXPathObjectPtr str = NULL;
7732
763
    xmlXPathObjectPtr from = NULL;
7733
763
    xmlXPathObjectPtr to = NULL;
7734
763
    xmlBufPtr target;
7735
763
    int offset, max;
7736
763
    int ch;
7737
763
    const xmlChar *point;
7738
763
    xmlChar *cptr, *content;
7739
7740
2.11k
    CHECK_ARITY(3);
7741
7742
2.11k
    CAST_TO_STRING;
7743
2.11k
    to = xmlXPathValuePop(ctxt);
7744
2.11k
    CAST_TO_STRING;
7745
2.11k
    from = xmlXPathValuePop(ctxt);
7746
2.11k
    CAST_TO_STRING;
7747
2.11k
    str = xmlXPathValuePop(ctxt);
7748
2.11k
    if (ctxt->error != 0)
7749
3
        goto error;
7750
7751
    /*
7752
     * Account for quadratic runtime
7753
     */
7754
671
    if (ctxt->context->opLimit != 0) {
7755
671
        unsigned long f1 = xmlStrlen(from->stringval);
7756
671
        unsigned long f2 = xmlStrlen(str->stringval);
7757
7758
671
        if ((f1 > 0) && (f2 > 0)) {
7759
365
            unsigned long p;
7760
7761
365
            f1 = f1 / 10 + 1;
7762
365
            f2 = f2 / 10 + 1;
7763
365
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7764
365
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7765
3
                goto error;
7766
365
        }
7767
671
    }
7768
7769
668
    target = xmlBufCreate(50);
7770
668
    if (target == NULL) {
7771
2
        xmlXPathPErrMemory(ctxt);
7772
2
        goto error;
7773
2
    }
7774
7775
666
    max = xmlUTF8Strlen(to->stringval);
7776
11.6k
    for (cptr = str->stringval; (ch=*cptr); ) {
7777
11.0k
        offset = xmlUTF8Strloc(from->stringval, cptr);
7778
11.0k
        if (offset >= 0) {
7779
4.15k
            if (offset < max) {
7780
2.87k
                point = xmlUTF8Strpos(to->stringval, offset);
7781
2.87k
                if (point)
7782
2.87k
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7783
2.87k
            }
7784
4.15k
        } else
7785
6.84k
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7786
7787
        /* Step to next character in input */
7788
11.0k
        cptr++;
7789
11.0k
        if ( ch & 0x80 ) {
7790
            /* if not simple ascii, verify proper format */
7791
84
            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
185
            while ( (ch <<= 1) & 0x80 )
7797
101
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7798
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7799
0
                    break;
7800
0
                }
7801
84
            if (ch & 0x80) /* must have had error encountered */
7802
0
                break;
7803
84
        }
7804
11.0k
    }
7805
7806
666
    content = xmlBufDetach(target);
7807
666
    if (content == NULL)
7808
9
        xmlXPathPErrMemory(ctxt);
7809
657
    else
7810
657
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7811
666
    xmlBufFree(target);
7812
674
error:
7813
674
    xmlXPathReleaseObject(ctxt->context, str);
7814
674
    xmlXPathReleaseObject(ctxt->context, from);
7815
674
    xmlXPathReleaseObject(ctxt->context, to);
7816
674
}
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
617k
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7832
617k
    xmlXPathObjectPtr cur;
7833
7834
1.84M
    CHECK_ARITY(1);
7835
1.84M
    cur = xmlXPathValuePop(ctxt);
7836
1.84M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7837
615k
    if (cur->type != XPATH_BOOLEAN) {
7838
355k
        int boolval = xmlXPathCastToBoolean(cur);
7839
7840
355k
        xmlXPathReleaseObject(ctxt->context, cur);
7841
355k
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7842
355k
    }
7843
615k
    xmlXPathValuePush(ctxt, cur);
7844
615k
}
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
1.10k
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7857
3.23k
    CHECK_ARITY(1);
7858
3.23k
    CAST_TO_BOOLEAN;
7859
3.23k
    CHECK_TYPE(XPATH_BOOLEAN);
7860
1.02k
    ctxt->value->boolval = ! ctxt->value->boolval;
7861
1.02k
}
7862
7863
/**
7864
 * Implement the true() XPath function
7865
 *    boolean true()
7866
 *
7867
 * @param ctxt  the XPath Parser context
7868
 * @param nargs  the number of arguments
7869
 */
7870
void
7871
1.88k
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7872
5.65k
    CHECK_ARITY(0);
7873
5.65k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7874
5.65k
}
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
533
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7885
1.41k
    CHECK_ARITY(0);
7886
1.41k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7887
1.41k
}
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
18.9k
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7911
18.9k
    xmlXPathObjectPtr val;
7912
18.9k
    xmlNodePtr cur;
7913
18.9k
    xmlChar *theLang;
7914
18.9k
    const xmlChar *lang;
7915
18.9k
    int ret = 0;
7916
18.9k
    int i;
7917
7918
55.4k
    CHECK_ARITY(1);
7919
55.4k
    CAST_TO_STRING;
7920
55.4k
    CHECK_TYPE(XPATH_STRING);
7921
18.0k
    val = xmlXPathValuePop(ctxt);
7922
18.0k
    lang = val->stringval;
7923
18.0k
    cur = ctxt->context->node;
7924
86.9k
    while (cur != NULL) {
7925
68.8k
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7926
68.8k
                                &theLang) < 0)
7927
0
            xmlXPathPErrMemory(ctxt);
7928
68.8k
        if (theLang != NULL)
7929
0
            break;
7930
68.8k
        cur = cur->parent;
7931
68.8k
    }
7932
18.0k
    if ((theLang != NULL) && (lang != NULL)) {
7933
0
        for (i = 0;lang[i] != 0;i++)
7934
0
            if (toupper(lang[i]) != toupper(theLang[i]))
7935
0
                goto not_equal;
7936
0
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7937
0
            ret = 1;
7938
0
    }
7939
18.0k
not_equal:
7940
18.0k
    if (theLang != NULL)
7941
0
  xmlFree((void *)theLang);
7942
7943
18.0k
    xmlXPathReleaseObject(ctxt->context, val);
7944
18.0k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7945
18.0k
}
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.48M
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7956
1.48M
    xmlXPathObjectPtr cur;
7957
1.48M
    double res;
7958
7959
1.48M
    if (ctxt == NULL) return;
7960
1.48M
    if (nargs == 0) {
7961
584
  if (ctxt->context->node == NULL) {
7962
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7963
584
  } else {
7964
584
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7965
584
            if (content == NULL)
7966
1
                xmlXPathPErrMemory(ctxt);
7967
7968
584
      res = xmlXPathStringEvalNumber(content);
7969
584
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
7970
584
      xmlFree(content);
7971
584
  }
7972
584
  return;
7973
584
    }
7974
7975
5.94M
    CHECK_ARITY(1);
7976
5.94M
    cur = xmlXPathValuePop(ctxt);
7977
5.94M
    if (cur->type != XPATH_NUMBER) {
7978
1.48M
        double floatval;
7979
7980
1.48M
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
7981
1.48M
        xmlXPathReleaseObject(ctxt->context, cur);
7982
1.48M
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
7983
1.48M
    }
7984
5.94M
    xmlXPathValuePush(ctxt, cur);
7985
5.94M
}
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
6.19k
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
7998
6.19k
    xmlXPathObjectPtr cur;
7999
6.19k
    int i;
8000
6.19k
    double res = 0.0;
8001
8002
12.4k
    CHECK_ARITY(1);
8003
12.4k
    if ((ctxt->value == NULL) ||
8004
3.12k
  ((ctxt->value->type != XPATH_NODESET) &&
8005
3.12k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8006
3.12k
  XP_ERROR(XPATH_INVALID_TYPE);
8007
3.12k
    cur = xmlXPathValuePop(ctxt);
8008
8009
3.12k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8010
7.18k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8011
6.89k
      res += xmlXPathNodeToNumberInternal(ctxt,
8012
6.89k
                                                cur->nodesetval->nodeTab[i]);
8013
6.89k
  }
8014
292
    }
8015
3.12k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8016
3.12k
    xmlXPathReleaseObject(ctxt->context, cur);
8017
3.12k
}
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
21.0k
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
58.6k
    CHECK_ARITY(1);
8031
58.6k
    CAST_TO_NUMBER;
8032
58.6k
    CHECK_TYPE(XPATH_NUMBER);
8033
8034
18.7k
    ctxt->value->floatval = floor(ctxt->value->floatval);
8035
18.7k
}
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
839
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8048
2.49k
    CHECK_ARITY(1);
8049
2.49k
    CAST_TO_NUMBER;
8050
2.49k
    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
828
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8057
828
#endif
8058
828
}
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
0
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8072
0
    double f;
8073
8074
0
    CHECK_ARITY(1);
8075
0
    CAST_TO_NUMBER;
8076
0
    CHECK_TYPE(XPATH_NUMBER);
8077
8078
0
    f = ctxt->value->floatval;
8079
8080
0
    if ((f >= -0.5) && (f < 0.5)) {
8081
        /* Handles negative zero. */
8082
0
        ctxt->value->floatval *= 0.0;
8083
0
    }
8084
0
    else {
8085
0
        double rounded = floor(f);
8086
0
        if (f - rounded >= 0.5)
8087
0
            rounded += 1.0;
8088
0
        ctxt->value->floatval = rounded;
8089
0
    }
8090
0
}
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
3.09M
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8116
3.09M
    const xmlChar *end;
8117
3.09M
    xmlChar *ret;
8118
8119
3.09M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8120
8121
3.09M
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8122
3.09M
    if (end == NULL) {
8123
261
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8124
0
    }
8125
3.09M
    if (end == ctxt->cur)
8126
196k
        return(NULL);
8127
8128
2.90M
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8129
2.90M
    if (ret == NULL)
8130
196
        xmlXPathPErrMemory(ctxt);
8131
2.90M
    ctxt->cur = end;
8132
2.90M
    return(ret);
8133
3.09M
}
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
648k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8147
648k
    xmlChar *ret = NULL;
8148
8149
648k
    *prefix = NULL;
8150
648k
    ret = xmlXPathParseNCName(ctxt);
8151
648k
    if (ret && CUR == ':') {
8152
309k
        *prefix = ret;
8153
309k
  NEXT;
8154
309k
  ret = xmlXPathParseNCName(ctxt);
8155
309k
    }
8156
648k
    return(ret);
8157
648k
}
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
53.4k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8168
53.4k
    const xmlChar *end;
8169
53.4k
    xmlChar *ret;
8170
8171
53.4k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8172
8173
53.4k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8174
53.4k
    if (end == NULL) {
8175
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8176
0
    }
8177
53.4k
    if (end == ctxt->cur)
8178
7.43k
        return(NULL);
8179
8180
45.9k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8181
45.9k
    if (ret == NULL)
8182
3
        xmlXPathPErrMemory(ctxt);
8183
45.9k
    ctxt->cur = end;
8184
45.9k
    return(ret);
8185
53.4k
}
8186
8187
109k
#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
2.20M
xmlXPathStringEvalNumber(const xmlChar *str) {
8205
2.20M
    const xmlChar *cur = str;
8206
2.20M
    double ret;
8207
2.20M
    int ok = 0;
8208
2.20M
    int isneg = 0;
8209
2.20M
    int exponent = 0;
8210
2.20M
    int is_exponent_negative = 0;
8211
2.20M
#ifdef __GNUC__
8212
2.20M
    unsigned long tmp = 0;
8213
2.20M
    double temp;
8214
2.20M
#endif
8215
2.20M
    if (cur == NULL) return(0);
8216
2.20M
    while (IS_BLANK_CH(*cur)) cur++;
8217
2.20M
    if (*cur == '-') {
8218
32.8k
  isneg = 1;
8219
32.8k
  cur++;
8220
32.8k
    }
8221
2.20M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8222
2.01M
        return(xmlXPathNAN);
8223
2.01M
    }
8224
8225
185k
#ifdef __GNUC__
8226
    /*
8227
     * tmp/temp is a workaround against a gcc compiler bug
8228
     * http://veillard.com/gcc.bug
8229
     */
8230
185k
    ret = 0;
8231
492k
    while ((*cur >= '0') && (*cur <= '9')) {
8232
306k
  ret = ret * 10;
8233
306k
  tmp = (*cur - '0');
8234
306k
  ok = 1;
8235
306k
  cur++;
8236
306k
  temp = (double) tmp;
8237
306k
  ret = ret + temp;
8238
306k
    }
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
185k
    if (*cur == '.') {
8249
117k
  int v, frac = 0, max;
8250
117k
  double fraction = 0;
8251
8252
117k
        cur++;
8253
117k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8254
30.8k
      return(xmlXPathNAN);
8255
30.8k
  }
8256
167k
        while (*cur == '0') {
8257
81.2k
      frac = frac + 1;
8258
81.2k
      cur++;
8259
81.2k
        }
8260
86.4k
        max = frac + MAX_FRAC;
8261
163k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8262
77.5k
      v = (*cur - '0');
8263
77.5k
      fraction = fraction * 10 + v;
8264
77.5k
      frac = frac + 1;
8265
77.5k
      cur++;
8266
77.5k
  }
8267
86.4k
  fraction /= pow(10.0, frac);
8268
86.4k
  ret = ret + fraction;
8269
97.3k
  while ((*cur >= '0') && (*cur <= '9'))
8270
10.8k
      cur++;
8271
86.4k
    }
8272
155k
    if ((*cur == 'e') || (*cur == 'E')) {
8273
6.13k
      cur++;
8274
6.13k
      if (*cur == '-') {
8275
601
  is_exponent_negative = 1;
8276
601
  cur++;
8277
5.52k
      } else if (*cur == '+') {
8278
3.07k
        cur++;
8279
3.07k
      }
8280
56.8k
      while ((*cur >= '0') && (*cur <= '9')) {
8281
50.7k
        if (exponent < 1000000)
8282
26.6k
    exponent = exponent * 10 + (*cur - '0');
8283
50.7k
  cur++;
8284
50.7k
      }
8285
6.13k
    }
8286
155k
    while (IS_BLANK_CH(*cur)) cur++;
8287
155k
    if (*cur != 0) return(xmlXPathNAN);
8288
123k
    if (isneg) ret = -ret;
8289
123k
    if (is_exponent_negative) exponent = -exponent;
8290
123k
    ret *= pow(10.0, (double)exponent);
8291
123k
    return(ret);
8292
155k
}
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
329k
{
8306
329k
    double ret = 0.0;
8307
329k
    int ok = 0;
8308
329k
    int exponent = 0;
8309
329k
    int is_exponent_negative = 0;
8310
329k
    xmlXPathObjectPtr num;
8311
329k
#ifdef __GNUC__
8312
329k
    unsigned long tmp = 0;
8313
329k
    double temp;
8314
329k
#endif
8315
8316
329k
    CHECK_ERROR;
8317
328k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8318
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8319
0
    }
8320
328k
#ifdef __GNUC__
8321
    /*
8322
     * tmp/temp is a workaround against a gcc compiler bug
8323
     * http://veillard.com/gcc.bug
8324
     */
8325
328k
    ret = 0;
8326
2.06M
    while ((CUR >= '0') && (CUR <= '9')) {
8327
1.73M
  ret = ret * 10;
8328
1.73M
  tmp = (CUR - '0');
8329
1.73M
        ok = 1;
8330
1.73M
        NEXT;
8331
1.73M
  temp = (double) tmp;
8332
1.73M
  ret = ret + temp;
8333
1.73M
    }
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
328k
    if (CUR == '.') {
8343
23.1k
  int v, frac = 0, max;
8344
23.1k
  double fraction = 0;
8345
8346
23.1k
        NEXT;
8347
23.1k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8348
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8349
0
        }
8350
38.3k
        while (CUR == '0') {
8351
15.2k
            frac = frac + 1;
8352
15.2k
            NEXT;
8353
15.2k
        }
8354
23.1k
        max = frac + MAX_FRAC;
8355
58.3k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8356
35.2k
      v = (CUR - '0');
8357
35.2k
      fraction = fraction * 10 + v;
8358
35.2k
      frac = frac + 1;
8359
35.2k
            NEXT;
8360
35.2k
        }
8361
23.1k
        fraction /= pow(10.0, frac);
8362
23.1k
        ret = ret + fraction;
8363
35.5k
        while ((CUR >= '0') && (CUR <= '9'))
8364
12.3k
            NEXT;
8365
23.1k
    }
8366
328k
    if ((CUR == 'e') || (CUR == 'E')) {
8367
28.8k
        NEXT;
8368
28.8k
        if (CUR == '-') {
8369
321
            is_exponent_negative = 1;
8370
321
            NEXT;
8371
28.5k
        } else if (CUR == '+') {
8372
21.1k
      NEXT;
8373
21.1k
  }
8374
150k
        while ((CUR >= '0') && (CUR <= '9')) {
8375
121k
            if (exponent < 1000000)
8376
91.9k
                exponent = exponent * 10 + (CUR - '0');
8377
121k
            NEXT;
8378
121k
        }
8379
28.8k
        if (is_exponent_negative)
8380
321
            exponent = -exponent;
8381
28.8k
        ret *= pow(10.0, (double) exponent);
8382
28.8k
    }
8383
328k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8384
328k
    if (num == NULL) {
8385
26
  ctxt->error = XPATH_MEMORY_ERROR;
8386
328k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8387
328k
                              NULL) == -1) {
8388
12
        xmlXPathReleaseObject(ctxt->context, num);
8389
12
    }
8390
328k
}
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
107k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8403
107k
    const xmlChar *q;
8404
107k
    xmlChar *ret = NULL;
8405
107k
    int quote;
8406
8407
107k
    if (CUR == '"') {
8408
42.7k
        quote = '"';
8409
64.8k
    } else if (CUR == '\'') {
8410
63.9k
        quote = '\'';
8411
63.9k
    } else {
8412
897
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8413
0
    }
8414
8415
106k
    NEXT;
8416
106k
    q = CUR_PTR;
8417
2.28M
    while (CUR != quote) {
8418
2.18M
        int ch;
8419
2.18M
        int len = 4;
8420
8421
2.18M
        if (CUR == 0)
8422
2.18M
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8423
2.18M
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8424
2.18M
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8425
2.18M
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8426
2.18M
        CUR_PTR += len;
8427
2.18M
    }
8428
100k
    ret = xmlStrndup(q, CUR_PTR - q);
8429
100k
    if (ret == NULL)
8430
2
        xmlXPathPErrMemory(ctxt);
8431
100k
    NEXT;
8432
100k
    return(ret);
8433
106k
}
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
105k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8447
105k
    xmlChar *ret = NULL;
8448
105k
    xmlXPathObjectPtr lit;
8449
8450
105k
    ret = xmlXPathParseLiteral(ctxt);
8451
105k
    if (ret == NULL)
8452
5.59k
        return;
8453
99.7k
    lit = xmlXPathCacheNewString(ctxt, ret);
8454
99.7k
    if (lit == NULL) {
8455
6
        ctxt->error = XPATH_MEMORY_ERROR;
8456
99.7k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8457
99.7k
                              NULL) == -1) {
8458
2
        xmlXPathReleaseObject(ctxt->context, lit);
8459
2
    }
8460
99.7k
    xmlFree(ret);
8461
99.7k
}
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
82.0k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8480
82.0k
    xmlChar *name;
8481
82.0k
    xmlChar *prefix;
8482
8483
82.0k
    SKIP_BLANKS;
8484
82.0k
    if (CUR != '$') {
8485
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8486
0
    }
8487
82.0k
    NEXT;
8488
82.0k
    name = xmlXPathParseQName(ctxt, &prefix);
8489
82.0k
    if (name == NULL) {
8490
3.89k
        xmlFree(prefix);
8491
3.89k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8492
0
    }
8493
78.1k
    ctxt->comp->last = -1;
8494
78.1k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8495
1
        xmlFree(prefix);
8496
1
        xmlFree(name);
8497
1
    }
8498
78.1k
    SKIP_BLANKS;
8499
78.1k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8500
464
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8501
0
    }
8502
78.1k
}
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
621k
xmlXPathIsNodeType(const xmlChar *name) {
8517
621k
    if (name == NULL)
8518
0
  return(0);
8519
8520
621k
    if (xmlStrEqual(name, BAD_CAST "node"))
8521
13.1k
  return(1);
8522
608k
    if (xmlStrEqual(name, BAD_CAST "text"))
8523
12.1k
  return(1);
8524
595k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8525
868
  return(1);
8526
594k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8527
2.64k
  return(1);
8528
592k
    return(0);
8529
594k
}
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
566k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8542
566k
    xmlChar *name;
8543
566k
    xmlChar *prefix;
8544
566k
    int nbargs = 0;
8545
566k
    int sort = 1;
8546
8547
566k
    name = xmlXPathParseQName(ctxt, &prefix);
8548
566k
    if (name == NULL) {
8549
438
  xmlFree(prefix);
8550
438
  XP_ERROR(XPATH_EXPR_ERROR);
8551
0
    }
8552
566k
    SKIP_BLANKS;
8553
8554
566k
    if (CUR != '(') {
8555
1.82k
  xmlFree(name);
8556
1.82k
  xmlFree(prefix);
8557
1.82k
  XP_ERROR(XPATH_EXPR_ERROR);
8558
0
    }
8559
564k
    NEXT;
8560
564k
    SKIP_BLANKS;
8561
8562
    /*
8563
    * Optimization for count(): we don't need the node-set to be sorted.
8564
    */
8565
564k
    if ((prefix == NULL) && (name[0] == 'c') &&
8566
564k
  xmlStrEqual(name, BAD_CAST "count"))
8567
2.55k
    {
8568
2.55k
  sort = 0;
8569
2.55k
    }
8570
564k
    ctxt->comp->last = -1;
8571
564k
    if (CUR != ')') {
8572
756k
  while (CUR != 0) {
8573
739k
      int op1 = ctxt->comp->last;
8574
739k
      ctxt->comp->last = -1;
8575
739k
      xmlXPathCompileExpr(ctxt, sort);
8576
739k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8577
80.5k
    xmlFree(name);
8578
80.5k
    xmlFree(prefix);
8579
80.5k
    return;
8580
80.5k
      }
8581
658k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8582
658k
      nbargs++;
8583
658k
      if (CUR == ')') break;
8584
313k
      if (CUR != ',') {
8585
13.1k
    xmlFree(name);
8586
13.1k
    xmlFree(prefix);
8587
13.1k
    XP_ERROR(XPATH_EXPR_ERROR);
8588
0
      }
8589
300k
      NEXT;
8590
300k
      SKIP_BLANKS;
8591
300k
  }
8592
455k
    }
8593
470k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8594
11
        xmlFree(prefix);
8595
11
        xmlFree(name);
8596
11
    }
8597
470k
    NEXT;
8598
470k
    SKIP_BLANKS;
8599
470k
}
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
1.16M
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8614
1.16M
    SKIP_BLANKS;
8615
1.16M
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8616
1.08M
    else if (CUR == '(') {
8617
86.3k
  NEXT;
8618
86.3k
  SKIP_BLANKS;
8619
86.3k
  xmlXPathCompileExpr(ctxt, 1);
8620
86.3k
  CHECK_ERROR;
8621
57.6k
  if (CUR != ')') {
8622
23.4k
      XP_ERROR(XPATH_EXPR_ERROR);
8623
0
  }
8624
34.1k
  NEXT;
8625
34.1k
  SKIP_BLANKS;
8626
1.00M
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8627
329k
  xmlXPathCompNumber(ctxt);
8628
671k
    } else if ((CUR == '\'') || (CUR == '"')) {
8629
105k
  xmlXPathCompLiteral(ctxt);
8630
566k
    } else {
8631
566k
  xmlXPathCompFunctionCall(ctxt);
8632
566k
    }
8633
1.11M
    SKIP_BLANKS;
8634
1.11M
}
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
1.16M
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8652
1.16M
    xmlXPathCompPrimaryExpr(ctxt);
8653
1.16M
    CHECK_ERROR;
8654
1.01M
    SKIP_BLANKS;
8655
8656
1.11M
    while (CUR == '[') {
8657
104k
  xmlXPathCompPredicate(ctxt, 1);
8658
104k
  SKIP_BLANKS;
8659
104k
    }
8660
8661
8662
1.01M
}
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
1.83M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8674
1.83M
    const xmlChar *end;
8675
1.83M
    xmlChar *ret;
8676
8677
1.83M
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8678
1.83M
    if (end == NULL) {
8679
251
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8680
0
    }
8681
1.83M
    if (end == ctxt->cur)
8682
136k
        return(NULL);
8683
8684
1.69M
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8685
1.69M
    if (ret == NULL)
8686
82
        xmlXPathPErrMemory(ctxt);
8687
1.69M
    return(ret);
8688
1.83M
}
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
4.18M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8703
4.18M
    int lc = 1;           /* Should we branch to LocationPath ?         */
8704
4.18M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8705
8706
4.18M
    SKIP_BLANKS;
8707
4.18M
    if ((CUR == '$') || (CUR == '(') ||
8708
4.18M
  (IS_ASCII_DIGIT(CUR)) ||
8709
4.18M
        (CUR == '\'') || (CUR == '"') ||
8710
4.18M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8711
603k
  lc = 0;
8712
3.57M
    } else if (CUR == '*') {
8713
  /* relative or absolute location path */
8714
613k
  lc = 1;
8715
2.96M
    } else if (CUR == '/') {
8716
  /* relative or absolute location path */
8717
624k
  lc = 1;
8718
2.34M
    } else if (CUR == '@') {
8719
  /* relative abbreviated attribute location path */
8720
89.5k
  lc = 1;
8721
2.25M
    } else if (CUR == '.') {
8722
  /* relative abbreviated attribute location path */
8723
415k
  lc = 1;
8724
1.83M
    } 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
1.83M
  SKIP_BLANKS;
8737
1.83M
  name = xmlXPathScanName(ctxt);
8738
1.83M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8739
17.3k
      lc = 1;
8740
17.3k
      xmlFree(name);
8741
1.81M
  } else if (name != NULL) {
8742
1.68M
      int len =xmlStrlen(name);
8743
8744
8745
2.14M
      while (NXT(len) != 0) {
8746
2.04M
    if (NXT(len) == '/') {
8747
        /* element name */
8748
124k
        lc = 1;
8749
124k
        break;
8750
1.92M
    } else if (IS_BLANK_CH(NXT(len))) {
8751
        /* ignore blanks */
8752
464k
        ;
8753
1.45M
    } else if (NXT(len) == ':') {
8754
1.29k
        lc = 1;
8755
1.29k
        break;
8756
1.45M
    } else if ((NXT(len) == '(')) {
8757
        /* Node Type or Function */
8758
590k
        if (xmlXPathIsNodeType(name)) {
8759
24.2k
      lc = 1;
8760
566k
        } else {
8761
566k
      lc = 0;
8762
566k
        }
8763
590k
                    break;
8764
867k
    } else if ((NXT(len) == '[')) {
8765
        /* element name */
8766
29.6k
        lc = 1;
8767
29.6k
        break;
8768
837k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8769
837k
         (NXT(len) == '=')) {
8770
160k
        lc = 1;
8771
160k
        break;
8772
676k
    } else {
8773
676k
        lc = 1;
8774
676k
        break;
8775
676k
    }
8776
464k
    len++;
8777
464k
      }
8778
1.68M
      if (NXT(len) == 0) {
8779
    /* element name */
8780
97.4k
    lc = 1;
8781
97.4k
      }
8782
1.68M
      xmlFree(name);
8783
1.68M
  } else {
8784
      /* make sure all cases are covered explicitly */
8785
136k
      XP_ERROR(XPATH_EXPR_ERROR);
8786
0
  }
8787
1.83M
    }
8788
8789
4.04M
    if (lc) {
8790
2.87M
  if (CUR == '/') {
8791
624k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8792
2.25M
  } else {
8793
2.25M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8794
2.25M
  }
8795
2.87M
  xmlXPathCompLocationPath(ctxt);
8796
2.87M
    } else {
8797
1.16M
  xmlXPathCompFilterExpr(ctxt);
8798
1.16M
  CHECK_ERROR;
8799
1.00M
  if ((CUR == '/') && (NXT(1) == '/')) {
8800
8.74k
      SKIP(2);
8801
8.74k
      SKIP_BLANKS;
8802
8803
8.74k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8804
8.74k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8805
8806
8.74k
      xmlXPathCompRelativeLocationPath(ctxt);
8807
997k
  } else if (CUR == '/') {
8808
93.9k
      xmlXPathCompRelativeLocationPath(ctxt);
8809
93.9k
  }
8810
1.00M
    }
8811
3.88M
    SKIP_BLANKS;
8812
3.88M
}
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
3.44M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8825
3.44M
    xmlXPathCompPathExpr(ctxt);
8826
3.44M
    CHECK_ERROR;
8827
3.09M
    SKIP_BLANKS;
8828
3.83M
    while (CUR == '|') {
8829
736k
  int op1 = ctxt->comp->last;
8830
736k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8831
8832
736k
  NEXT;
8833
736k
  SKIP_BLANKS;
8834
736k
  xmlXPathCompPathExpr(ctxt);
8835
8836
736k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8837
8838
736k
  SKIP_BLANKS;
8839
736k
    }
8840
3.09M
}
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
3.44M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8853
3.44M
    int minus = 0;
8854
3.44M
    int found = 0;
8855
8856
3.44M
    SKIP_BLANKS;
8857
4.29M
    while (CUR == '-') {
8858
853k
        minus = 1 - minus;
8859
853k
  found = 1;
8860
853k
  NEXT;
8861
853k
  SKIP_BLANKS;
8862
853k
    }
8863
8864
3.44M
    xmlXPathCompUnionExpr(ctxt);
8865
3.44M
    CHECK_ERROR;
8866
3.07M
    if (found) {
8867
240k
  if (minus)
8868
157k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8869
82.8k
  else
8870
82.8k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8871
240k
    }
8872
3.07M
}
8873
8874
/**
8875
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
8876
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
8877
 *                   | MultiplicativeExpr 'div' UnaryExpr
8878
 *                   | MultiplicativeExpr 'mod' UnaryExpr
8879
 *  [34]   MultiplyOperator ::=   '*'
8880
 *
8881
 * Compile an Additive expression.
8882
 *
8883
 * @param ctxt  the XPath Parser context
8884
 */
8885
8886
static void
8887
2.82M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8888
2.82M
    xmlXPathCompUnaryExpr(ctxt);
8889
2.82M
    CHECK_ERROR;
8890
2.46M
    SKIP_BLANKS;
8891
3.07M
    while ((CUR == '*') ||
8892
3.07M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8893
3.07M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8894
621k
  int op = -1;
8895
621k
  int op1 = ctxt->comp->last;
8896
8897
621k
        if (CUR == '*') {
8898
597k
      op = 0;
8899
597k
      NEXT;
8900
597k
  } else if (CUR == 'd') {
8901
940
      op = 1;
8902
940
      SKIP(3);
8903
23.8k
  } else if (CUR == 'm') {
8904
23.8k
      op = 2;
8905
23.8k
      SKIP(3);
8906
23.8k
  }
8907
621k
  SKIP_BLANKS;
8908
621k
        xmlXPathCompUnaryExpr(ctxt);
8909
621k
  CHECK_ERROR;
8910
606k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8911
606k
  SKIP_BLANKS;
8912
606k
    }
8913
2.46M
}
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
2.44M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8927
8928
2.44M
    xmlXPathCompMultiplicativeExpr(ctxt);
8929
2.44M
    CHECK_ERROR;
8930
2.11M
    SKIP_BLANKS;
8931
2.44M
    while ((CUR == '+') || (CUR == '-')) {
8932
378k
  int plus;
8933
378k
  int op1 = ctxt->comp->last;
8934
8935
378k
        if (CUR == '+') plus = 1;
8936
257k
  else plus = 0;
8937
378k
  NEXT;
8938
378k
  SKIP_BLANKS;
8939
378k
        xmlXPathCompMultiplicativeExpr(ctxt);
8940
378k
  CHECK_ERROR;
8941
336k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8942
336k
  SKIP_BLANKS;
8943
336k
    }
8944
2.11M
}
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
2.24M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8965
2.24M
    xmlXPathCompAdditiveExpr(ctxt);
8966
2.24M
    CHECK_ERROR;
8967
1.90M
    SKIP_BLANKS;
8968
2.07M
    while ((CUR == '<') || (CUR == '>')) {
8969
200k
  int inf, strict;
8970
200k
  int op1 = ctxt->comp->last;
8971
8972
200k
        if (CUR == '<') inf = 1;
8973
195k
  else inf = 0;
8974
200k
  if (NXT(1) == '=') strict = 0;
8975
168k
  else strict = 1;
8976
200k
  NEXT;
8977
200k
  if (!strict) NEXT;
8978
200k
  SKIP_BLANKS;
8979
200k
        xmlXPathCompAdditiveExpr(ctxt);
8980
200k
  CHECK_ERROR;
8981
164k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
8982
164k
  SKIP_BLANKS;
8983
164k
    }
8984
1.90M
}
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
2.00M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9002
2.00M
    xmlXPathCompRelationalExpr(ctxt);
9003
2.00M
    CHECK_ERROR;
9004
1.66M
    SKIP_BLANKS;
9005
1.86M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9006
234k
  int eq;
9007
234k
  int op1 = ctxt->comp->last;
9008
9009
234k
        if (CUR == '=') eq = 1;
9010
40.2k
  else eq = 0;
9011
234k
  NEXT;
9012
234k
  if (!eq) NEXT;
9013
234k
  SKIP_BLANKS;
9014
234k
        xmlXPathCompRelationalExpr(ctxt);
9015
234k
  CHECK_ERROR;
9016
203k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9017
203k
  SKIP_BLANKS;
9018
203k
    }
9019
1.66M
}
9020
9021
/**
9022
 *  [22]   AndExpr ::=   EqualityExpr
9023
 *                 | AndExpr 'and' EqualityExpr
9024
 *
9025
 * Compile an AND expression.
9026
 *
9027
 * @param ctxt  the XPath Parser context
9028
 */
9029
static void
9030
1.97M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9031
1.97M
    xmlXPathCompEqualityExpr(ctxt);
9032
1.97M
    CHECK_ERROR;
9033
1.60M
    SKIP_BLANKS;
9034
1.63M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9035
36.1k
  int op1 = ctxt->comp->last;
9036
36.1k
        SKIP(3);
9037
36.1k
  SKIP_BLANKS;
9038
36.1k
        xmlXPathCompEqualityExpr(ctxt);
9039
36.1k
  CHECK_ERROR;
9040
32.1k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9041
32.1k
  SKIP_BLANKS;
9042
32.1k
    }
9043
1.60M
}
9044
9045
/**
9046
 *  [14]   Expr ::=   OrExpr
9047
 *  [21]   OrExpr ::=   AndExpr
9048
 *                 | OrExpr 'or' AndExpr
9049
 *
9050
 * Parse and compile an expression
9051
 *
9052
 * @param ctxt  the XPath Parser context
9053
 * @param sort  whether to sort the resulting node set
9054
 */
9055
static void
9056
1.97M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9057
1.97M
    xmlXPathContextPtr xpctxt = ctxt->context;
9058
9059
1.97M
    if (xpctxt != NULL) {
9060
1.97M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9061
1.93M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9062
        /*
9063
         * Parsing a single '(' pushes about 10 functions on the call stack
9064
         * before recursing!
9065
         */
9066
1.93M
        xpctxt->depth += 10;
9067
1.93M
    }
9068
9069
1.93M
    xmlXPathCompAndExpr(ctxt);
9070
1.93M
    CHECK_ERROR;
9071
1.56M
    SKIP_BLANKS;
9072
1.59M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9073
36.7k
  int op1 = ctxt->comp->last;
9074
36.7k
        SKIP(2);
9075
36.7k
  SKIP_BLANKS;
9076
36.7k
        xmlXPathCompAndExpr(ctxt);
9077
36.7k
  CHECK_ERROR;
9078
33.5k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9079
33.5k
  SKIP_BLANKS;
9080
33.5k
    }
9081
1.56M
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9082
  /* more ops could be optimized too */
9083
  /*
9084
  * This is the main place to eliminate sorting for
9085
  * operations which don't require a sorted node-set.
9086
  * E.g. count().
9087
  */
9088
1.34M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9089
1.34M
    }
9090
9091
1.56M
    if (xpctxt != NULL)
9092
1.56M
        xpctxt->depth -= 10;
9093
1.56M
}
9094
9095
/**
9096
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
9097
 *  [9]   PredicateExpr ::=   Expr
9098
 *
9099
 * Compile a predicate expression
9100
 *
9101
 * @param ctxt  the XPath Parser context
9102
 * @param filter  act as a filter
9103
 */
9104
static void
9105
241k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9106
241k
    int op1 = ctxt->comp->last;
9107
9108
241k
    SKIP_BLANKS;
9109
241k
    if (CUR != '[') {
9110
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9111
0
    }
9112
241k
    NEXT;
9113
241k
    SKIP_BLANKS;
9114
9115
241k
    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
241k
    if (! filter)
9126
136k
  xmlXPathCompileExpr(ctxt, 0);
9127
104k
    else
9128
104k
  xmlXPathCompileExpr(ctxt, 1);
9129
241k
    CHECK_ERROR;
9130
9131
225k
    if (CUR != ']') {
9132
21.4k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9133
0
    }
9134
9135
204k
    if (filter)
9136
99.9k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9137
104k
    else
9138
104k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9139
9140
204k
    NEXT;
9141
204k
    SKIP_BLANKS;
9142
204k
}
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
2.56M
         xmlChar *name) {
9170
2.56M
    int blanks;
9171
9172
2.56M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9173
0
  return(NULL);
9174
0
    }
9175
2.56M
    *type = (xmlXPathTypeVal) 0;
9176
2.56M
    *test = (xmlXPathTestVal) 0;
9177
2.56M
    *prefix = NULL;
9178
2.56M
    SKIP_BLANKS;
9179
9180
2.56M
    if ((name == NULL) && (CUR == '*')) {
9181
  /*
9182
   * All elements
9183
   */
9184
779k
  NEXT;
9185
779k
  *test = NODE_TEST_ALL;
9186
779k
  return(NULL);
9187
779k
    }
9188
9189
1.78M
    if (name == NULL)
9190
135k
  name = xmlXPathParseNCName(ctxt);
9191
1.78M
    if (name == NULL) {
9192
25.8k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9193
0
    }
9194
9195
1.76M
    blanks = IS_BLANK_CH(CUR);
9196
1.76M
    SKIP_BLANKS;
9197
1.76M
    if (CUR == '(') {
9198
245k
  NEXT;
9199
  /*
9200
   * NodeType or PI search
9201
   */
9202
245k
  if (xmlStrEqual(name, BAD_CAST "comment"))
9203
27.5k
      *type = NODE_TYPE_COMMENT;
9204
218k
  else if (xmlStrEqual(name, BAD_CAST "node"))
9205
169k
      *type = NODE_TYPE_NODE;
9206
48.3k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9207
17.1k
      *type = NODE_TYPE_PI;
9208
31.1k
  else if (xmlStrEqual(name, BAD_CAST "text"))
9209
28.2k
      *type = NODE_TYPE_TEXT;
9210
2.95k
  else {
9211
2.95k
      if (name != NULL)
9212
2.95k
    xmlFree(name);
9213
2.95k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9214
0
  }
9215
9216
242k
  *test = NODE_TEST_TYPE;
9217
9218
242k
  SKIP_BLANKS;
9219
242k
  if (*type == NODE_TYPE_PI) {
9220
      /*
9221
       * Specific case: search a PI by name.
9222
       */
9223
17.1k
      if (name != NULL)
9224
17.1k
    xmlFree(name);
9225
17.1k
      name = NULL;
9226
17.1k
      if (CUR != ')') {
9227
2.26k
    name = xmlXPathParseLiteral(ctxt);
9228
2.26k
    *test = NODE_TEST_PI;
9229
2.26k
    SKIP_BLANKS;
9230
2.26k
      }
9231
17.1k
  }
9232
242k
  if (CUR != ')') {
9233
3.13k
      if (name != NULL)
9234
1.87k
    xmlFree(name);
9235
3.13k
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9236
0
  }
9237
239k
  NEXT;
9238
239k
  return(name);
9239
242k
    }
9240
1.51M
    *test = NODE_TEST_NAME;
9241
1.51M
    if ((!blanks) && (CUR == ':')) {
9242
98.4k
  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
98.4k
  *prefix = name;
9252
9253
98.4k
  if (CUR == '*') {
9254
      /*
9255
       * All elements
9256
       */
9257
6.00k
      NEXT;
9258
6.00k
      *test = NODE_TEST_ALL;
9259
6.00k
      return(NULL);
9260
6.00k
  }
9261
9262
92.4k
  name = xmlXPathParseNCName(ctxt);
9263
92.4k
  if (name == NULL) {
9264
12.1k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9265
0
  }
9266
92.4k
    }
9267
1.49M
    return(name);
9268
1.51M
}
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
1.74M
xmlXPathIsAxisName(const xmlChar *name) {
9290
1.74M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9291
1.74M
    switch (name[0]) {
9292
113k
  case 'a':
9293
113k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9294
5.87k
    ret = AXIS_ANCESTOR;
9295
113k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9296
1.12k
    ret = AXIS_ANCESTOR_OR_SELF;
9297
113k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9298
3.11k
    ret = AXIS_ATTRIBUTE;
9299
113k
      break;
9300
116k
  case 'c':
9301
116k
      if (xmlStrEqual(name, BAD_CAST "child"))
9302
881
    ret = AXIS_CHILD;
9303
116k
      break;
9304
112k
  case 'd':
9305
112k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9306
663
    ret = AXIS_DESCENDANT;
9307
112k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9308
817
    ret = AXIS_DESCENDANT_OR_SELF;
9309
112k
      break;
9310
12.8k
  case 'f':
9311
12.8k
      if (xmlStrEqual(name, BAD_CAST "following"))
9312
816
    ret = AXIS_FOLLOWING;
9313
12.8k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9314
1
    ret = AXIS_FOLLOWING_SIBLING;
9315
12.8k
      break;
9316
376k
  case 'n':
9317
376k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9318
89.9k
    ret = AXIS_NAMESPACE;
9319
376k
      break;
9320
71.3k
  case 'p':
9321
71.3k
      if (xmlStrEqual(name, BAD_CAST "parent"))
9322
469
    ret = AXIS_PARENT;
9323
71.3k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9324
1.28k
    ret = AXIS_PRECEDING;
9325
71.3k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9326
273
    ret = AXIS_PRECEDING_SIBLING;
9327
71.3k
      break;
9328
37.7k
  case 's':
9329
37.7k
      if (xmlStrEqual(name, BAD_CAST "self"))
9330
5.15k
    ret = AXIS_SELF;
9331
37.7k
      break;
9332
1.74M
    }
9333
1.74M
    return(ret);
9334
1.74M
}
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
3.16M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9359
3.16M
    SKIP_BLANKS;
9360
3.16M
    if ((CUR == '.') && (NXT(1) == '.')) {
9361
71.2k
  SKIP(2);
9362
71.2k
  SKIP_BLANKS;
9363
71.2k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9364
71.2k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9365
3.09M
    } else if (CUR == '.') {
9366
491k
  NEXT;
9367
491k
  SKIP_BLANKS;
9368
2.60M
    } else {
9369
2.60M
  xmlChar *name = NULL;
9370
2.60M
  xmlChar *prefix = NULL;
9371
2.60M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9372
2.60M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9373
2.60M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9374
2.60M
  int op1;
9375
9376
2.60M
  if (CUR == '*') {
9377
699k
      axis = AXIS_CHILD;
9378
1.90M
  } else {
9379
1.90M
      if (name == NULL)
9380
1.90M
    name = xmlXPathParseNCName(ctxt);
9381
1.90M
      if (name != NULL) {
9382
1.74M
    axis = xmlXPathIsAxisName(name);
9383
1.74M
    if (axis != 0) {
9384
110k
        SKIP_BLANKS;
9385
110k
        if ((CUR == ':') && (NXT(1) == ':')) {
9386
93.3k
      SKIP(2);
9387
93.3k
      xmlFree(name);
9388
93.3k
      name = NULL;
9389
93.3k
        } else {
9390
      /* an element name can conflict with an axis one :-\ */
9391
17.0k
      axis = AXIS_CHILD;
9392
17.0k
        }
9393
1.63M
    } else {
9394
1.63M
        axis = AXIS_CHILD;
9395
1.63M
    }
9396
1.74M
      } else if (CUR == '@') {
9397
99.5k
    NEXT;
9398
99.5k
    axis = AXIS_ATTRIBUTE;
9399
99.5k
      } else {
9400
53.3k
    axis = AXIS_CHILD;
9401
53.3k
      }
9402
1.90M
  }
9403
9404
2.60M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9405
32.7k
            xmlFree(name);
9406
32.7k
            return;
9407
32.7k
        }
9408
9409
2.56M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9410
2.56M
  if (test == 0)
9411
28.7k
      return;
9412
9413
2.53M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9414
2.53M
      (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
2.53M
  op1 = ctxt->comp->last;
9422
2.53M
  ctxt->comp->last = -1;
9423
9424
2.53M
  SKIP_BLANKS;
9425
2.67M
  while (CUR == '[') {
9426
136k
      xmlXPathCompPredicate(ctxt, 0);
9427
136k
  }
9428
9429
2.53M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9430
2.53M
                           test, type, (void *)prefix, (void *)name) == -1) {
9431
84
            xmlFree(prefix);
9432
84
            xmlFree(name);
9433
84
        }
9434
2.53M
    }
9435
3.16M
}
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
2.83M
(xmlXPathParserContextPtr ctxt) {
9450
2.83M
    SKIP_BLANKS;
9451
2.83M
    if ((CUR == '/') && (NXT(1) == '/')) {
9452
10.0k
  SKIP(2);
9453
10.0k
  SKIP_BLANKS;
9454
10.0k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9455
10.0k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9456
2.82M
    } else if (CUR == '/') {
9457
97.0k
      NEXT;
9458
97.0k
  SKIP_BLANKS;
9459
97.0k
    }
9460
2.83M
    xmlXPathCompStep(ctxt);
9461
2.83M
    CHECK_ERROR;
9462
2.79M
    SKIP_BLANKS;
9463
3.11M
    while (CUR == '/') {
9464
323k
  if ((CUR == '/') && (NXT(1) == '/')) {
9465
63.5k
      SKIP(2);
9466
63.5k
      SKIP_BLANKS;
9467
63.5k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9468
63.5k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9469
63.5k
      xmlXPathCompStep(ctxt);
9470
259k
  } else if (CUR == '/') {
9471
259k
      NEXT;
9472
259k
      SKIP_BLANKS;
9473
259k
      xmlXPathCompStep(ctxt);
9474
259k
  }
9475
323k
  SKIP_BLANKS;
9476
323k
    }
9477
2.79M
}
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
2.87M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9493
2.87M
    SKIP_BLANKS;
9494
2.87M
    if (CUR != '/') {
9495
2.25M
        xmlXPathCompRelativeLocationPath(ctxt);
9496
2.25M
    } else {
9497
1.24M
  while (CUR == '/') {
9498
635k
      if ((CUR == '/') && (NXT(1) == '/')) {
9499
279k
    SKIP(2);
9500
279k
    SKIP_BLANKS;
9501
279k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9502
279k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9503
279k
    xmlXPathCompRelativeLocationPath(ctxt);
9504
356k
      } else if (CUR == '/') {
9505
356k
    NEXT;
9506
356k
    SKIP_BLANKS;
9507
356k
    if ((CUR != 0) &&
9508
356k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9509
352k
                     (CUR == '_') || (CUR == '.') ||
9510
352k
         (CUR == '@') || (CUR == '*')))
9511
206k
        xmlXPathCompRelativeLocationPath(ctxt);
9512
356k
      }
9513
635k
      CHECK_ERROR;
9514
635k
  }
9515
624k
    }
9516
2.87M
}
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
484k
{
9546
484k
    xmlXPathContextPtr xpctxt;
9547
484k
    xmlNodePtr oldnode;
9548
484k
    xmlDocPtr olddoc;
9549
484k
    xmlXPathStepOpPtr filterOp;
9550
484k
    int oldcs, oldpp;
9551
484k
    int i, j, pos;
9552
9553
484k
    if ((set == NULL) || (set->nodeNr == 0))
9554
214k
        return;
9555
9556
    /*
9557
    * Check if the node set contains a sufficient number of nodes for
9558
    * the requested range.
9559
    */
9560
270k
    if (set->nodeNr < minPos) {
9561
11.6k
        xmlXPathNodeSetClear(set, hasNsNodes);
9562
11.6k
        return;
9563
11.6k
    }
9564
9565
259k
    xpctxt = ctxt->context;
9566
259k
    oldnode = xpctxt->node;
9567
259k
    olddoc = xpctxt->doc;
9568
259k
    oldcs = xpctxt->contextSize;
9569
259k
    oldpp = xpctxt->proximityPosition;
9570
259k
    filterOp = &ctxt->comp->steps[filterOpIndex];
9571
9572
259k
    xpctxt->contextSize = set->nodeNr;
9573
9574
2.00M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9575
1.92M
        xmlNodePtr node = set->nodeTab[i];
9576
1.92M
        int res;
9577
9578
1.92M
        xpctxt->node = node;
9579
1.92M
        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.92M
        if ((node->type != XML_NAMESPACE_DECL) &&
9588
1.92M
            (node->doc != NULL))
9589
1.82M
            xpctxt->doc = node->doc;
9590
9591
1.92M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9592
9593
1.92M
        if (ctxt->error != XPATH_EXPRESSION_OK)
9594
40.8k
            break;
9595
1.88M
        if (res < 0) {
9596
            /* Shouldn't happen */
9597
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9598
0
            break;
9599
0
        }
9600
9601
1.88M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9602
1.18M
            if (i != j) {
9603
37.0k
                set->nodeTab[j] = node;
9604
37.0k
                set->nodeTab[i] = NULL;
9605
37.0k
            }
9606
9607
1.18M
            j += 1;
9608
1.18M
        } else {
9609
            /* Remove the entry from the initial node set. */
9610
699k
            set->nodeTab[i] = NULL;
9611
699k
            if (node->type == XML_NAMESPACE_DECL)
9612
38.5k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9613
699k
        }
9614
9615
1.88M
        if (res != 0) {
9616
1.18M
            if (pos == maxPos) {
9617
135k
                i += 1;
9618
135k
                break;
9619
135k
            }
9620
9621
1.05M
            pos += 1;
9622
1.05M
        }
9623
1.88M
    }
9624
9625
    /* Free remaining nodes. */
9626
259k
    if (hasNsNodes) {
9627
2.16M
        for (; i < set->nodeNr; i++) {
9628
2.07M
            xmlNodePtr node = set->nodeTab[i];
9629
2.07M
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9630
32.4k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9631
2.07M
        }
9632
87.1k
    }
9633
9634
259k
    set->nodeNr = j;
9635
9636
    /* If too many elements were removed, shrink table to preserve memory. */
9637
259k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9638
259k
        (set->nodeNr < set->nodeMax / 2)) {
9639
29.5k
        xmlNodePtr *tmp;
9640
29.5k
        int nodeMax = set->nodeNr;
9641
9642
29.5k
        if (nodeMax < XML_NODESET_DEFAULT)
9643
29.2k
            nodeMax = XML_NODESET_DEFAULT;
9644
29.5k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9645
29.5k
                nodeMax * sizeof(xmlNodePtr));
9646
29.5k
        if (tmp == NULL) {
9647
584
            xmlXPathPErrMemory(ctxt);
9648
28.9k
        } else {
9649
28.9k
            set->nodeTab = tmp;
9650
28.9k
            set->nodeMax = nodeMax;
9651
28.9k
        }
9652
29.5k
    }
9653
9654
259k
    xpctxt->node = oldnode;
9655
259k
    xpctxt->doc = olddoc;
9656
259k
    xpctxt->contextSize = oldcs;
9657
259k
    xpctxt->proximityPosition = oldpp;
9658
259k
}
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
207k
{
9679
207k
    if (op->ch1 != -1) {
9680
16.3k
  xmlXPathCompExprPtr comp = ctxt->comp;
9681
  /*
9682
  * Process inner predicates first.
9683
  */
9684
16.3k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9685
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9686
0
  }
9687
16.3k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9688
16.3k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9689
16.3k
        ctxt->context->depth += 1;
9690
16.3k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9691
16.3k
                                    1, set->nodeNr, hasNsNodes);
9692
16.3k
        ctxt->context->depth -= 1;
9693
16.3k
  CHECK_ERROR;
9694
16.3k
    }
9695
9696
201k
    if (op->ch2 != -1)
9697
201k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9698
201k
}
9699
9700
static int
9701
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9702
          xmlXPathStepOpPtr op,
9703
          int *maxPos)
9704
176k
{
9705
9706
176k
    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
176k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9722
0
  return(0);
9723
9724
176k
    if (op->ch2 != -1) {
9725
176k
  exprOp = &ctxt->comp->steps[op->ch2];
9726
176k
    } else
9727
0
  return(0);
9728
9729
176k
    if ((exprOp != NULL) &&
9730
176k
  (exprOp->op == XPATH_OP_VALUE) &&
9731
176k
  (exprOp->value4 != NULL) &&
9732
176k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9733
52.0k
    {
9734
52.0k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
9735
9736
  /*
9737
  * We have a "[n]" predicate here.
9738
  * TODO: Unfortunately this simplistic test here is not
9739
  * able to detect a position() predicate in compound
9740
  * expressions like "[@attr = 'a" and position() = 1],
9741
  * and even not the usage of position() in
9742
  * "[position() = 1]"; thus - obviously - a position-range,
9743
  * like it "[position() < 5]", is also not detected.
9744
  * Maybe we could rewrite the AST to ease the optimization.
9745
  */
9746
9747
52.0k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9748
51.3k
      *maxPos = (int) floatval;
9749
51.3k
            if (floatval == (double) *maxPos)
9750
48.0k
                return(1);
9751
51.3k
        }
9752
52.0k
    }
9753
128k
    return(0);
9754
176k
}
9755
9756
static int
9757
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9758
                           xmlXPathStepOpPtr op,
9759
         xmlNodePtr * first, xmlNodePtr * last,
9760
         int toBool)
9761
7.71M
{
9762
9763
7.71M
#define XP_TEST_HIT \
9764
34.9M
    if (hasAxisRange != 0) { \
9765
72.5k
  if (++pos == maxPos) { \
9766
22.6k
      if (addNode(seq, cur) < 0) \
9767
22.6k
          xmlXPathPErrMemory(ctxt); \
9768
22.6k
      goto axis_range_end; } \
9769
34.8M
    } else { \
9770
34.8M
  if (addNode(seq, cur) < 0) \
9771
34.8M
      xmlXPathPErrMemory(ctxt); \
9772
34.8M
  if (breakOnFirstHit) goto first_hit; }
9773
9774
7.71M
#define XP_TEST_HIT_NS \
9775
7.71M
    if (hasAxisRange != 0) { \
9776
47.7k
  if (++pos == maxPos) { \
9777
16.5k
      hasNsNodes = 1; \
9778
16.5k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9779
16.5k
          xmlXPathPErrMemory(ctxt); \
9780
16.5k
  goto axis_range_end; } \
9781
1.38M
    } else { \
9782
1.38M
  hasNsNodes = 1; \
9783
1.38M
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9784
1.38M
      xmlXPathPErrMemory(ctxt); \
9785
1.38M
  if (breakOnFirstHit) goto first_hit; }
9786
9787
7.71M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9788
7.71M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9789
7.71M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9790
7.71M
    const xmlChar *prefix = op->value4;
9791
7.71M
    const xmlChar *name = op->value5;
9792
7.71M
    const xmlChar *URI = NULL;
9793
9794
7.71M
    int total = 0, hasNsNodes = 0;
9795
    /* The popped object holding the context nodes */
9796
7.71M
    xmlXPathObjectPtr obj;
9797
    /* The set of context nodes for the node tests */
9798
7.71M
    xmlNodeSetPtr contextSeq;
9799
7.71M
    int contextIdx;
9800
7.71M
    xmlNodePtr contextNode;
9801
    /* The final resulting node set wrt to all context nodes */
9802
7.71M
    xmlNodeSetPtr outSeq;
9803
    /*
9804
    * The temporary resulting node set wrt 1 context node.
9805
    * Used to feed predicate evaluation.
9806
    */
9807
7.71M
    xmlNodeSetPtr seq;
9808
7.71M
    xmlNodePtr cur;
9809
    /* First predicate operator */
9810
7.71M
    xmlXPathStepOpPtr predOp;
9811
7.71M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9812
7.71M
    int hasPredicateRange, hasAxisRange, pos;
9813
7.71M
    int breakOnFirstHit;
9814
9815
7.71M
    xmlXPathTraversalFunction next = NULL;
9816
7.71M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9817
7.71M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9818
7.71M
    xmlNodePtr oldContextNode;
9819
7.71M
    xmlXPathContextPtr xpctxt = ctxt->context;
9820
9821
9822
7.71M
    CHECK_TYPE0(XPATH_NODESET);
9823
7.69M
    obj = xmlXPathValuePop(ctxt);
9824
    /*
9825
    * Setup namespaces.
9826
    */
9827
7.69M
    if (prefix != NULL) {
9828
574k
        URI = xmlXPathNsLookup(xpctxt, prefix);
9829
574k
        if (URI == NULL) {
9830
61.1k
      xmlXPathReleaseObject(xpctxt, obj);
9831
61.1k
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9832
61.1k
                           "Undefined namespace prefix: %s\n", prefix);
9833
61.1k
            return 0;
9834
61.1k
  }
9835
574k
    }
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
7.63M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9850
7.63M
    switch (axis) {
9851
29.8k
        case AXIS_ANCESTOR:
9852
29.8k
            first = NULL;
9853
29.8k
            next = xmlXPathNextAncestor;
9854
29.8k
            break;
9855
13.4k
        case AXIS_ANCESTOR_OR_SELF:
9856
13.4k
            first = NULL;
9857
13.4k
            next = xmlXPathNextAncestorOrSelf;
9858
13.4k
            break;
9859
542k
        case AXIS_ATTRIBUTE:
9860
542k
            first = NULL;
9861
542k
      last = NULL;
9862
542k
            next = xmlXPathNextAttribute;
9863
542k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9864
542k
            break;
9865
5.40M
        case AXIS_CHILD:
9866
5.40M
      last = NULL;
9867
5.40M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9868
5.40M
    (type == NODE_TYPE_NODE))
9869
5.04M
      {
9870
    /*
9871
    * Optimization if an element node type is 'element'.
9872
    */
9873
5.04M
    next = xmlXPathNextChildElement;
9874
5.04M
      } else
9875
362k
    next = xmlXPathNextChild;
9876
5.40M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9877
5.40M
            break;
9878
965k
        case AXIS_DESCENDANT:
9879
965k
      last = NULL;
9880
965k
            next = xmlXPathNextDescendant;
9881
965k
            break;
9882
243k
        case AXIS_DESCENDANT_OR_SELF:
9883
243k
      last = NULL;
9884
243k
            next = xmlXPathNextDescendantOrSelf;
9885
243k
            break;
9886
3.39k
        case AXIS_FOLLOWING:
9887
3.39k
      last = NULL;
9888
3.39k
            next = xmlXPathNextFollowing;
9889
3.39k
            break;
9890
0
        case AXIS_FOLLOWING_SIBLING:
9891
0
      last = NULL;
9892
0
            next = xmlXPathNextFollowingSibling;
9893
0
            break;
9894
184k
        case AXIS_NAMESPACE:
9895
184k
            first = NULL;
9896
184k
      last = NULL;
9897
184k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9898
184k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9899
184k
            break;
9900
233k
        case AXIS_PARENT:
9901
233k
            first = NULL;
9902
233k
            next = xmlXPathNextParent;
9903
233k
            break;
9904
5.18k
        case AXIS_PRECEDING:
9905
5.18k
            first = NULL;
9906
5.18k
            next = xmlXPathNextPrecedingInternal;
9907
5.18k
            break;
9908
9
        case AXIS_PRECEDING_SIBLING:
9909
9
            first = NULL;
9910
9
            next = xmlXPathNextPrecedingSibling;
9911
9
            break;
9912
1.44k
        case AXIS_SELF:
9913
1.44k
            first = NULL;
9914
1.44k
      last = NULL;
9915
1.44k
            next = xmlXPathNextSelf;
9916
1.44k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9917
1.44k
            break;
9918
7.63M
    }
9919
9920
7.63M
    if (next == NULL) {
9921
0
  xmlXPathReleaseObject(xpctxt, obj);
9922
0
        return(0);
9923
0
    }
9924
7.63M
    contextSeq = obj->nodesetval;
9925
7.63M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9926
702k
        xmlXPathValuePush(ctxt, obj);
9927
702k
        return(0);
9928
702k
    }
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
6.92M
    maxPos = 0;
9948
6.92M
    predOp = NULL;
9949
6.92M
    hasPredicateRange = 0;
9950
6.92M
    hasAxisRange = 0;
9951
6.92M
    if (op->ch2 != -1) {
9952
  /*
9953
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9954
  */
9955
176k
  predOp = &ctxt->comp->steps[op->ch2];
9956
176k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9957
48.0k
      if (predOp->ch1 != -1) {
9958
    /*
9959
    * Use the next inner predicate operator.
9960
    */
9961
22.8k
    predOp = &ctxt->comp->steps[predOp->ch1];
9962
22.8k
    hasPredicateRange = 1;
9963
25.1k
      } else {
9964
    /*
9965
    * There's no other predicate than the [n] predicate.
9966
    */
9967
25.1k
    predOp = NULL;
9968
25.1k
    hasAxisRange = 1;
9969
25.1k
      }
9970
48.0k
  }
9971
176k
    }
9972
6.92M
    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
6.92M
    oldContextNode = xpctxt->node;
9987
6.92M
    addNode = xmlXPathNodeSetAddUnique;
9988
6.92M
    outSeq = NULL;
9989
6.92M
    seq = NULL;
9990
6.92M
    contextNode = NULL;
9991
6.92M
    contextIdx = 0;
9992
9993
9994
17.4M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
9995
17.4M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
9996
10.5M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
9997
9998
10.5M
  if (seq == NULL) {
9999
7.01M
      seq = xmlXPathNodeSetCreate(NULL);
10000
7.01M
      if (seq == NULL) {
10001
1.22k
                xmlXPathPErrMemory(ctxt);
10002
1.22k
    total = 0;
10003
1.22k
    goto error;
10004
1.22k
      }
10005
7.01M
  }
10006
  /*
10007
  * Traverse the axis and test the nodes.
10008
  */
10009
10.5M
  pos = 0;
10010
10.5M
  cur = NULL;
10011
10.5M
  hasNsNodes = 0;
10012
56.1M
        do {
10013
56.1M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10014
2.70k
                goto error;
10015
10016
56.1M
            cur = next(ctxt, cur);
10017
56.1M
            if (cur == NULL)
10018
10.5M
                break;
10019
10020
      /*
10021
      * QUESTION TODO: What does the "first" and "last" stuff do?
10022
      */
10023
45.6M
            if ((first != NULL) && (*first != NULL)) {
10024
14.4k
    if (*first == cur)
10025
1.87k
        break;
10026
12.5k
    if (((total % 256) == 0) &&
10027
12.5k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10028
12.5k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10029
#else
10030
        (xmlXPathCmpNodes(*first, cur) >= 0))
10031
#endif
10032
7.81k
    {
10033
7.81k
        break;
10034
7.81k
    }
10035
12.5k
      }
10036
45.6M
      if ((last != NULL) && (*last != NULL)) {
10037
3.08k
    if (*last == cur)
10038
247
        break;
10039
2.84k
    if (((total % 256) == 0) &&
10040
2.84k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10041
2.84k
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10042
#else
10043
        (xmlXPathCmpNodes(cur, *last) >= 0))
10044
#endif
10045
713
    {
10046
713
        break;
10047
713
    }
10048
2.84k
      }
10049
10050
45.6M
            total++;
10051
10052
45.6M
      switch (test) {
10053
0
                case NODE_TEST_NONE:
10054
0
        total = 0;
10055
0
        goto error;
10056
33.2M
                case NODE_TEST_TYPE:
10057
33.2M
        if (type == NODE_TYPE_NODE) {
10058
31.2M
      switch (cur->type) {
10059
269k
          case XML_DOCUMENT_NODE:
10060
269k
          case XML_HTML_DOCUMENT_NODE:
10061
20.6M
          case XML_ELEMENT_NODE:
10062
20.7M
          case XML_ATTRIBUTE_NODE:
10063
21.1M
          case XML_PI_NODE:
10064
21.6M
          case XML_COMMENT_NODE:
10065
21.7M
          case XML_CDATA_SECTION_NODE:
10066
30.7M
          case XML_TEXT_NODE:
10067
30.7M
        XP_TEST_HIT
10068
30.7M
        break;
10069
30.7M
          case XML_NAMESPACE_DECL: {
10070
509k
        if (axis == AXIS_NAMESPACE) {
10071
119k
            XP_TEST_HIT_NS
10072
390k
        } else {
10073
390k
                              hasNsNodes = 1;
10074
390k
            XP_TEST_HIT
10075
390k
        }
10076
509k
        break;
10077
509k
                            }
10078
509k
          default:
10079
12.9k
        break;
10080
31.2M
      }
10081
31.2M
        } else if (cur->type == (xmlElementType) type) {
10082
323k
      if (cur->type == XML_NAMESPACE_DECL)
10083
0
          XP_TEST_HIT_NS
10084
323k
      else
10085
323k
          XP_TEST_HIT
10086
1.63M
        } else if ((type == NODE_TYPE_TEXT) &&
10087
1.63M
       (cur->type == XML_CDATA_SECTION_NODE))
10088
1
        {
10089
1
      XP_TEST_HIT
10090
1
        }
10091
33.1M
        break;
10092
33.1M
                case NODE_TEST_PI:
10093
9.10k
                    if ((cur->type == XML_PI_NODE) &&
10094
9.10k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10095
0
        {
10096
0
      XP_TEST_HIT
10097
0
                    }
10098
9.10k
                    break;
10099
5.47M
                case NODE_TEST_ALL:
10100
5.47M
                    if (axis == AXIS_ATTRIBUTE) {
10101
105k
                        if (cur->type == XML_ATTRIBUTE_NODE)
10102
105k
      {
10103
105k
                            if (prefix == NULL)
10104
68.5k
          {
10105
68.5k
        XP_TEST_HIT
10106
68.5k
                            } else if ((cur->ns != NULL) &&
10107
37.3k
        (xmlStrEqual(URI, cur->ns->href)))
10108
8.96k
          {
10109
8.96k
        XP_TEST_HIT
10110
8.96k
                            }
10111
105k
                        }
10112
5.37M
                    } else if (axis == AXIS_NAMESPACE) {
10113
1.28M
                        if (cur->type == XML_NAMESPACE_DECL)
10114
1.28M
      {
10115
1.28M
          XP_TEST_HIT_NS
10116
1.28M
                        }
10117
4.08M
                    } else {
10118
4.08M
                        if (cur->type == XML_ELEMENT_NODE) {
10119
2.77M
                            if (prefix == NULL)
10120
2.70M
          {
10121
2.70M
        XP_TEST_HIT
10122
10123
2.70M
                            } else if ((cur->ns != NULL) &&
10124
77.0k
        (xmlStrEqual(URI, cur->ns->href)))
10125
34.2k
          {
10126
34.2k
        XP_TEST_HIT
10127
34.2k
                            }
10128
2.77M
                        }
10129
4.08M
                    }
10130
5.43M
                    break;
10131
5.43M
                case NODE_TEST_NS:{
10132
                        /* TODO */
10133
0
                        break;
10134
5.47M
                    }
10135
6.95M
                case NODE_TEST_NAME:
10136
6.95M
                    if (axis == AXIS_ATTRIBUTE) {
10137
549k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10138
0
          break;
10139
6.40M
        } else if (axis == AXIS_NAMESPACE) {
10140
151k
                        if (cur->type != XML_NAMESPACE_DECL)
10141
0
          break;
10142
6.25M
        } else {
10143
6.25M
            if (cur->type != XML_ELEMENT_NODE)
10144
1.56M
          break;
10145
6.25M
        }
10146
5.38M
                    switch (cur->type) {
10147
4.68M
                        case XML_ELEMENT_NODE:
10148
4.68M
                            if (xmlStrEqual(name, cur->name)) {
10149
395k
                                if (prefix == NULL) {
10150
323k
                                    if (cur->ns == NULL)
10151
301k
            {
10152
301k
          XP_TEST_HIT
10153
301k
                                    }
10154
323k
                                } else {
10155
72.5k
                                    if ((cur->ns != NULL) &&
10156
72.5k
                                        (xmlStrEqual(URI, cur->ns->href)))
10157
21.9k
            {
10158
21.9k
          XP_TEST_HIT
10159
21.9k
                                    }
10160
72.5k
                                }
10161
395k
                            }
10162
4.67M
                            break;
10163
4.67M
                        case XML_ATTRIBUTE_NODE:{
10164
549k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10165
10166
549k
                                if (xmlStrEqual(name, attr->name)) {
10167
329k
                                    if (prefix == NULL) {
10168
329k
                                        if ((attr->ns == NULL) ||
10169
329k
                                            (attr->ns->prefix == NULL))
10170
329k
          {
10171
329k
              XP_TEST_HIT
10172
329k
                                        }
10173
329k
                                    } else {
10174
100
                                        if ((attr->ns != NULL) &&
10175
100
                                            (xmlStrEqual(URI,
10176
0
                attr->ns->href)))
10177
0
          {
10178
0
              XP_TEST_HIT
10179
0
                                        }
10180
100
                                    }
10181
329k
                                }
10182
548k
                                break;
10183
549k
                            }
10184
548k
                        case XML_NAMESPACE_DECL:
10185
151k
                            if (cur->type == XML_NAMESPACE_DECL) {
10186
151k
                                xmlNsPtr ns = (xmlNsPtr) cur;
10187
10188
151k
                                if ((ns->prefix != NULL) && (name != NULL)
10189
151k
                                    && (xmlStrEqual(ns->prefix, name)))
10190
29.5k
        {
10191
29.5k
            XP_TEST_HIT_NS
10192
29.5k
                                }
10193
151k
                            }
10194
144k
                            break;
10195
144k
                        default:
10196
0
                            break;
10197
5.38M
                    }
10198
5.37M
                    break;
10199
45.6M
      } /* switch(test) */
10200
45.6M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10201
10202
10.5M
  goto apply_predicates;
10203
10204
10.5M
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
39.1k
  if (outSeq == NULL) {
10212
11.3k
      outSeq = seq;
10213
11.3k
      seq = NULL;
10214
27.8k
  } else {
10215
27.8k
      outSeq = mergeAndClear(outSeq, seq);
10216
27.8k
            if (outSeq == NULL)
10217
5
                xmlXPathPErrMemory(ctxt);
10218
27.8k
        }
10219
  /*
10220
  * Break if only a true/false result was requested.
10221
  */
10222
39.1k
  if (toBool)
10223
3.14k
      break;
10224
36.0k
  continue;
10225
10226
36.0k
first_hit: /* ---------------------------------------------------------- */
10227
  /*
10228
  * Break if only a true/false result was requested and
10229
  * no predicates existed and a node test succeeded.
10230
  */
10231
22.9k
  if (outSeq == NULL) {
10232
22.9k
      outSeq = seq;
10233
22.9k
      seq = NULL;
10234
22.9k
  } else {
10235
0
      outSeq = mergeAndClear(outSeq, seq);
10236
0
            if (outSeq == NULL)
10237
0
                xmlXPathPErrMemory(ctxt);
10238
0
        }
10239
22.9k
  break;
10240
10241
10.5M
apply_predicates: /* --------------------------------------------------- */
10242
10.5M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10243
678
      goto error;
10244
10245
        /*
10246
  * Apply predicates.
10247
  */
10248
10.5M
        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
191k
      if (hasPredicateRange != 0)
10278
32.6k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10279
32.6k
              hasNsNodes);
10280
158k
      else
10281
158k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10282
158k
              hasNsNodes);
10283
10284
191k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10285
21.9k
    total = 0;
10286
21.9k
    goto error;
10287
21.9k
      }
10288
191k
        }
10289
10290
10.4M
        if (seq->nodeNr > 0) {
10291
      /*
10292
      * Add to result set.
10293
      */
10294
3.78M
      if (outSeq == NULL) {
10295
2.24M
    outSeq = seq;
10296
2.24M
    seq = NULL;
10297
2.24M
      } else {
10298
1.53M
    outSeq = mergeAndClear(outSeq, seq);
10299
1.53M
                if (outSeq == NULL)
10300
110
                    xmlXPathPErrMemory(ctxt);
10301
1.53M
      }
10302
10303
3.78M
            if (toBool)
10304
338
                break;
10305
3.78M
  }
10306
10.4M
    }
10307
10308
6.92M
error:
10309
6.92M
    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
6.92M
    xmlXPathReleaseObject(xpctxt, obj);
10321
10322
    /*
10323
    * Ensure we return at least an empty set.
10324
    */
10325
6.92M
    if (outSeq == NULL) {
10326
4.64M
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10327
4.64M
      outSeq = seq;
10328
4.64M
        } else {
10329
3.18k
      outSeq = xmlXPathNodeSetCreate(NULL);
10330
3.18k
            if (outSeq == NULL)
10331
1.68k
                xmlXPathPErrMemory(ctxt);
10332
3.18k
        }
10333
4.64M
    }
10334
6.92M
    if ((seq != NULL) && (seq != outSeq)) {
10335
87.6k
   xmlXPathFreeNodeSet(seq);
10336
87.6k
    }
10337
    /*
10338
    * Hand over the result. Better to push the set also in
10339
    * case of errors.
10340
    */
10341
6.92M
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10342
    /*
10343
    * Reset the context node.
10344
    */
10345
6.92M
    xpctxt->node = oldContextNode;
10346
    /*
10347
    * When traversing the namespace axis in "toBool" mode, it's
10348
    * possible that tmpNsList wasn't freed.
10349
    */
10350
6.92M
    if (xpctxt->tmpNsList != NULL) {
10351
7.73k
        xmlFree(xpctxt->tmpNsList);
10352
7.73k
        xpctxt->tmpNsList = NULL;
10353
7.73k
    }
10354
10355
6.92M
    return(total);
10356
6.92M
}
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
219k
{
10375
219k
    int total = 0, cur;
10376
219k
    xmlXPathCompExprPtr comp;
10377
219k
    xmlXPathObjectPtr arg1, arg2;
10378
10379
219k
    CHECK_ERROR0;
10380
219k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10381
1
        return(0);
10382
219k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10383
218k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10384
218k
    ctxt->context->depth += 1;
10385
218k
    comp = ctxt->comp;
10386
218k
    switch (op->op) {
10387
0
        case XPATH_OP_END:
10388
0
            break;
10389
63.8k
        case XPATH_OP_UNION:
10390
63.8k
            total =
10391
63.8k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10392
63.8k
                                        first);
10393
63.8k
      CHECK_ERROR0;
10394
54.4k
            if ((ctxt->value != NULL)
10395
54.4k
                && (ctxt->value->type == XPATH_NODESET)
10396
54.4k
                && (ctxt->value->nodesetval != NULL)
10397
54.4k
                && (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
28.8k
    if (ctxt->value->nodesetval->nodeNr > 1)
10409
1.92k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10410
28.8k
                *first = ctxt->value->nodesetval->nodeTab[0];
10411
28.8k
            }
10412
54.4k
            cur =
10413
54.4k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10414
54.4k
                                        first);
10415
54.4k
      CHECK_ERROR0;
10416
10417
50.3k
            arg2 = xmlXPathValuePop(ctxt);
10418
50.3k
            arg1 = xmlXPathValuePop(ctxt);
10419
50.3k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10420
50.3k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10421
3.96k
          xmlXPathReleaseObject(ctxt->context, arg1);
10422
3.96k
          xmlXPathReleaseObject(ctxt->context, arg2);
10423
3.96k
                XP_ERROR0(XPATH_INVALID_TYPE);
10424
0
            }
10425
46.3k
            if ((ctxt->context->opLimit != 0) &&
10426
46.3k
                (((arg1->nodesetval != NULL) &&
10427
46.3k
                  (xmlXPathCheckOpLimit(ctxt,
10428
46.3k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10429
46.3k
                 ((arg2->nodesetval != NULL) &&
10430
46.3k
                  (xmlXPathCheckOpLimit(ctxt,
10431
46.3k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10432
7
          xmlXPathReleaseObject(ctxt->context, arg1);
10433
7
          xmlXPathReleaseObject(ctxt->context, arg2);
10434
7
                break;
10435
7
            }
10436
10437
46.3k
            if ((arg2->nodesetval != NULL) &&
10438
46.3k
                (arg2->nodesetval->nodeNr != 0)) {
10439
29.7k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10440
29.7k
                                                        arg2->nodesetval);
10441
29.7k
                if (arg1->nodesetval == NULL)
10442
3
                    xmlXPathPErrMemory(ctxt);
10443
29.7k
            }
10444
46.3k
            xmlXPathValuePush(ctxt, arg1);
10445
46.3k
      xmlXPathReleaseObject(ctxt->context, arg2);
10446
46.3k
            total += cur;
10447
46.3k
            break;
10448
5.87k
        case XPATH_OP_ROOT:
10449
5.87k
            xmlXPathRoot(ctxt);
10450
5.87k
            break;
10451
21.3k
        case XPATH_OP_NODE:
10452
21.3k
            if (op->ch1 != -1)
10453
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10454
21.3k
      CHECK_ERROR0;
10455
21.3k
            if (op->ch2 != -1)
10456
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10457
21.3k
      CHECK_ERROR0;
10458
21.3k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10459
21.3k
    ctxt->context->node));
10460
21.3k
            break;
10461
48.6k
        case XPATH_OP_COLLECT:{
10462
48.6k
                if (op->ch1 == -1)
10463
0
                    break;
10464
10465
48.6k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10466
48.6k
    CHECK_ERROR0;
10467
10468
46.6k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10469
46.6k
                break;
10470
48.6k
            }
10471
3.96k
        case XPATH_OP_VALUE:
10472
3.96k
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10473
3.96k
            break;
10474
28.1k
        case XPATH_OP_SORT:
10475
28.1k
            if (op->ch1 != -1)
10476
28.1k
                total +=
10477
28.1k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10478
28.1k
                                            first);
10479
28.1k
      CHECK_ERROR0;
10480
16.8k
            if ((ctxt->value != NULL)
10481
16.8k
                && (ctxt->value->type == XPATH_NODESET)
10482
16.8k
                && (ctxt->value->nodesetval != NULL)
10483
16.8k
    && (ctxt->value->nodesetval->nodeNr > 1))
10484
6.67k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10485
16.8k
            break;
10486
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10487
44.3k
  case XPATH_OP_FILTER:
10488
44.3k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10489
44.3k
            break;
10490
0
#endif
10491
2.63k
        default:
10492
2.63k
            total += xmlXPathCompOpEval(ctxt, op);
10493
2.63k
            break;
10494
218k
    }
10495
10496
188k
    ctxt->context->depth -= 1;
10497
188k
    return(total);
10498
218k
}
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
87.1k
{
10513
87.1k
    int total = 0, cur;
10514
87.1k
    xmlXPathCompExprPtr comp;
10515
87.1k
    xmlXPathObjectPtr arg1, arg2;
10516
10517
87.1k
    CHECK_ERROR0;
10518
87.1k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10519
3
        return(0);
10520
87.1k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10521
86.3k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10522
86.3k
    ctxt->context->depth += 1;
10523
86.3k
    comp = ctxt->comp;
10524
86.3k
    switch (op->op) {
10525
0
        case XPATH_OP_END:
10526
0
            break;
10527
27.3k
        case XPATH_OP_UNION:
10528
27.3k
            total =
10529
27.3k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10530
27.3k
      CHECK_ERROR0;
10531
24.8k
            if ((ctxt->value != NULL)
10532
24.8k
                && (ctxt->value->type == XPATH_NODESET)
10533
24.8k
                && (ctxt->value->nodesetval != NULL)
10534
24.8k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10535
                /*
10536
                 * limit tree traversing to first node in the result
10537
                 */
10538
9.08k
    if (ctxt->value->nodesetval->nodeNr > 1)
10539
491
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10540
9.08k
                *last =
10541
9.08k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10542
9.08k
                                                     nodesetval->nodeNr -
10543
9.08k
                                                     1];
10544
9.08k
            }
10545
24.8k
            cur =
10546
24.8k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10547
24.8k
      CHECK_ERROR0;
10548
24.1k
            if ((ctxt->value != NULL)
10549
24.1k
                && (ctxt->value->type == XPATH_NODESET)
10550
24.1k
                && (ctxt->value->nodesetval != NULL)
10551
24.1k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10552
15.0k
            }
10553
10554
24.1k
            arg2 = xmlXPathValuePop(ctxt);
10555
24.1k
            arg1 = xmlXPathValuePop(ctxt);
10556
24.1k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10557
24.1k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10558
329
          xmlXPathReleaseObject(ctxt->context, arg1);
10559
329
          xmlXPathReleaseObject(ctxt->context, arg2);
10560
329
                XP_ERROR0(XPATH_INVALID_TYPE);
10561
0
            }
10562
23.7k
            if ((ctxt->context->opLimit != 0) &&
10563
23.7k
                (((arg1->nodesetval != NULL) &&
10564
23.7k
                  (xmlXPathCheckOpLimit(ctxt,
10565
23.7k
                                        arg1->nodesetval->nodeNr) < 0)) ||
10566
23.7k
                 ((arg2->nodesetval != NULL) &&
10567
23.7k
                  (xmlXPathCheckOpLimit(ctxt,
10568
23.7k
                                        arg2->nodesetval->nodeNr) < 0)))) {
10569
2
          xmlXPathReleaseObject(ctxt->context, arg1);
10570
2
          xmlXPathReleaseObject(ctxt->context, arg2);
10571
2
                break;
10572
2
            }
10573
10574
23.7k
            if ((arg2->nodesetval != NULL) &&
10575
23.7k
                (arg2->nodesetval->nodeNr != 0)) {
10576
15.0k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10577
15.0k
                                                        arg2->nodesetval);
10578
15.0k
                if (arg1->nodesetval == NULL)
10579
1
                    xmlXPathPErrMemory(ctxt);
10580
15.0k
            }
10581
23.7k
            xmlXPathValuePush(ctxt, arg1);
10582
23.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
10583
23.7k
            total += cur;
10584
23.7k
            break;
10585
2.35k
        case XPATH_OP_ROOT:
10586
2.35k
            xmlXPathRoot(ctxt);
10587
2.35k
            break;
10588
4.50k
        case XPATH_OP_NODE:
10589
4.50k
            if (op->ch1 != -1)
10590
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10591
4.50k
      CHECK_ERROR0;
10592
4.50k
            if (op->ch2 != -1)
10593
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10594
4.50k
      CHECK_ERROR0;
10595
4.50k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10596
4.50k
    ctxt->context->node));
10597
4.50k
            break;
10598
30.2k
        case XPATH_OP_COLLECT:{
10599
30.2k
                if (op->ch1 == -1)
10600
0
                    break;
10601
10602
30.2k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10603
30.2k
    CHECK_ERROR0;
10604
10605
29.7k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10606
29.7k
                break;
10607
30.2k
            }
10608
366
        case XPATH_OP_VALUE:
10609
366
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10610
366
            break;
10611
17.4k
        case XPATH_OP_SORT:
10612
17.4k
            if (op->ch1 != -1)
10613
17.4k
                total +=
10614
17.4k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10615
17.4k
                                           last);
10616
17.4k
      CHECK_ERROR0;
10617
15.2k
            if ((ctxt->value != NULL)
10618
15.2k
                && (ctxt->value->type == XPATH_NODESET)
10619
15.2k
                && (ctxt->value->nodesetval != NULL)
10620
15.2k
    && (ctxt->value->nodesetval->nodeNr > 1))
10621
6.20k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10622
15.2k
            break;
10623
4.07k
        default:
10624
4.07k
            total += xmlXPathCompOpEval(ctxt, op);
10625
4.07k
            break;
10626
86.3k
    }
10627
10628
80.1k
    ctxt->context->depth -= 1;
10629
80.1k
    return (total);
10630
86.3k
}
10631
10632
#ifdef XP_OPTIMIZED_FILTER_FIRST
10633
static int
10634
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10635
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10636
44.3k
{
10637
44.3k
    int total = 0;
10638
44.3k
    xmlXPathCompExprPtr comp;
10639
44.3k
    xmlXPathObjectPtr obj;
10640
44.3k
    xmlNodeSetPtr set;
10641
10642
44.3k
    CHECK_ERROR0;
10643
44.3k
    comp = ctxt->comp;
10644
    /*
10645
    * Optimization for ()[last()] selection i.e. the last elem
10646
    */
10647
44.3k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10648
44.3k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10649
44.3k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10650
10.3k
  int f = comp->steps[op->ch2].ch1;
10651
10652
10.3k
  if ((f != -1) &&
10653
10.3k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10654
10.3k
      (comp->steps[f].value5 == NULL) &&
10655
10.3k
      (comp->steps[f].value == 0) &&
10656
10.3k
      (comp->steps[f].value4 != NULL) &&
10657
10.3k
      (xmlStrEqual
10658
8.89k
      (comp->steps[f].value4, BAD_CAST "last"))) {
10659
7.78k
      xmlNodePtr last = NULL;
10660
10661
7.78k
      total +=
10662
7.78k
    xmlXPathCompOpEvalLast(ctxt,
10663
7.78k
        &comp->steps[op->ch1],
10664
7.78k
        &last);
10665
7.78k
      CHECK_ERROR0;
10666
      /*
10667
      * The nodeset should be in document order,
10668
      * Keep only the last value
10669
      */
10670
6.31k
      if ((ctxt->value != NULL) &&
10671
6.31k
    (ctxt->value->type == XPATH_NODESET) &&
10672
6.31k
    (ctxt->value->nodesetval != NULL) &&
10673
6.31k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10674
6.31k
    (ctxt->value->nodesetval->nodeNr > 1)) {
10675
248
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10676
248
    *first = *(ctxt->value->nodesetval->nodeTab);
10677
248
      }
10678
6.31k
      return (total);
10679
7.78k
  }
10680
10.3k
    }
10681
10682
36.6k
    if (op->ch1 != -1)
10683
36.6k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10684
36.6k
    CHECK_ERROR0;
10685
34.4k
    if (op->ch2 == -1)
10686
0
  return (total);
10687
34.4k
    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
34.4k
    CHECK_TYPE0(XPATH_NODESET);
10696
30.3k
    obj = xmlXPathValuePop(ctxt);
10697
30.3k
    set = obj->nodesetval;
10698
30.3k
    if (set != NULL) {
10699
30.3k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10700
30.3k
        if (set->nodeNr > 0)
10701
13.6k
            *first = set->nodeTab[0];
10702
30.3k
    }
10703
30.3k
    xmlXPathValuePush(ctxt, obj);
10704
10705
30.3k
    return (total);
10706
34.4k
}
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
36.4M
{
10719
36.4M
    int total = 0;
10720
36.4M
    int equal, ret;
10721
36.4M
    xmlXPathCompExprPtr comp;
10722
36.4M
    xmlXPathObjectPtr arg1, arg2;
10723
10724
36.4M
    CHECK_ERROR0;
10725
36.4M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10726
837k
        return(0);
10727
35.5M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10728
35.5M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10729
35.5M
    ctxt->context->depth += 1;
10730
35.5M
    comp = ctxt->comp;
10731
35.5M
    switch (op->op) {
10732
0
        case XPATH_OP_END:
10733
0
            break;
10734
190k
        case XPATH_OP_AND:
10735
190k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10736
190k
      CHECK_ERROR0;
10737
158k
            xmlXPathBooleanFunction(ctxt, 1);
10738
158k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10739
127k
                break;
10740
30.4k
            arg2 = xmlXPathValuePop(ctxt);
10741
30.4k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10742
30.4k
      if (ctxt->error) {
10743
3.93k
    xmlXPathFreeObject(arg2);
10744
3.93k
    break;
10745
3.93k
      }
10746
26.5k
            xmlXPathBooleanFunction(ctxt, 1);
10747
26.5k
            if (ctxt->value != NULL)
10748
26.4k
                ctxt->value->boolval &= arg2->boolval;
10749
26.5k
      xmlXPathReleaseObject(ctxt->context, arg2);
10750
26.5k
            break;
10751
232k
        case XPATH_OP_OR:
10752
232k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10753
232k
      CHECK_ERROR0;
10754
222k
            xmlXPathBooleanFunction(ctxt, 1);
10755
222k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10756
18.5k
                break;
10757
203k
            arg2 = xmlXPathValuePop(ctxt);
10758
203k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10759
203k
      if (ctxt->error) {
10760
24.5k
    xmlXPathFreeObject(arg2);
10761
24.5k
    break;
10762
24.5k
      }
10763
178k
            xmlXPathBooleanFunction(ctxt, 1);
10764
178k
            if (ctxt->value != NULL)
10765
178k
                ctxt->value->boolval |= arg2->boolval;
10766
178k
      xmlXPathReleaseObject(ctxt->context, arg2);
10767
178k
            break;
10768
751k
        case XPATH_OP_EQUAL:
10769
751k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10770
751k
      CHECK_ERROR0;
10771
678k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10772
678k
      CHECK_ERROR0;
10773
607k
      if (op->value)
10774
322k
    equal = xmlXPathEqualValues(ctxt);
10775
284k
      else
10776
284k
    equal = xmlXPathNotEqualValues(ctxt);
10777
607k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10778
607k
            break;
10779
761k
        case XPATH_OP_CMP:
10780
761k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10781
761k
      CHECK_ERROR0;
10782
733k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10783
733k
      CHECK_ERROR0;
10784
611k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10785
611k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10786
611k
            break;
10787
1.28M
        case XPATH_OP_PLUS:
10788
1.28M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10789
1.28M
      CHECK_ERROR0;
10790
1.22M
            if (op->ch2 != -1) {
10791
515k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10792
515k
      }
10793
1.22M
      CHECK_ERROR0;
10794
1.12M
            if (op->value == 0)
10795
215k
                xmlXPathSubValues(ctxt);
10796
905k
            else if (op->value == 1)
10797
199k
                xmlXPathAddValues(ctxt);
10798
705k
            else if (op->value == 2)
10799
662k
                xmlXPathValueFlipSign(ctxt);
10800
43.0k
            else if (op->value == 3) {
10801
43.0k
                CAST_TO_NUMBER;
10802
43.0k
                CHECK_TYPE0(XPATH_NUMBER);
10803
42.9k
            }
10804
1.12M
            break;
10805
1.12M
        case XPATH_OP_MULT:
10806
644k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10807
644k
      CHECK_ERROR0;
10808
509k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10809
509k
      CHECK_ERROR0;
10810
481k
            if (op->value == 0)
10811
447k
                xmlXPathMultValues(ctxt);
10812
33.6k
            else if (op->value == 1)
10813
1.68k
                xmlXPathDivValues(ctxt);
10814
31.9k
            else if (op->value == 2)
10815
31.9k
                xmlXPathModValues(ctxt);
10816
481k
            break;
10817
2.00M
        case XPATH_OP_UNION:
10818
2.00M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10819
2.00M
      CHECK_ERROR0;
10820
1.93M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10821
1.93M
      CHECK_ERROR0;
10822
10823
1.89M
            arg2 = xmlXPathValuePop(ctxt);
10824
1.89M
            arg1 = xmlXPathValuePop(ctxt);
10825
1.89M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10826
1.89M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10827
14.8k
          xmlXPathReleaseObject(ctxt->context, arg1);
10828
14.8k
          xmlXPathReleaseObject(ctxt->context, arg2);
10829
14.8k
                XP_ERROR0(XPATH_INVALID_TYPE);
10830
0
            }
10831
1.87M
            if ((ctxt->context->opLimit != 0) &&
10832
1.87M
                (((arg1->nodesetval != NULL) &&
10833
1.87M
                  (xmlXPathCheckOpLimit(ctxt,
10834
1.87M
                                        arg1->nodesetval->nodeNr) < 0)) ||
10835
1.87M
                 ((arg2->nodesetval != NULL) &&
10836
1.87M
                  (xmlXPathCheckOpLimit(ctxt,
10837
1.87M
                                        arg2->nodesetval->nodeNr) < 0)))) {
10838
333
          xmlXPathReleaseObject(ctxt->context, arg1);
10839
333
          xmlXPathReleaseObject(ctxt->context, arg2);
10840
333
                break;
10841
333
            }
10842
10843
1.87M
      if (((arg2->nodesetval != NULL) &&
10844
1.87M
     (arg2->nodesetval->nodeNr != 0)))
10845
1.09M
      {
10846
1.09M
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10847
1.09M
              arg2->nodesetval);
10848
1.09M
                if (arg1->nodesetval == NULL)
10849
424
                    xmlXPathPErrMemory(ctxt);
10850
1.09M
      }
10851
10852
1.87M
            xmlXPathValuePush(ctxt, arg1);
10853
1.87M
      xmlXPathReleaseObject(ctxt->context, arg2);
10854
1.87M
            break;
10855
1.91M
        case XPATH_OP_ROOT:
10856
1.91M
            xmlXPathRoot(ctxt);
10857
1.91M
            break;
10858
6.82M
        case XPATH_OP_NODE:
10859
6.82M
            if (op->ch1 != -1)
10860
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10861
6.82M
      CHECK_ERROR0;
10862
6.82M
            if (op->ch2 != -1)
10863
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10864
6.82M
      CHECK_ERROR0;
10865
6.82M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10866
6.82M
                                                    ctxt->context->node));
10867
6.82M
            break;
10868
7.67M
        case XPATH_OP_COLLECT:{
10869
7.67M
                if (op->ch1 == -1)
10870
0
                    break;
10871
10872
7.67M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10873
7.67M
    CHECK_ERROR0;
10874
10875
7.54M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10876
7.54M
                break;
10877
7.67M
            }
10878
1.02M
        case XPATH_OP_VALUE:
10879
1.02M
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10880
1.02M
            break;
10881
143k
        case XPATH_OP_VARIABLE:{
10882
143k
    xmlXPathObjectPtr val;
10883
10884
143k
                if (op->ch1 != -1)
10885
0
                    total +=
10886
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10887
143k
                if (op->value5 == NULL) {
10888
132k
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10889
132k
        if (val == NULL) {
10890
52.0k
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10891
52.0k
                                       "Undefined variable: %s\n", op->value4);
10892
52.0k
                        return 0;
10893
52.0k
                    }
10894
80.8k
                    xmlXPathValuePush(ctxt, val);
10895
80.8k
    } else {
10896
10.5k
                    const xmlChar *URI;
10897
10898
10.5k
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10899
10.5k
                    if (URI == NULL) {
10900
800
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10901
800
                                       "Undefined namespace prefix: %s\n",
10902
800
                                       op->value5);
10903
800
                        return 0;
10904
800
                    }
10905
9.75k
        val = xmlXPathVariableLookupNS(ctxt->context,
10906
9.75k
                                                       op->value4, URI);
10907
9.75k
        if (val == NULL) {
10908
9.75k
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10909
9.75k
                                       "Undefined variable: %s:%s\n",
10910
9.75k
                                       op->value5, op->value4);
10911
9.75k
                        return 0;
10912
9.75k
                    }
10913
0
                    xmlXPathValuePush(ctxt, val);
10914
0
                }
10915
80.8k
                break;
10916
143k
            }
10917
2.30M
        case XPATH_OP_FUNCTION:{
10918
2.30M
                xmlXPathFunction func;
10919
2.30M
                const xmlChar *oldFunc, *oldFuncURI;
10920
2.30M
    int i;
10921
2.30M
                int frame;
10922
10923
2.30M
                frame = ctxt->valueNr;
10924
2.30M
                if (op->ch1 != -1) {
10925
1.63M
                    total +=
10926
1.63M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10927
1.63M
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10928
87.6k
                        break;
10929
1.63M
                }
10930
2.22M
    if (ctxt->valueNr < frame + op->value)
10931
2.22M
        XP_ERROR0(XPATH_INVALID_OPERAND);
10932
4.82M
    for (i = 0; i < op->value; i++) {
10933
2.60M
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10934
2.60M
      XP_ERROR0(XPATH_INVALID_OPERAND);
10935
2.60M
                }
10936
2.22M
                if (op->cache != NULL)
10937
1.89M
                    func = op->cache;
10938
328k
                else {
10939
328k
                    const xmlChar *URI = NULL;
10940
10941
328k
                    if (op->value5 == NULL) {
10942
136k
                        func = xmlXPathFunctionLookup(ctxt->context,
10943
136k
                                                      op->value4);
10944
136k
                        if (func == NULL) {
10945
80.1k
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10946
80.1k
                                           "Unregistered function: %s\n",
10947
80.1k
                                           op->value4);
10948
80.1k
                            return 0;
10949
80.1k
                        }
10950
192k
                    } else {
10951
192k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10952
192k
                        if (URI == NULL) {
10953
23.3k
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10954
23.3k
                                           "Undefined namespace prefix: %s\n",
10955
23.3k
                                           op->value5);
10956
23.3k
                            return 0;
10957
23.3k
                        }
10958
168k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10959
168k
                                                        op->value4, URI);
10960
168k
                        if (func == NULL) {
10961
11.1k
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10962
11.1k
                                           "Unregistered function: %s:%s\n",
10963
11.1k
                                           op->value5, op->value4);
10964
11.1k
                            return 0;
10965
11.1k
                        }
10966
168k
                    }
10967
214k
                    op->cache = func;
10968
214k
                    op->cacheURI = (void *) URI;
10969
214k
                }
10970
2.10M
                oldFunc = ctxt->context->function;
10971
2.10M
                oldFuncURI = ctxt->context->functionURI;
10972
2.10M
                ctxt->context->function = op->value4;
10973
2.10M
                ctxt->context->functionURI = op->cacheURI;
10974
2.10M
                func(ctxt, op->value);
10975
2.10M
                ctxt->context->function = oldFunc;
10976
2.10M
                ctxt->context->functionURI = oldFuncURI;
10977
2.10M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
10978
2.10M
                    (ctxt->valueNr != frame + 1))
10979
2.10M
                    XP_ERROR0(XPATH_STACK_ERROR);
10980
2.10M
                break;
10981
2.10M
            }
10982
2.75M
        case XPATH_OP_ARG:
10983
2.75M
            if (op->ch1 != -1) {
10984
1.11M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10985
1.11M
          CHECK_ERROR0;
10986
1.11M
            }
10987
2.73M
            if (op->ch2 != -1) {
10988
2.73M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10989
2.73M
          CHECK_ERROR0;
10990
2.73M
      }
10991
2.64M
            break;
10992
2.64M
        case XPATH_OP_PREDICATE:
10993
361k
        case XPATH_OP_FILTER:{
10994
361k
                xmlXPathObjectPtr obj;
10995
361k
                xmlNodeSetPtr set;
10996
10997
                /*
10998
                 * Optimization for ()[1] selection i.e. the first elem
10999
                 */
11000
361k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11001
361k
#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
361k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11012
361k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11013
#else
11014
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11015
#endif
11016
361k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11017
97.1k
                    xmlXPathObjectPtr val;
11018
11019
97.1k
                    val = comp->steps[op->ch2].value4;
11020
97.1k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11021
97.1k
                        (val->floatval == 1.0)) {
11022
73.0k
                        xmlNodePtr first = NULL;
11023
11024
73.0k
                        total +=
11025
73.0k
                            xmlXPathCompOpEvalFirst(ctxt,
11026
73.0k
                                                    &comp->steps[op->ch1],
11027
73.0k
                                                    &first);
11028
73.0k
      CHECK_ERROR0;
11029
                        /*
11030
                         * The nodeset should be in document order,
11031
                         * Keep only the first value
11032
                         */
11033
52.9k
                        if ((ctxt->value != NULL) &&
11034
52.9k
                            (ctxt->value->type == XPATH_NODESET) &&
11035
52.9k
                            (ctxt->value->nodesetval != NULL) &&
11036
52.9k
                            (ctxt->value->nodesetval->nodeNr > 1))
11037
6.67k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11038
6.67k
                                                        1, 1);
11039
52.9k
                        break;
11040
73.0k
                    }
11041
97.1k
                }
11042
                /*
11043
                 * Optimization for ()[last()] selection i.e. the last elem
11044
                 */
11045
288k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11046
288k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
288k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11048
19.0k
                    int f = comp->steps[op->ch2].ch1;
11049
11050
19.0k
                    if ((f != -1) &&
11051
19.0k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11052
19.0k
                        (comp->steps[f].value5 == NULL) &&
11053
19.0k
                        (comp->steps[f].value == 0) &&
11054
19.0k
                        (comp->steps[f].value4 != NULL) &&
11055
19.0k
                        (xmlStrEqual
11056
9.97k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11057
9.77k
                        xmlNodePtr last = NULL;
11058
11059
9.77k
                        total +=
11060
9.77k
                            xmlXPathCompOpEvalLast(ctxt,
11061
9.77k
                                                   &comp->steps[op->ch1],
11062
9.77k
                                                   &last);
11063
9.77k
      CHECK_ERROR0;
11064
                        /*
11065
                         * The nodeset should be in document order,
11066
                         * Keep only the last value
11067
                         */
11068
8.93k
                        if ((ctxt->value != NULL) &&
11069
8.93k
                            (ctxt->value->type == XPATH_NODESET) &&
11070
8.93k
                            (ctxt->value->nodesetval != NULL) &&
11071
8.93k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11072
8.93k
                            (ctxt->value->nodesetval->nodeNr > 1))
11073
5.96k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11074
8.93k
                        break;
11075
9.77k
                    }
11076
19.0k
                }
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
278k
                if (op->ch1 != -1)
11089
278k
                    total +=
11090
278k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11091
278k
    CHECK_ERROR0;
11092
255k
                if (op->ch2 == -1)
11093
0
                    break;
11094
255k
                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
255k
                CHECK_TYPE0(XPATH_NODESET);
11104
252k
                obj = xmlXPathValuePop(ctxt);
11105
252k
                set = obj->nodesetval;
11106
252k
                if (set != NULL)
11107
252k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11108
252k
                                          1, set->nodeNr, 1);
11109
252k
                xmlXPathValuePush(ctxt, obj);
11110
252k
                break;
11111
255k
            }
11112
6.68M
        case XPATH_OP_SORT:
11113
6.68M
            if (op->ch1 != -1)
11114
6.68M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11115
6.68M
      CHECK_ERROR0;
11116
6.19M
            if ((ctxt->value != NULL) &&
11117
6.19M
                (ctxt->value->type == XPATH_NODESET) &&
11118
6.19M
                (ctxt->value->nodesetval != NULL) &&
11119
6.19M
    (ctxt->value->nodesetval->nodeNr > 1))
11120
1.02M
      {
11121
1.02M
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11122
1.02M
      }
11123
6.19M
            break;
11124
0
        default:
11125
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11126
0
            break;
11127
35.5M
    }
11128
11129
33.8M
    ctxt->context->depth -= 1;
11130
33.8M
    return (total);
11131
35.5M
}
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.94M
{
11146
1.94M
    xmlXPathObjectPtr resObj = NULL;
11147
11148
2.55M
start:
11149
2.55M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11150
7.39k
        return(0);
11151
    /* comp = ctxt->comp; */
11152
2.54M
    switch (op->op) {
11153
0
        case XPATH_OP_END:
11154
0
            return (0);
11155
962k
  case XPATH_OP_VALUE:
11156
962k
      resObj = (xmlXPathObjectPtr) op->value4;
11157
962k
      if (isPredicate)
11158
961k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11159
836
      return(xmlXPathCastToBoolean(resObj));
11160
606k
  case XPATH_OP_SORT:
11161
      /*
11162
      * We don't need sorting for boolean results. Skip this one.
11163
      */
11164
606k
            if (op->ch1 != -1) {
11165
606k
    op = &ctxt->comp->steps[op->ch1];
11166
606k
    goto start;
11167
606k
      }
11168
0
      return(0);
11169
92.4k
  case XPATH_OP_COLLECT:
11170
92.4k
      if (op->ch1 == -1)
11171
0
    return(0);
11172
11173
92.4k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11174
92.4k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11175
790
    return(-1);
11176
11177
91.6k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11178
91.6k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11179
2.59k
    return(-1);
11180
11181
89.0k
      resObj = xmlXPathValuePop(ctxt);
11182
89.0k
      if (resObj == NULL)
11183
0
    return(-1);
11184
89.0k
      break;
11185
882k
  default:
11186
      /*
11187
      * Fallback to call xmlXPathCompOpEval().
11188
      */
11189
882k
      xmlXPathCompOpEval(ctxt, op);
11190
882k
      if (ctxt->error != XPATH_EXPRESSION_OK)
11191
30.4k
    return(-1);
11192
11193
851k
      resObj = xmlXPathValuePop(ctxt);
11194
851k
      if (resObj == NULL)
11195
0
    return(-1);
11196
851k
      break;
11197
2.54M
    }
11198
11199
940k
    if (resObj) {
11200
940k
  int res;
11201
11202
940k
  if (resObj->type == XPATH_BOOLEAN) {
11203
281k
      res = resObj->boolval;
11204
659k
  } 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
647k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11214
647k
  } else {
11215
11.4k
      res = xmlXPathCastToBoolean(resObj);
11216
11.4k
  }
11217
940k
  xmlXPathReleaseObject(ctxt->context, resObj);
11218
940k
  return(res);
11219
940k
    }
11220
11221
0
    return(0);
11222
940k
}
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
4.72M
{
11465
4.72M
    xmlXPathCompExprPtr comp;
11466
4.72M
    int oldDepth;
11467
11468
4.72M
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11469
0
  return(-1);
11470
11471
4.72M
    if (ctxt->valueTab == NULL) {
11472
17.7k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11473
17.7k
        int valueMax = 1;
11474
#else
11475
        int valueMax = 10;
11476
#endif
11477
11478
  /* Allocate the value stack */
11479
17.7k
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11480
17.7k
  if (ctxt->valueTab == NULL) {
11481
9
      xmlXPathPErrMemory(ctxt);
11482
9
      return(-1);
11483
9
  }
11484
17.7k
  ctxt->valueNr = 0;
11485
17.7k
  ctxt->valueMax = valueMax;
11486
17.7k
  ctxt->value = NULL;
11487
17.7k
    }
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
4.72M
    comp = ctxt->comp;
11521
4.72M
    if (comp->last < 0) {
11522
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11523
0
  return(-1);
11524
0
    }
11525
4.72M
    oldDepth = ctxt->context->depth;
11526
4.72M
    if (toBool)
11527
20.0k
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11528
20.0k
      &comp->steps[comp->last], 0));
11529
4.70M
    else
11530
4.70M
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11531
4.70M
    ctxt->context->depth = oldDepth;
11532
11533
4.70M
    return(0);
11534
4.72M
}
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
25.2k
xmlXPathEvalPredicate(xmlXPathContext *ctxt, xmlXPathObject *res) {
11558
25.2k
    if ((ctxt == NULL) || (res == NULL)) return(0);
11559
25.2k
    switch (res->type) {
11560
13.7k
        case XPATH_BOOLEAN:
11561
13.7k
      return(res->boolval);
11562
8.42k
        case XPATH_NUMBER:
11563
8.42k
      return(res->floatval == ctxt->proximityPosition);
11564
1.52k
        case XPATH_NODESET:
11565
1.52k
        case XPATH_XSLT_TREE:
11566
1.52k
      if (res->nodesetval == NULL)
11567
1
    return(0);
11568
1.52k
      return(res->nodesetval->nodeNr != 0);
11569
1.47k
        case XPATH_STRING:
11570
1.47k
      return((res->stringval != NULL) &&
11571
1.47k
             (xmlStrlen(res->stringval) != 0));
11572
0
        default:
11573
0
      break;
11574
25.2k
    }
11575
0
    return(0);
11576
25.2k
}
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.60M
                                xmlXPathObject *res) {
11595
1.60M
    if ((ctxt == NULL) || (res == NULL)) return(0);
11596
1.60M
    switch (res->type) {
11597
0
        case XPATH_BOOLEAN:
11598
0
      return(res->boolval);
11599
625k
        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
625k
      return(res->floatval == ctxt->context->proximityPosition);
11605
0
#endif
11606
108k
        case XPATH_NODESET:
11607
108k
        case XPATH_XSLT_TREE:
11608
108k
      if (res->nodesetval == NULL)
11609
0
    return(0);
11610
108k
      return(res->nodesetval->nodeNr != 0);
11611
876k
        case XPATH_STRING:
11612
876k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11613
0
        default:
11614
0
      break;
11615
1.60M
    }
11616
0
    return(0);
11617
1.60M
}
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
8.10M
{
11709
8.10M
    xmlXPathCompExprPtr comp = pctxt->comp;
11710
8.10M
    xmlXPathContextPtr ctxt;
11711
11712
    /*
11713
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11714
    * internal representation.
11715
    */
11716
11717
8.10M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11718
8.10M
        (op->ch1 != -1) &&
11719
8.10M
        (op->ch2 == -1 /* no predicate */))
11720
1.68M
    {
11721
1.68M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11722
11723
1.68M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11724
1.68M
            ((xmlXPathAxisVal) prevop->value ==
11725
323k
                AXIS_DESCENDANT_OR_SELF) &&
11726
1.68M
            (prevop->ch2 == -1) &&
11727
1.68M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11728
1.68M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11729
190k
        {
11730
            /*
11731
            * This is a "descendant-or-self::node()" without predicates.
11732
            * Try to eliminate it.
11733
            */
11734
11735
190k
            switch ((xmlXPathAxisVal) op->value) {
11736
178k
                case AXIS_CHILD:
11737
178k
                case AXIS_DESCENDANT:
11738
                    /*
11739
                    * Convert "descendant-or-self::node()/child::" or
11740
                    * "descendant-or-self::node()/descendant::" to
11741
                    * "descendant::"
11742
                    */
11743
178k
                    op->ch1   = prevop->ch1;
11744
178k
                    op->value = AXIS_DESCENDANT;
11745
178k
                    break;
11746
43
                case AXIS_SELF:
11747
1.61k
                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
1.61k
                    op->ch1   = prevop->ch1;
11754
1.61k
                    op->value = AXIS_DESCENDANT_OR_SELF;
11755
1.61k
                    break;
11756
9.99k
                default:
11757
9.99k
                    break;
11758
190k
            }
11759
190k
  }
11760
1.68M
    }
11761
11762
    /* OP_VALUE has invalid ch1. */
11763
8.10M
    if (op->op == XPATH_OP_VALUE)
11764
323k
        return;
11765
11766
    /* Recurse */
11767
7.78M
    ctxt = pctxt->context;
11768
7.78M
    if (ctxt != NULL) {
11769
7.78M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11770
6.13k
            return;
11771
7.77M
        ctxt->depth += 1;
11772
7.77M
    }
11773
7.77M
    if (op->ch1 != -1)
11774
5.29M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11775
7.77M
    if (op->ch2 != -1)
11776
2.36M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11777
7.77M
    if (ctxt != NULL)
11778
7.77M
        ctxt->depth -= 1;
11779
7.77M
}
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
867k
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11791
867k
    xmlXPathParserContextPtr pctxt;
11792
867k
    xmlXPathContextPtr tmpctxt = NULL;
11793
867k
    xmlXPathCompExprPtr comp;
11794
867k
    int oldDepth = 0;
11795
11796
867k
    if (str == NULL)
11797
81
        return(NULL);
11798
11799
#ifdef XPATH_STREAMING
11800
    comp = xmlXPathTryStreamCompile(ctxt, str);
11801
    if (comp != NULL)
11802
        return(comp);
11803
#endif
11804
11805
867k
    xmlInitParser();
11806
11807
    /*
11808
     * We need an xmlXPathContext for the depth check.
11809
     */
11810
867k
    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
867k
    pctxt = xmlXPathNewParserContext(str, ctxt);
11818
867k
    if (pctxt == NULL) {
11819
131
        if (tmpctxt != NULL)
11820
0
            xmlXPathFreeContext(tmpctxt);
11821
131
        return NULL;
11822
131
    }
11823
11824
867k
    oldDepth = ctxt->depth;
11825
867k
    xmlXPathCompileExpr(pctxt, 1);
11826
867k
    ctxt->depth = oldDepth;
11827
11828
867k
    if( pctxt->error != XPATH_EXPRESSION_OK )
11829
283k
    {
11830
283k
        xmlXPathFreeParserContext(pctxt);
11831
283k
        if (tmpctxt != NULL)
11832
0
            xmlXPathFreeContext(tmpctxt);
11833
283k
        return(NULL);
11834
283k
    }
11835
11836
584k
    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
143k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11844
143k
  comp = NULL;
11845
441k
    } else {
11846
441k
  comp = pctxt->comp;
11847
441k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11848
418k
            if (ctxt != NULL)
11849
418k
                oldDepth = ctxt->depth;
11850
418k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11851
418k
            if (ctxt != NULL)
11852
418k
                ctxt->depth = oldDepth;
11853
418k
  }
11854
441k
  pctxt->comp = NULL;
11855
441k
    }
11856
584k
    xmlXPathFreeParserContext(pctxt);
11857
584k
    if (tmpctxt != NULL)
11858
0
        xmlXPathFreeContext(tmpctxt);
11859
11860
584k
    if (comp != NULL) {
11861
441k
  comp->expr = xmlStrdup(str);
11862
441k
    }
11863
584k
    return(comp);
11864
867k
}
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
4.78M
{
11895
4.78M
    xmlXPathParserContextPtr pctxt;
11896
4.78M
    xmlXPathObjectPtr resObj = NULL;
11897
4.78M
    int res;
11898
11899
4.78M
    if (comp == NULL)
11900
557
  return(-1);
11901
4.78M
    xmlInitParser();
11902
11903
4.78M
    xmlResetError(&ctxt->lastError);
11904
11905
4.78M
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11906
4.78M
    if (pctxt == NULL)
11907
86.0k
        return(-1);
11908
4.70M
    res = xmlXPathRunEval(pctxt, toBool);
11909
11910
4.70M
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11911
3.50M
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11912
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11913
3.50M
        else if (!toBool)
11914
3.48M
            resObj = xmlXPathValuePop(pctxt);
11915
3.50M
    }
11916
11917
4.70M
    if (resObjPtr)
11918
4.68M
        *resObjPtr = resObj;
11919
20.0k
    else
11920
20.0k
        xmlXPathReleaseObject(ctxt, resObj);
11921
11922
4.70M
    pctxt->comp = NULL;
11923
4.70M
    xmlXPathFreeParserContext(pctxt);
11924
11925
4.70M
    return(res);
11926
4.78M
}
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
4.76M
{
11939
4.76M
    xmlXPathObjectPtr res = NULL;
11940
11941
4.76M
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11942
4.76M
    return(res);
11943
4.76M
}
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
20.0k
{
11958
20.0k
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
11959
20.0k
}
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
43.5k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
11971
#ifdef XPATH_STREAMING
11972
    xmlXPathCompExprPtr comp;
11973
#endif
11974
43.5k
    int oldDepth = 0;
11975
11976
43.5k
    if ((ctxt == NULL) || (ctxt->context == NULL))
11977
0
        return;
11978
43.5k
    if (ctxt->context->lastError.code != 0)
11979
543
        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
43.0k
    {
11995
43.0k
        if (ctxt->context != NULL)
11996
43.0k
            oldDepth = ctxt->context->depth;
11997
43.0k
  xmlXPathCompileExpr(ctxt, 1);
11998
43.0k
        if (ctxt->context != NULL)
11999
43.0k
            ctxt->context->depth = oldDepth;
12000
43.0k
        CHECK_ERROR;
12001
12002
        /* Check for trailing characters. */
12003
36.0k
        if (*ctxt->cur != 0)
12004
26.6k
            XP_ERROR(XPATH_EXPR_ERROR);
12005
12006
26.6k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12007
24.9k
            if (ctxt->context != NULL)
12008
24.9k
                oldDepth = ctxt->context->depth;
12009
24.9k
      xmlXPathOptimizeExpression(ctxt,
12010
24.9k
    &ctxt->comp->steps[ctxt->comp->last]);
12011
24.9k
            if (ctxt->context != NULL)
12012
24.9k
                ctxt->context->depth = oldDepth;
12013
24.9k
        }
12014
26.6k
    }
12015
12016
0
    xmlXPathRunEval(ctxt, 0);
12017
26.6k
}
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
33.5k
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
12029
33.5k
    xmlXPathParserContextPtr ctxt;
12030
33.5k
    xmlXPathObjectPtr res;
12031
12032
33.5k
    if (ctx == NULL)
12033
0
        return(NULL);
12034
12035
33.5k
    xmlInitParser();
12036
12037
33.5k
    xmlResetError(&ctx->lastError);
12038
12039
33.5k
    ctxt = xmlXPathNewParserContext(str, ctx);
12040
33.5k
    if (ctxt == NULL)
12041
1.27k
        return NULL;
12042
32.2k
    xmlXPathEvalExpr(ctxt);
12043
12044
32.2k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12045
24.5k
  res = NULL;
12046
24.5k
    } else if (ctxt->valueNr != 1) {
12047
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12048
0
  res = NULL;
12049
7.71k
    } else {
12050
7.71k
  res = xmlXPathValuePop(ctxt);
12051
7.71k
    }
12052
12053
32.2k
    xmlXPathFreeParserContext(ctxt);
12054
32.2k
    return(res);
12055
33.5k
}
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
7.26k
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContext *ctxt) {
12106
7.26k
    return(xmlXPathEval(str, ctxt));
12107
7.26k
}
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 */