Coverage Report

Created: 2026-11-12 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxml2/xpath.c
Line
Count
Source
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: Daniel Veillard
14
 */
15
16
/* To avoid EBCDIC trouble when parsing on zOS */
17
#if defined(__MVS__)
18
#pragma convert("ISO8859-1")
19
#endif
20
21
#define IN_LIBXML
22
#include "libxml.h"
23
24
#include <limits.h>
25
#include <string.h>
26
#include <stddef.h>
27
#include <math.h>
28
#include <float.h>
29
#include <ctype.h>
30
31
#include <libxml/xmlmemory.h>
32
#include <libxml/tree.h>
33
#include <libxml/xpath.h>
34
#include <libxml/xpathInternals.h>
35
#include <libxml/parserInternals.h>
36
#include <libxml/hash.h>
37
#ifdef LIBXML_DEBUG_ENABLED
38
#include <libxml/debugXML.h>
39
#endif
40
#include <libxml/xmlerror.h>
41
#include <libxml/threads.h>
42
#ifdef LIBXML_PATTERN_ENABLED
43
#include <libxml/pattern.h>
44
#endif
45
46
#include "private/buf.h"
47
#include "private/error.h"
48
#include "private/memory.h"
49
#include "private/parser.h"
50
#include "private/xpath.h"
51
52
/* Disabled for now */
53
#if 0
54
#ifdef LIBXML_PATTERN_ENABLED
55
#define XPATH_STREAMING
56
#endif
57
#endif
58
59
/**
60
 * Use the Timsort algorithm provided in timsort.h to sort
61
 * nodeset as this is a great improvement over the old Shell sort
62
 * used in #xmlXPathNodeSetSort
63
 */
64
#define WITH_TIM_SORT
65
66
/*
67
* If defined, this will use xmlXPathCmpNodesExt() instead of
68
* xmlXPathCmpNodes(). The new function is optimized comparison of
69
* non-element nodes; actually it will speed up comparison only if
70
* xmlXPathOrderDocElems() was called in order to index the elements of
71
* a tree in document order; Libxslt does such an indexing, thus it will
72
* benefit from this optimization.
73
*/
74
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
75
76
/*
77
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
78
* in a way, that it stop evaluation at the first node.
79
*/
80
#define XP_OPTIMIZED_FILTER_FIRST
81
82
/*
83
 * when compiling an XPath expression we arbitrary limit the maximum
84
 * number of step operation in the compiled expression. 1000000 is
85
 * an insanely large value which should never be reached under normal
86
 * circumstances
87
 */
88
375k
#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
136k
#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
49.9M
#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
268M
#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
168
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
41.4k
#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
36.1k
xmlXPathSFComputeHash(const xmlChar *name) {
187
36.1k
    unsigned hashValue = 5381;
188
36.1k
    const xmlChar *ptr;
189
190
186k
    for (ptr = name; *ptr; ptr++)
191
150k
        hashValue = hashValue * 33 + *ptr;
192
193
36.1k
    return(hashValue);
194
36.1k
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
6
xmlInitXPathInternal(void) {
202
6
    size_t i;
203
204
6
#if defined(NAN) && defined(INFINITY)
205
6
    xmlXPathNAN = NAN;
206
6
    xmlXPathPINF = INFINITY;
207
6
    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
390
    for (i = 0; i < SF_HASH_SIZE; i++)
221
384
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
168
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
162
        const char *name = xmlXPathStandardFunctions[i].name;
225
162
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
204
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
42
            bucketIndex += 1;
229
42
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
42
        }
232
233
162
        xmlXPathSFHash[bucketIndex] = i;
234
162
    }
235
6
}
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
8.99M
xmlXPathIsNaN(double val) {
251
8.99M
#ifdef isnan
252
8.99M
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
8.99M
}
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
4.87M
xmlXPathIsInf(double val) {
266
4.87M
#ifdef isinf
267
4.87M
    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
4.87M
}
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
595M
#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
431M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
431M
    int depth1, depth2;
311
431M
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
431M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
431M
    xmlNodePtr cur, root;
314
431M
    XML_INTPTR_T l1, l2;
315
316
431M
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
431M
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
431M
    switch (node1->type) {
326
329M
  case XML_ELEMENT_NODE:
327
329M
      if (node2->type == XML_ELEMENT_NODE) {
328
308M
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
439k
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
439k
        (node1->doc == node2->doc))
331
439k
    {
332
439k
        l1 = -XML_NODE_SORT_VALUE(node1);
333
439k
        l2 = -XML_NODE_SORT_VALUE(node2);
334
439k
        if (l1 < l2)
335
439k
      return(1);
336
0
        if (l1 > l2)
337
0
      return(-1);
338
0
    } else
339
308M
        goto turtle_comparison;
340
308M
      }
341
20.4M
      break;
342
62.7M
  case XML_ATTRIBUTE_NODE:
343
62.7M
      precedence1 = 1; /* element is owner */
344
62.7M
      miscNode1 = node1;
345
62.7M
      node1 = node1->parent;
346
62.7M
      misc = 1;
347
62.7M
      break;
348
35.4M
  case XML_TEXT_NODE:
349
35.4M
  case XML_CDATA_SECTION_NODE:
350
36.6M
  case XML_COMMENT_NODE:
351
37.6M
  case XML_PI_NODE: {
352
37.6M
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
37.6M
      if (node1->prev != NULL) {
357
3.79G
    do {
358
3.79G
        node1 = node1->prev;
359
3.79G
        if (node1->type == XML_ELEMENT_NODE) {
360
25.6M
      precedence1 = 3; /* element in prev-sibl axis */
361
25.6M
      break;
362
25.6M
        }
363
3.77G
        if (node1->prev == NULL) {
364
783k
      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
783k
      node1 = node1->parent;
370
783k
      break;
371
783k
        }
372
3.77G
    } while (1);
373
26.4M
      } else {
374
11.2M
    precedence1 = 2; /* element is parent */
375
11.2M
    node1 = node1->parent;
376
11.2M
      }
377
37.6M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
37.6M
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
37.6M
    node1 = miscNode1;
383
37.6M
    precedence1 = 0;
384
37.6M
      } else
385
0
    misc = 1;
386
37.6M
  }
387
37.6M
      break;
388
1.74M
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
1.74M
      return(1);
393
98.6k
  default:
394
98.6k
      break;
395
431M
    }
396
120M
    switch (node2->type) {
397
67.8M
  case XML_ELEMENT_NODE:
398
67.8M
      break;
399
14.1M
  case XML_ATTRIBUTE_NODE:
400
14.1M
      precedence2 = 1; /* element is owner */
401
14.1M
      miscNode2 = node2;
402
14.1M
      node2 = node2->parent;
403
14.1M
      misc = 1;
404
14.1M
      break;
405
36.2M
  case XML_TEXT_NODE:
406
36.2M
  case XML_CDATA_SECTION_NODE:
407
37.0M
  case XML_COMMENT_NODE:
408
38.0M
  case XML_PI_NODE: {
409
38.0M
      miscNode2 = node2;
410
38.0M
      if (node2->prev != NULL) {
411
2.51G
    do {
412
2.51G
        node2 = node2->prev;
413
2.51G
        if (node2->type == XML_ELEMENT_NODE) {
414
22.9M
      precedence2 = 3; /* element in prev-sibl axis */
415
22.9M
      break;
416
22.9M
        }
417
2.49G
        if (node2->prev == NULL) {
418
942k
      precedence2 = 2; /* element is parent */
419
942k
      node2 = node2->parent;
420
942k
      break;
421
942k
        }
422
2.49G
    } while (1);
423
23.8M
      } else {
424
14.1M
    precedence2 = 2; /* element is parent */
425
14.1M
    node2 = node2->parent;
426
14.1M
      }
427
38.0M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
37.6M
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
38.0M
      {
430
38.0M
    node2 = miscNode2;
431
38.0M
    precedence2 = 0;
432
38.0M
      } else
433
0
    misc = 1;
434
38.0M
  }
435
38.0M
      break;
436
339k
  case XML_NAMESPACE_DECL:
437
339k
      return(1);
438
552k
  default:
439
552k
      break;
440
120M
    }
441
120M
    if (misc) {
442
69.8M
  if (node1 == node2) {
443
6.30M
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
1.38M
    cur = miscNode2->prev;
449
1.40M
    while (cur != NULL) {
450
1.39M
        if (cur == miscNode1)
451
1.37M
      return(1);
452
18.6k
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
18.6k
        cur = cur->prev;
455
18.6k
    }
456
11.4k
    return (-1);
457
4.91M
      } 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
4.91M
    if (precedence1 < precedence2)
464
399k
        return(1);
465
4.51M
    else
466
4.51M
        return(-1);
467
4.91M
      }
468
6.30M
  }
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
63.5M
  if ((precedence2 == 3) && (precedence1 > 1)) {
479
0
      cur = node1->parent;
480
0
      while (cur) {
481
0
    if (cur == node2)
482
0
        return(1);
483
0
    cur = cur->parent;
484
0
      }
485
0
  }
486
63.5M
  if ((precedence1 == 3) && (precedence2 > 1)) {
487
0
      cur = node2->parent;
488
0
      while (cur) {
489
0
    if (cur == node1)
490
0
        return(-1);
491
0
    cur = cur->parent;
492
0
      }
493
0
  }
494
63.5M
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
114M
    if ((node1->type == XML_ELEMENT_NODE) &&
500
76.8M
  (node2->type == XML_ELEMENT_NODE) &&
501
61.3M
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
55.6k
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
55.6k
  (node1->doc == node2->doc)) {
504
505
55.6k
  l1 = -XML_NODE_SORT_VALUE(node1);
506
55.6k
  l2 = -XML_NODE_SORT_VALUE(node2);
507
55.6k
  if (l1 < l2)
508
55.6k
      return(1);
509
0
  if (l1 > l2)
510
0
      return(-1);
511
0
    }
512
513
422M
turtle_comparison:
514
515
422M
    if (node1 == node2->prev)
516
109M
  return(1);
517
312M
    if (node1 == node2->next)
518
7.87M
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
2.10G
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
1.83G
  if (cur->parent == node1)
524
36.1M
      return(1);
525
1.80G
  depth2++;
526
1.80G
    }
527
268M
    root = cur;
528
1.74G
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
1.48G
  if (cur->parent == node2)
530
16.0M
      return(-1);
531
1.47G
  depth1++;
532
1.47G
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
252M
    if (root != cur) {
537
0
  return(-2);
538
0
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
377M
    while (depth1 > depth2) {
543
125M
  depth1--;
544
125M
  node1 = node1->parent;
545
125M
    }
546
606M
    while (depth2 > depth1) {
547
353M
  depth2--;
548
353M
  node2 = node2->parent;
549
353M
    }
550
298M
    while (node1->parent != node2->parent) {
551
46.1M
  node1 = node1->parent;
552
46.1M
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
46.1M
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
46.1M
    }
557
    /*
558
     * Find who's first.
559
     */
560
252M
    if (node1 == node2->prev)
561
19.0M
  return(1);
562
233M
    if (node1 == node2->next)
563
76.5M
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
157M
    if ((node1->type == XML_ELEMENT_NODE) &&
568
151M
  (node2->type == XML_ELEMENT_NODE) &&
569
148M
  (0 > XML_NODE_SORT_VALUE(node1)) &&
570
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
571
0
  (node1->doc == node2->doc)) {
572
573
0
  l1 = -XML_NODE_SORT_VALUE(node1);
574
0
  l2 = -XML_NODE_SORT_VALUE(node2);
575
0
  if (l1 < l2)
576
0
      return(1);
577
0
  if (l1 > l2)
578
0
      return(-1);
579
0
    }
580
581
14.7G
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
14.6G
  if (cur == node2)
583
70.7M
      return(1);
584
86.4M
    return(-1); /* assume there is no sibling list corruption */
585
157M
}
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
37.2M
#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
431M
    {
607
431M
        int res = xmlXPathCmpNodesExt(x, y);
608
431M
        return res == -2 ? res : -res;
609
431M
    }
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
431M
#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
4.90k
    { 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
38.4k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
38.4k
       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
251
{
678
251
    if (ctxt == NULL)
679
0
        return;
680
251
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
251
                        &ctxt->lastError);
682
251
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
251
{
692
251
    if (ctxt == NULL)
693
0
        return;
694
251
    ctxt->error = XPATH_MEMORY_ERROR;
695
251
    xmlXPathErrMemory(ctxt->context);
696
251
}
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
38.4k
xmlXPathErrFmt(xmlXPathParserContext *ctxt, int code, const char *fmt, ...) {
708
38.4k
    va_list ap;
709
38.4k
    xmlStructuredErrorFunc schannel = NULL;
710
38.4k
    xmlGenericErrorFunc channel = NULL;
711
38.4k
    void *data = NULL;
712
38.4k
    xmlNodePtr node = NULL;
713
38.4k
    int res;
714
715
38.4k
    if (ctxt == NULL)
716
0
        return;
717
38.4k
    if ((code < 0) || (code > MAXERRNO))
718
0
  code = MAXERRNO;
719
    /* Only report the first error */
720
38.4k
    if (ctxt->error != 0)
721
8.08k
        return;
722
723
30.4k
    ctxt->error = code;
724
725
30.4k
    if (ctxt->context != NULL) {
726
30.4k
        xmlErrorPtr err = &ctxt->context->lastError;
727
728
        /* Don't overwrite memory error. */
729
30.4k
        if (err->code == XML_ERR_NO_MEMORY)
730
0
            return;
731
732
        /* cleanup current last error */
733
30.4k
        xmlResetError(err);
734
735
30.4k
        err->domain = XML_FROM_XPATH;
736
30.4k
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
737
30.4k
        err->level = XML_ERR_ERROR;
738
30.4k
        if (ctxt->base != NULL) {
739
30.3k
            err->str1 = (char *) xmlStrdup(ctxt->base);
740
30.3k
            if (err->str1 == NULL) {
741
0
                xmlXPathPErrMemory(ctxt);
742
0
                return;
743
0
            }
744
30.3k
        }
745
30.4k
        err->int1 = ctxt->cur - ctxt->base;
746
30.4k
        err->node = ctxt->context->debugNode;
747
748
30.4k
        schannel = ctxt->context->error;
749
30.4k
        data = ctxt->context->userData;
750
30.4k
        node = ctxt->context->debugNode;
751
30.4k
    }
752
753
30.4k
    if (schannel == NULL) {
754
30.4k
        channel = xmlGenericError;
755
30.4k
        data = xmlGenericErrorContext;
756
30.4k
    }
757
758
30.4k
    va_start(ap, fmt);
759
30.4k
    res = xmlVRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
760
30.4k
                         code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
761
30.4k
                         XML_ERR_ERROR, NULL, 0,
762
30.4k
                         (const char *) ctxt->base, NULL, NULL,
763
30.4k
                         ctxt->cur - ctxt->base, 0,
764
30.4k
                         fmt, ap);
765
30.4k
    va_end(ap);
766
30.4k
    if (res < 0)
767
0
        xmlXPathPErrMemory(ctxt);
768
30.4k
}
769
770
/**
771
 * Handle an XPath error
772
 *
773
 * @param ctxt  a XPath parser context
774
 * @param code  the error code
775
 */
776
void
777
36.3k
xmlXPathErr(xmlXPathParserContext *ctxt, int code) {
778
36.3k
    xmlXPathErrFmt(ctxt, code, "%s\n", xmlXPathErrorMessages[code]);
779
36.3k
}
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
4.74k
              int line ATTRIBUTE_UNUSED, int no) {
792
4.74k
    xmlXPathErr(ctxt, no);
793
4.74k
}
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
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
804
0
    xmlXPathContextPtr xpctxt = ctxt->context;
805
806
0
    if ((opCount > xpctxt->opLimit) ||
807
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
808
0
        xpctxt->opCount = xpctxt->opLimit;
809
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
810
0
        return(-1);
811
0
    }
812
813
0
    xpctxt->opCount += opCount;
814
0
    return(0);
815
0
}
816
817
#define OP_LIMIT_EXCEEDED(ctxt, n) \
818
1.23G
    ((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
89.8k
xmlXPathNewCompExpr(void) {
941
89.8k
    xmlXPathCompExprPtr cur;
942
943
89.8k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
944
89.8k
    if (cur == NULL)
945
0
  return(NULL);
946
89.8k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
947
89.8k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
948
89.8k
    cur->maxStep = 1;
949
#else
950
    cur->maxStep = 10;
951
#endif
952
89.8k
    cur->nbStep = 0;
953
89.8k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
954
89.8k
                                     sizeof(xmlXPathStepOp));
955
89.8k
    if (cur->steps == NULL) {
956
0
  xmlFree(cur);
957
0
  return(NULL);
958
0
    }
959
89.8k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
960
89.8k
    cur->last = -1;
961
89.8k
    return(cur);
962
89.8k
}
963
964
/**
965
 * Free up the memory allocated by `comp`
966
 *
967
 * @param comp  an XPATH comp
968
 */
969
void
970
xmlXPathFreeCompExpr(xmlXPathCompExpr *comp)
971
89.8k
{
972
89.8k
    xmlXPathStepOpPtr op;
973
89.8k
    int i;
974
975
89.8k
    if (comp == NULL)
976
0
        return;
977
89.8k
    if (comp->dict == NULL) {
978
80.4M
  for (i = 0; i < comp->nbStep; i++) {
979
80.3M
      op = &comp->steps[i];
980
80.3M
      if (op->value4 != NULL) {
981
453k
    if (op->op == XPATH_OP_VALUE)
982
351k
        xmlXPathFreeObject(op->value4);
983
101k
    else
984
101k
        xmlFree(op->value4);
985
453k
      }
986
80.3M
      if (op->value5 != NULL)
987
481k
    xmlFree(op->value5);
988
80.3M
  }
989
60.1k
    } else {
990
440k
  for (i = 0; i < comp->nbStep; i++) {
991
410k
      op = &comp->steps[i];
992
410k
      if (op->value4 != NULL) {
993
10.1k
    if (op->op == XPATH_OP_VALUE)
994
6.83k
        xmlXPathFreeObject(op->value4);
995
10.1k
      }
996
410k
  }
997
29.7k
        xmlDictFree(comp->dict);
998
29.7k
    }
999
89.8k
    if (comp->steps != NULL) {
1000
89.8k
        xmlFree(comp->steps);
1001
89.8k
    }
1002
#ifdef XPATH_STREAMING
1003
    if (comp->stream != NULL) {
1004
        xmlFreePatternList(comp->stream);
1005
    }
1006
#endif
1007
89.8k
    if (comp->expr != NULL) {
1008
12.5k
        xmlFree(comp->expr);
1009
12.5k
    }
1010
1011
89.8k
    xmlFree(comp);
1012
89.8k
}
1013
1014
/**
1015
 * Add a step to an XPath Compiled Expression
1016
 *
1017
 * @param ctxt  XPath parser context
1018
 * @param ch1  first child index
1019
 * @param ch2  second child index
1020
 * @param op  an op
1021
 * @param value  the first int value
1022
 * @param value2  the second int value
1023
 * @param value3  the third int value
1024
 * @param value4  the first string value
1025
 * @param value5  the second string value
1026
 * @returns -1 in case of failure, the index otherwise
1027
 */
1028
static int
1029
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1030
   xmlXPathOp op, int value,
1031
80.7M
   int value2, int value3, void *value4, void *value5) {
1032
80.7M
    xmlXPathCompExprPtr comp = ctxt->comp;
1033
80.7M
    if (comp->nbStep >= comp->maxStep) {
1034
375k
  xmlXPathStepOp *real;
1035
375k
        int newSize;
1036
1037
375k
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1038
375k
                                  10, XPATH_MAX_STEPS);
1039
375k
        if (newSize < 0) {
1040
251
      xmlXPathPErrMemory(ctxt);
1041
251
      return(-1);
1042
251
        }
1043
375k
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1044
375k
  if (real == NULL) {
1045
0
      xmlXPathPErrMemory(ctxt);
1046
0
      return(-1);
1047
0
  }
1048
375k
  comp->steps = real;
1049
375k
  comp->maxStep = newSize;
1050
375k
    }
1051
80.7M
    comp->last = comp->nbStep;
1052
80.7M
    comp->steps[comp->nbStep].ch1 = ch1;
1053
80.7M
    comp->steps[comp->nbStep].ch2 = ch2;
1054
80.7M
    comp->steps[comp->nbStep].op = op;
1055
80.7M
    comp->steps[comp->nbStep].value = value;
1056
80.7M
    comp->steps[comp->nbStep].value2 = value2;
1057
80.7M
    comp->steps[comp->nbStep].value3 = value3;
1058
80.7M
    if ((comp->dict != NULL) &&
1059
410k
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1060
408k
   (op == XPATH_OP_COLLECT))) {
1061
136k
        if (value4 != NULL) {
1062
3.36k
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1063
3.36k
          (void *)xmlDictLookup(comp->dict, value4, -1);
1064
3.36k
      xmlFree(value4);
1065
3.36k
  } else
1066
133k
      comp->steps[comp->nbStep].value4 = NULL;
1067
136k
        if (value5 != NULL) {
1068
26.9k
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1069
26.9k
          (void *)xmlDictLookup(comp->dict, value5, -1);
1070
26.9k
      xmlFree(value5);
1071
26.9k
  } else
1072
109k
      comp->steps[comp->nbStep].value5 = NULL;
1073
80.6M
    } else {
1074
80.6M
  comp->steps[comp->nbStep].value4 = value4;
1075
80.6M
  comp->steps[comp->nbStep].value5 = value5;
1076
80.6M
    }
1077
80.7M
    comp->steps[comp->nbStep].cache = NULL;
1078
80.7M
    return(comp->nbStep++);
1079
80.7M
}
1080
1081
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1082
26.3M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1083
26.3M
                  (op), (val), (val2), (val3), (val4), (val5))
1084
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1085
564k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1086
564k
                  (op), (val), (val2), (val3), (val4), (val5))
1087
1088
26.5M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1089
26.5M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1090
1091
555k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1092
555k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1093
1094
26.7M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1095
26.7M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1096
26.7M
      (val), (val2), 0 ,NULL ,NULL)
1097
1098
/************************************************************************
1099
 *                  *
1100
 *    XPath object cache structures       *
1101
 *                  *
1102
 ************************************************************************/
1103
1104
/* #define XP_DEFAULT_CACHE_ON */
1105
1106
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1107
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1108
struct _xmlXPathContextCache {
1109
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1110
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1111
    int numNodeset;
1112
    int maxNodeset;
1113
    int numMisc;
1114
    int maxMisc;
1115
};
1116
1117
/************************************************************************
1118
 *                  *
1119
 *    Debugging related functions       *
1120
 *                  *
1121
 ************************************************************************/
1122
1123
#ifdef LIBXML_DEBUG_ENABLED
1124
static void
1125
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
9.93k
{
1516
9.93k
    xmlXPathContextCachePtr ret;
1517
1518
9.93k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1519
9.93k
    if (ret == NULL)
1520
0
  return(NULL);
1521
9.93k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1522
9.93k
    ret->maxNodeset = 100;
1523
9.93k
    ret->maxMisc = 100;
1524
9.93k
    return(ret);
1525
9.93k
}
1526
1527
static void
1528
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1529
857
{
1530
11.8k
    while (list != NULL) {
1531
11.0k
        xmlXPathObjectPtr next;
1532
1533
11.0k
        next = (void *) list->stringval;
1534
1535
11.0k
  if (list->nodesetval != NULL) {
1536
10.8k
      if (list->nodesetval->nodeTab != NULL)
1537
8.57k
    xmlFree(list->nodesetval->nodeTab);
1538
10.8k
      xmlFree(list->nodesetval);
1539
10.8k
  }
1540
11.0k
  xmlFree(list);
1541
1542
11.0k
        list = next;
1543
11.0k
    }
1544
857
}
1545
1546
static void
1547
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1548
9.93k
{
1549
9.93k
    if (cache == NULL)
1550
0
  return;
1551
9.93k
    if (cache->nodesetObjs)
1552
768
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1553
9.93k
    if (cache->miscObjs)
1554
89
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1555
9.93k
    xmlFree(cache);
1556
9.93k
}
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
9.93k
{
1582
9.93k
    if (ctxt == NULL)
1583
0
  return(-1);
1584
9.93k
    if (active) {
1585
9.93k
  xmlXPathContextCachePtr cache;
1586
1587
9.93k
  if (ctxt->cache == NULL) {
1588
9.93k
      ctxt->cache = xmlXPathNewCache();
1589
9.93k
      if (ctxt->cache == NULL) {
1590
0
                xmlXPathErrMemory(ctxt);
1591
0
    return(-1);
1592
0
            }
1593
9.93k
  }
1594
9.93k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1595
9.93k
  if (options == 0) {
1596
9.93k
      if (value < 0)
1597
9.93k
    value = 100;
1598
9.93k
      cache->maxNodeset = value;
1599
9.93k
      cache->maxMisc = value;
1600
9.93k
  }
1601
9.93k
    } else if (ctxt->cache != NULL) {
1602
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1603
0
  ctxt->cache = NULL;
1604
0
    }
1605
9.93k
    return(0);
1606
9.93k
}
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
69.0M
{
1621
69.0M
    xmlXPathObjectPtr ret;
1622
69.0M
    xmlXPathContextPtr ctxt = pctxt->context;
1623
1624
69.0M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1625
800k
  xmlXPathContextCachePtr cache =
1626
800k
      (xmlXPathContextCachePtr) ctxt->cache;
1627
1628
800k
  if (cache->miscObjs != NULL) {
1629
162k
      ret = cache->miscObjs;
1630
162k
            cache->miscObjs = (void *) ret->stringval;
1631
162k
            cache->numMisc -= 1;
1632
162k
            ret->stringval = NULL;
1633
162k
      ret->type = XPATH_NODESET;
1634
162k
      ret->nodesetval = val;
1635
162k
      return(ret);
1636
162k
  }
1637
800k
    }
1638
1639
68.9M
    ret = xmlXPathWrapNodeSet(val);
1640
68.9M
    if (ret == NULL)
1641
0
        xmlXPathPErrMemory(pctxt);
1642
68.9M
    return(ret);
1643
69.0M
}
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
8.41M
{
1656
8.41M
    xmlXPathObjectPtr ret;
1657
8.41M
    xmlXPathContextPtr ctxt = pctxt->context;
1658
1659
8.41M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1660
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1661
1662
0
  if (cache->miscObjs != NULL) {
1663
0
      ret = cache->miscObjs;
1664
0
            cache->miscObjs = (void *) ret->stringval;
1665
0
            cache->numMisc -= 1;
1666
0
      ret->type = XPATH_STRING;
1667
0
      ret->stringval = val;
1668
0
      return(ret);
1669
0
  }
1670
0
    }
1671
1672
8.41M
    ret = xmlXPathWrapString(val);
1673
8.41M
    if (ret == NULL)
1674
0
        xmlXPathPErrMemory(pctxt);
1675
8.41M
    return(ret);
1676
8.41M
}
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
79.6M
{
1690
79.6M
    xmlXPathObjectPtr ret;
1691
79.6M
    xmlXPathContextPtr ctxt = pctxt->context;
1692
1693
79.6M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1694
751k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1695
1696
751k
  if (cache->nodesetObjs != NULL) {
1697
      /*
1698
      * Use the nodeset-cache.
1699
      */
1700
750k
      ret = cache->nodesetObjs;
1701
750k
            cache->nodesetObjs = (void *) ret->stringval;
1702
750k
            cache->numNodeset -= 1;
1703
750k
            ret->stringval = NULL;
1704
750k
      ret->type = XPATH_NODESET;
1705
750k
      ret->boolval = 0;
1706
750k
      if (val) {
1707
750k
    if ((ret->nodesetval->nodeMax == 0) ||
1708
747k
        (val->type == XML_NAMESPACE_DECL))
1709
3.14k
    {
1710
3.14k
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1711
0
                        xmlXPathPErrMemory(pctxt);
1712
747k
    } else {
1713
747k
        ret->nodesetval->nodeTab[0] = val;
1714
747k
        ret->nodesetval->nodeNr = 1;
1715
747k
    }
1716
750k
      }
1717
750k
      return(ret);
1718
750k
  } else if (cache->miscObjs != NULL) {
1719
0
            xmlNodeSetPtr set;
1720
      /*
1721
      * Fallback to misc-cache.
1722
      */
1723
1724
0
      set = xmlXPathNodeSetCreate(val);
1725
0
      if (set == NULL) {
1726
0
                xmlXPathPErrMemory(pctxt);
1727
0
    return(NULL);
1728
0
      }
1729
1730
0
      ret = cache->miscObjs;
1731
0
            cache->miscObjs = (void *) ret->stringval;
1732
0
            cache->numMisc -= 1;
1733
0
            ret->stringval = NULL;
1734
0
      ret->type = XPATH_NODESET;
1735
0
      ret->boolval = 0;
1736
0
      ret->nodesetval = set;
1737
0
      return(ret);
1738
0
  }
1739
751k
    }
1740
78.9M
    ret = xmlXPathNewNodeSet(val);
1741
78.9M
    if (ret == NULL)
1742
0
        xmlXPathPErrMemory(pctxt);
1743
78.9M
    return(ret);
1744
79.6M
}
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
981k
{
1757
981k
    xmlXPathObjectPtr ret;
1758
981k
    xmlXPathContextPtr ctxt = pctxt->context;
1759
1760
981k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1761
63.2k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
63.2k
  if (cache->miscObjs != NULL) {
1764
51.1k
            xmlChar *copy;
1765
1766
51.1k
            if (val == NULL)
1767
0
                val = BAD_CAST "";
1768
51.1k
            copy = xmlStrdup(val);
1769
51.1k
            if (copy == NULL) {
1770
0
                xmlXPathPErrMemory(pctxt);
1771
0
                return(NULL);
1772
0
            }
1773
1774
51.1k
      ret = cache->miscObjs;
1775
51.1k
            cache->miscObjs = (void *) ret->stringval;
1776
51.1k
            cache->numMisc -= 1;
1777
51.1k
      ret->type = XPATH_STRING;
1778
51.1k
            ret->stringval = copy;
1779
51.1k
      return(ret);
1780
51.1k
  }
1781
63.2k
    }
1782
1783
930k
    ret = xmlXPathNewString(val);
1784
930k
    if (ret == NULL)
1785
0
        xmlXPathPErrMemory(pctxt);
1786
930k
    return(ret);
1787
981k
}
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
13.4k
{
1800
13.4k
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1801
13.4k
}
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
46.4M
{
1814
46.4M
    xmlXPathObjectPtr ret;
1815
46.4M
    xmlXPathContextPtr ctxt = pctxt->context;
1816
1817
46.4M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1818
127k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1819
1820
127k
  if (cache->miscObjs != NULL) {
1821
17.1k
      ret = cache->miscObjs;
1822
17.1k
            cache->miscObjs = (void *) ret->stringval;
1823
17.1k
            cache->numMisc -= 1;
1824
17.1k
            ret->stringval = NULL;
1825
17.1k
      ret->type = XPATH_BOOLEAN;
1826
17.1k
      ret->boolval = (val != 0);
1827
17.1k
      return(ret);
1828
17.1k
  }
1829
127k
    }
1830
1831
46.4M
    ret = xmlXPathNewBoolean(val);
1832
46.4M
    if (ret == NULL)
1833
0
        xmlXPathPErrMemory(pctxt);
1834
46.4M
    return(ret);
1835
46.4M
}
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
9.72M
{
1848
9.72M
    xmlXPathObjectPtr ret;
1849
9.72M
    xmlXPathContextPtr ctxt = pctxt->context;
1850
1851
9.72M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1852
138k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1853
1854
138k
  if (cache->miscObjs != NULL) {
1855
128k
      ret = cache->miscObjs;
1856
128k
            cache->miscObjs = (void *) ret->stringval;
1857
128k
            cache->numMisc -= 1;
1858
128k
            ret->stringval = NULL;
1859
128k
      ret->type = XPATH_NUMBER;
1860
128k
      ret->floatval = val;
1861
128k
      return(ret);
1862
128k
  }
1863
138k
    }
1864
1865
9.59M
    ret = xmlXPathNewFloat(val);
1866
9.59M
    if (ret == NULL)
1867
0
        xmlXPathPErrMemory(pctxt);
1868
9.59M
    return(ret);
1869
9.72M
}
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
10.3M
{
1882
10.3M
    xmlXPathObjectPtr ret;
1883
10.3M
    xmlXPathContextPtr ctxt = pctxt->context;
1884
1885
10.3M
    if (val == NULL)
1886
0
  return(NULL);
1887
1888
10.3M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1889
51.0k
  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
80
      case XPATH_STRING:
1901
80
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1902
0
      case XPATH_BOOLEAN:
1903
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1904
50.9k
      case XPATH_NUMBER:
1905
50.9k
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1906
0
      default:
1907
0
    break;
1908
51.0k
  }
1909
51.0k
    }
1910
10.2M
    ret = xmlXPathObjectCopy(val);
1911
10.2M
    if (ret == NULL)
1912
0
        xmlXPathPErrMemory(pctxt);
1913
10.2M
    return(ret);
1914
10.3M
}
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
29.1M
                             xmlXPathObjectPtr val) {
1932
29.1M
    double ret = 0.0;
1933
1934
29.1M
    if (val == NULL)
1935
0
  return(xmlXPathNAN);
1936
29.1M
    switch (val->type) {
1937
0
    case XPATH_UNDEFINED:
1938
0
  ret = xmlXPathNAN;
1939
0
  break;
1940
21.7M
    case XPATH_NODESET:
1941
21.7M
    case XPATH_XSLT_TREE: {
1942
21.7M
        xmlChar *str;
1943
1944
21.7M
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1945
21.7M
        if (str == NULL) {
1946
0
            xmlXPathPErrMemory(ctxt);
1947
0
            ret = xmlXPathNAN;
1948
21.7M
        } else {
1949
21.7M
      ret = xmlXPathCastStringToNumber(str);
1950
21.7M
            xmlFree(str);
1951
21.7M
        }
1952
21.7M
  break;
1953
21.7M
    }
1954
1.71M
    case XPATH_STRING:
1955
1.71M
  ret = xmlXPathCastStringToNumber(val->stringval);
1956
1.71M
  break;
1957
865k
    case XPATH_NUMBER:
1958
865k
  ret = val->floatval;
1959
865k
  break;
1960
4.78M
    case XPATH_BOOLEAN:
1961
4.78M
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1962
4.78M
  break;
1963
0
    case XPATH_USERS:
1964
  /* TODO */
1965
0
  ret = xmlXPathNAN;
1966
0
  break;
1967
29.1M
    }
1968
29.1M
    return(ret);
1969
29.1M
}
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
240M
{
1980
240M
    xmlXPathObjectPtr ret;
1981
1982
240M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1983
58.9k
        return (NULL);
1984
1985
240M
    ctxt->valueNr--;
1986
240M
    if (ctxt->valueNr > 0)
1987
218M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1988
21.9M
    else
1989
21.9M
        ctxt->value = NULL;
1990
240M
    ret = ctxt->valueTab[ctxt->valueNr];
1991
240M
    ctxt->valueTab[ctxt->valueNr] = NULL;
1992
240M
    return (ret);
1993
240M
}
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
240M
{
2008
240M
    if (ctxt == NULL) return(-1);
2009
240M
    if (value == NULL) {
2010
        /*
2011
         * A NULL value typically indicates that a memory allocation failed.
2012
         */
2013
0
        xmlXPathPErrMemory(ctxt);
2014
0
        return(-1);
2015
0
    }
2016
240M
    if (ctxt->valueNr >= ctxt->valueMax) {
2017
136k
        xmlXPathObjectPtr *tmp;
2018
136k
        int newSize;
2019
2020
136k
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2021
136k
                                  10, XPATH_MAX_STACK_DEPTH);
2022
136k
        if (newSize < 0) {
2023
0
            xmlXPathPErrMemory(ctxt);
2024
0
            xmlXPathFreeObject(value);
2025
0
            return (-1);
2026
0
        }
2027
136k
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2028
136k
        if (tmp == NULL) {
2029
0
            xmlXPathPErrMemory(ctxt);
2030
0
            xmlXPathFreeObject(value);
2031
0
            return (-1);
2032
0
        }
2033
136k
  ctxt->valueTab = tmp;
2034
136k
        ctxt->valueMax = newSize;
2035
136k
    }
2036
240M
    ctxt->valueTab[ctxt->valueNr] = value;
2037
240M
    ctxt->value = value;
2038
240M
    return (ctxt->valueNr++);
2039
240M
}
2040
2041
/**
2042
 * Pops a boolean from the stack, handling conversion if needed.
2043
 * Check error with xmlXPathCheckError.
2044
 *
2045
 * @param ctxt  an XPath parser context
2046
 * @returns the boolean
2047
 */
2048
int
2049
0
xmlXPathPopBoolean (xmlXPathParserContext *ctxt) {
2050
0
    xmlXPathObjectPtr obj;
2051
0
    int ret;
2052
2053
0
    obj = xmlXPathValuePop(ctxt);
2054
0
    if (obj == NULL) {
2055
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2056
0
  return(0);
2057
0
    }
2058
0
    if (obj->type != XPATH_BOOLEAN)
2059
0
  ret = xmlXPathCastToBoolean(obj);
2060
0
    else
2061
0
        ret = obj->boolval;
2062
0
    xmlXPathReleaseObject(ctxt->context, obj);
2063
0
    return(ret);
2064
0
}
2065
2066
/**
2067
 * Pops a number from the stack, handling conversion if needed.
2068
 * Check error with xmlXPathCheckError.
2069
 *
2070
 * @param ctxt  an XPath parser context
2071
 * @returns the number
2072
 */
2073
double
2074
0
xmlXPathPopNumber (xmlXPathParserContext *ctxt) {
2075
0
    xmlXPathObjectPtr obj;
2076
0
    double ret;
2077
2078
0
    obj = xmlXPathValuePop(ctxt);
2079
0
    if (obj == NULL) {
2080
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2081
0
  return(0);
2082
0
    }
2083
0
    if (obj->type != XPATH_NUMBER)
2084
0
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2085
0
    else
2086
0
        ret = obj->floatval;
2087
0
    xmlXPathReleaseObject(ctxt->context, obj);
2088
0
    return(ret);
2089
0
}
2090
2091
/**
2092
 * Pops a string from the stack, handling conversion if needed.
2093
 * Check error with xmlXPathCheckError.
2094
 *
2095
 * @param ctxt  an XPath parser context
2096
 * @returns the string
2097
 */
2098
xmlChar *
2099
0
xmlXPathPopString (xmlXPathParserContext *ctxt) {
2100
0
    xmlXPathObjectPtr obj;
2101
0
    xmlChar * ret;
2102
2103
0
    obj = xmlXPathValuePop(ctxt);
2104
0
    if (obj == NULL) {
2105
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2106
0
  return(NULL);
2107
0
    }
2108
0
    ret = xmlXPathCastToString(obj);
2109
0
    if (ret == NULL)
2110
0
        xmlXPathPErrMemory(ctxt);
2111
0
    xmlXPathReleaseObject(ctxt->context, obj);
2112
0
    return(ret);
2113
0
}
2114
2115
/**
2116
 * Pops a node-set from the stack, handling conversion if needed.
2117
 * Check error with xmlXPathCheckError.
2118
 *
2119
 * @param ctxt  an XPath parser context
2120
 * @returns the node-set
2121
 */
2122
xmlNodeSet *
2123
0
xmlXPathPopNodeSet (xmlXPathParserContext *ctxt) {
2124
0
    xmlXPathObjectPtr obj;
2125
0
    xmlNodeSetPtr ret;
2126
2127
0
    if (ctxt == NULL) return(NULL);
2128
0
    if (ctxt->value == NULL) {
2129
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2130
0
  return(NULL);
2131
0
    }
2132
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2133
0
  xmlXPathSetTypeError(ctxt);
2134
0
  return(NULL);
2135
0
    }
2136
0
    obj = xmlXPathValuePop(ctxt);
2137
0
    ret = obj->nodesetval;
2138
0
    obj->nodesetval = NULL;
2139
0
    xmlXPathReleaseObject(ctxt->context, obj);
2140
0
    return(ret);
2141
0
}
2142
2143
/**
2144
 * Pops an external object from the stack, handling conversion if needed.
2145
 * Check error with xmlXPathCheckError.
2146
 *
2147
 * @param ctxt  an XPath parser context
2148
 * @returns the object
2149
 */
2150
void *
2151
0
xmlXPathPopExternal (xmlXPathParserContext *ctxt) {
2152
0
    xmlXPathObjectPtr obj;
2153
0
    void * ret;
2154
2155
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2156
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2157
0
  return(NULL);
2158
0
    }
2159
0
    if (ctxt->value->type != XPATH_USERS) {
2160
0
  xmlXPathSetTypeError(ctxt);
2161
0
  return(NULL);
2162
0
    }
2163
0
    obj = xmlXPathValuePop(ctxt);
2164
0
    ret = obj->user;
2165
0
    obj->user = NULL;
2166
0
    xmlXPathReleaseObject(ctxt->context, obj);
2167
0
    return(ret);
2168
0
}
2169
2170
/*
2171
 * Macros for accessing the content. Those should be used only by the parser,
2172
 * and not exported.
2173
 *
2174
 * Dirty macros, i.e. one need to make assumption on the context to use them
2175
 *
2176
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2177
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2178
 *           in ISO-Latin or UTF-8.
2179
 *           This should be used internally by the parser
2180
 *           only to compare to ASCII values otherwise it would break when
2181
 *           running with UTF-8 encoding.
2182
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2183
 *           to compare on ASCII based substring.
2184
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2185
 *           strings within the parser.
2186
 *   CURRENT Returns the current char value, with the full decoding of
2187
 *           UTF-8 if we are using this mode. It returns an int.
2188
 *   NEXT    Skip to the next character, this does the proper decoding
2189
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2190
 *           It returns the pointer to the current xmlChar.
2191
 */
2192
2193
572M
#define CUR (*ctxt->cur)
2194
201k
#define SKIP(val) ctxt->cur += (val)
2195
8.37M
#define NXT(val) ctxt->cur[(val)]
2196
15.5M
#define CUR_PTR ctxt->cur
2197
2198
#define SKIP_BLANKS             \
2199
328M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2200
2201
#define CURRENT (*ctxt->cur)
2202
243M
#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
4.80k
#define UPPER_DOUBLE 1E9
2213
2.25k
#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
3.36k
#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
8.55k
{
2230
8.55k
    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
8.55k
    default:
2240
8.55k
  if (xmlXPathIsNaN(number)) {
2241
0
      if (buffersize > (int)sizeof("NaN"))
2242
0
    snprintf(buffer, buffersize, "NaN");
2243
8.55k
  } else if (number == 0) {
2244
            /* Omit sign for negative zero. */
2245
0
      snprintf(buffer, buffersize, "0");
2246
8.55k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2247
5.99k
                   (number == (int) number)) {
2248
3.74k
      char work[30];
2249
3.74k
      char *ptr, *cur;
2250
3.74k
      int value = (int) number;
2251
2252
3.74k
            ptr = &buffer[0];
2253
3.74k
      if (value == 0) {
2254
0
    *ptr++ = '0';
2255
3.74k
      } else {
2256
3.74k
    snprintf(work, 29, "%d", value);
2257
3.74k
    cur = &work[0];
2258
14.8k
    while ((*cur) && (ptr - buffer < buffersize)) {
2259
11.0k
        *ptr++ = *cur++;
2260
11.0k
    }
2261
3.74k
      }
2262
3.74k
      if (ptr - buffer < buffersize) {
2263
3.74k
    *ptr = 0;
2264
3.74k
      } else if (buffersize > 0) {
2265
0
    ptr--;
2266
0
    *ptr = 0;
2267
0
      }
2268
4.80k
  } 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
4.80k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2279
4.80k
      int integer_place, fraction_place;
2280
4.80k
      char *ptr;
2281
4.80k
      char *after_fraction;
2282
4.80k
      double absolute_value;
2283
4.80k
      int size;
2284
2285
4.80k
      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
4.80k
      if ( ((absolute_value > UPPER_DOUBLE) ||
2293
2.25k
      (absolute_value < LOWER_DOUBLE)) &&
2294
3.36k
     (absolute_value != 0.0) ) {
2295
    /* Use scientific notation */
2296
3.36k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2297
3.36k
    fraction_place = DBL_DIG - 1;
2298
3.36k
    size = snprintf(work, sizeof(work),"%*.*e",
2299
3.36k
       integer_place, fraction_place, number);
2300
17.2k
    while ((size > 0) && (work[size] != 'e')) size--;
2301
2302
3.36k
      }
2303
1.44k
      else {
2304
    /* Use regular notation */
2305
1.44k
    if (absolute_value > 0.0) {
2306
1.44k
        integer_place = (int)log10(absolute_value);
2307
1.44k
        if (integer_place > 0)
2308
874
            fraction_place = DBL_DIG - integer_place - 1;
2309
566
        else
2310
566
            fraction_place = DBL_DIG - integer_place;
2311
1.44k
    } else {
2312
0
        fraction_place = 1;
2313
0
    }
2314
1.44k
    size = snprintf(work, sizeof(work), "%0.*f",
2315
1.44k
        fraction_place, number);
2316
1.44k
      }
2317
2318
      /* Remove leading spaces sometimes inserted by snprintf */
2319
6.91k
      while (work[0] == ' ') {
2320
44.2k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2321
2.10k
    size--;
2322
2.10k
      }
2323
2324
      /* Remove fractional trailing zeroes */
2325
4.80k
      after_fraction = work + size;
2326
4.80k
      ptr = after_fraction;
2327
41.3k
      while (*(--ptr) == '0')
2328
36.5k
    ;
2329
4.80k
      if (*ptr != '.')
2330
3.91k
          ptr++;
2331
18.6k
      while ((*ptr++ = *after_fraction++) != 0);
2332
2333
      /* Finally copy result back to caller */
2334
4.80k
      size = strlen(work) + 1;
2335
4.80k
      if (size > buffersize) {
2336
0
    work[buffersize - 1] = 0;
2337
0
    size = buffersize;
2338
0
      }
2339
4.80k
      memmove(buffer, work, size);
2340
4.80k
  }
2341
8.55k
  break;
2342
8.55k
    }
2343
8.55k
}
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
2.30k
xmlXPathOrderDocElems(xmlDoc *doc) {
2365
2.30k
    XML_INTPTR_T count = 0;
2366
2.30k
    xmlNodePtr cur;
2367
2368
2.30k
    if (doc == NULL)
2369
0
  return(-1);
2370
2.30k
    cur = doc->children;
2371
589k
    while (cur != NULL) {
2372
587k
  if (cur->type == XML_ELEMENT_NODE) {
2373
188k
            count += 1;
2374
188k
            cur->content = XML_INT_TO_PTR(-count);
2375
188k
      if (cur->children != NULL) {
2376
80.6k
    cur = cur->children;
2377
80.6k
    continue;
2378
80.6k
      }
2379
188k
  }
2380
506k
  if (cur->next != NULL) {
2381
451k
      cur = cur->next;
2382
451k
      continue;
2383
451k
  }
2384
82.9k
  do {
2385
82.9k
      cur = cur->parent;
2386
82.9k
      if (cur == NULL)
2387
0
    break;
2388
82.9k
      if (cur == (xmlNodePtr) doc) {
2389
2.30k
    cur = NULL;
2390
2.30k
    break;
2391
2.30k
      }
2392
80.6k
      if (cur->next != NULL) {
2393
52.1k
    cur = cur->next;
2394
52.1k
    break;
2395
52.1k
      }
2396
80.6k
  } while (cur != NULL);
2397
54.4k
    }
2398
2.30k
    return(count);
2399
2.30k
}
2400
2401
/**
2402
 * Compare two nodes w.r.t document order
2403
 *
2404
 * @param node1  the first node
2405
 * @param node2  the second node
2406
 * @returns -2 in case of error 1 if first point < second point, 0 if
2407
 *         it's the same node, -1 otherwise
2408
 */
2409
int
2410
0
xmlXPathCmpNodes(xmlNode *node1, xmlNode *node2) {
2411
0
    int depth1, depth2;
2412
0
    int attr1 = 0, attr2 = 0;
2413
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2414
0
    xmlNodePtr cur, root;
2415
2416
0
    if ((node1 == NULL) || (node2 == NULL))
2417
0
  return(-2);
2418
    /*
2419
     * a couple of optimizations which will avoid computations in most cases
2420
     */
2421
0
    if (node1 == node2)   /* trivial case */
2422
0
  return(0);
2423
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2424
0
  attr1 = 1;
2425
0
  attrNode1 = node1;
2426
0
  node1 = node1->parent;
2427
0
    }
2428
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2429
0
  attr2 = 1;
2430
0
  attrNode2 = node2;
2431
0
  node2 = node2->parent;
2432
0
    }
2433
0
    if (node1 == node2) {
2434
0
  if (attr1 == attr2) {
2435
      /* not required, but we keep attributes in order */
2436
0
      if (attr1 != 0) {
2437
0
          cur = attrNode2->prev;
2438
0
    while (cur != NULL) {
2439
0
        if (cur == attrNode1)
2440
0
            return (1);
2441
0
        cur = cur->prev;
2442
0
    }
2443
0
    return (-1);
2444
0
      }
2445
0
      return(0);
2446
0
  }
2447
0
  if (attr2 == 1)
2448
0
      return(1);
2449
0
  return(-1);
2450
0
    }
2451
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2452
0
        (node2->type == XML_NAMESPACE_DECL))
2453
0
  return(1);
2454
0
    if (node1 == node2->prev)
2455
0
  return(1);
2456
0
    if (node1 == node2->next)
2457
0
  return(-1);
2458
2459
    /*
2460
     * Speedup using document order if available.
2461
     */
2462
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2463
0
  (node2->type == XML_ELEMENT_NODE) &&
2464
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2465
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2466
0
  (node1->doc == node2->doc)) {
2467
0
  XML_INTPTR_T l1, l2;
2468
2469
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2470
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2471
0
  if (l1 < l2)
2472
0
      return(1);
2473
0
  if (l1 > l2)
2474
0
      return(-1);
2475
0
    }
2476
2477
    /*
2478
     * compute depth to root
2479
     */
2480
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2481
0
  if (cur->parent == node1)
2482
0
      return(1);
2483
0
  depth2++;
2484
0
    }
2485
0
    root = cur;
2486
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2487
0
  if (cur->parent == node2)
2488
0
      return(-1);
2489
0
  depth1++;
2490
0
    }
2491
    /*
2492
     * Distinct document (or distinct entities :-( ) case.
2493
     */
2494
0
    if (root != cur) {
2495
0
  return(-2);
2496
0
    }
2497
    /*
2498
     * get the nearest common ancestor.
2499
     */
2500
0
    while (depth1 > depth2) {
2501
0
  depth1--;
2502
0
  node1 = node1->parent;
2503
0
    }
2504
0
    while (depth2 > depth1) {
2505
0
  depth2--;
2506
0
  node2 = node2->parent;
2507
0
    }
2508
0
    while (node1->parent != node2->parent) {
2509
0
  node1 = node1->parent;
2510
0
  node2 = node2->parent;
2511
  /* should not happen but just in case ... */
2512
0
  if ((node1 == NULL) || (node2 == NULL))
2513
0
      return(-2);
2514
0
    }
2515
    /*
2516
     * Find who's first.
2517
     */
2518
0
    if (node1 == node2->prev)
2519
0
  return(1);
2520
0
    if (node1 == node2->next)
2521
0
  return(-1);
2522
    /*
2523
     * Speedup using document order if available.
2524
     */
2525
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2526
0
  (node2->type == XML_ELEMENT_NODE) &&
2527
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2528
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2529
0
  (node1->doc == node2->doc)) {
2530
0
  XML_INTPTR_T l1, l2;
2531
2532
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2533
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2534
0
  if (l1 < l2)
2535
0
      return(1);
2536
0
  if (l1 > l2)
2537
0
      return(-1);
2538
0
    }
2539
2540
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2541
0
  if (cur == node2)
2542
0
      return(1);
2543
0
    return(-1); /* assume there is no sibling list corruption */
2544
0
}
2545
2546
/**
2547
 * Sort the node set in document order
2548
 *
2549
 * @param set  the node set
2550
 */
2551
void
2552
857k
xmlXPathNodeSetSort(xmlNodeSet *set) {
2553
#ifndef WITH_TIM_SORT
2554
    int i, j, incr, len;
2555
    xmlNodePtr tmp;
2556
#endif
2557
2558
857k
    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
857k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2590
857k
#endif /* WITH_TIM_SORT */
2591
857k
}
2592
2593
290M
#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
11.0M
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2605
11.0M
    xmlNsPtr cur;
2606
2607
11.0M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2608
0
  return(NULL);
2609
11.0M
    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
11.0M
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2616
11.0M
    if (cur == NULL)
2617
0
  return(NULL);
2618
11.0M
    memset(cur, 0, sizeof(xmlNs));
2619
11.0M
    cur->type = XML_NAMESPACE_DECL;
2620
11.0M
    if (ns->href != NULL) {
2621
11.0M
  cur->href = xmlStrdup(ns->href);
2622
11.0M
        if (cur->href == NULL) {
2623
0
            xmlFree(cur);
2624
0
            return(NULL);
2625
0
        }
2626
11.0M
    }
2627
11.0M
    if (ns->prefix != NULL) {
2628
8.44M
  cur->prefix = xmlStrdup(ns->prefix);
2629
8.44M
        if (cur->prefix == NULL) {
2630
0
            xmlFree((xmlChar *) cur->href);
2631
0
            xmlFree(cur);
2632
0
            return(NULL);
2633
0
        }
2634
8.44M
    }
2635
11.0M
    cur->next = (xmlNsPtr) node;
2636
11.0M
    return((xmlNodePtr) cur);
2637
11.0M
}
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
11.0M
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2648
11.0M
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2649
0
  return;
2650
2651
11.0M
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2652
11.0M
  if (ns->href != NULL)
2653
11.0M
      xmlFree((xmlChar *)ns->href);
2654
11.0M
  if (ns->prefix != NULL)
2655
8.44M
      xmlFree((xmlChar *)ns->prefix);
2656
11.0M
  xmlFree(ns);
2657
11.0M
    }
2658
11.0M
}
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
171M
xmlXPathNodeSetCreate(xmlNode *val) {
2668
171M
    xmlNodeSetPtr ret;
2669
2670
171M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2671
171M
    if (ret == NULL)
2672
0
  return(NULL);
2673
171M
    memset(ret, 0 , sizeof(xmlNodeSet));
2674
171M
    if (val != NULL) {
2675
78.9M
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2676
78.9M
               sizeof(xmlNodePtr));
2677
78.9M
  if (ret->nodeTab == NULL) {
2678
0
      xmlFree(ret);
2679
0
      return(NULL);
2680
0
  }
2681
78.9M
  memset(ret->nodeTab, 0 ,
2682
78.9M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2683
78.9M
        ret->nodeMax = XML_NODESET_DEFAULT;
2684
78.9M
  if (val->type == XML_NAMESPACE_DECL) {
2685
8.49M
      xmlNsPtr ns = (xmlNsPtr) val;
2686
8.49M
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2687
2688
8.49M
            if (nsNode == NULL) {
2689
0
                xmlXPathFreeNodeSet(ret);
2690
0
                return(NULL);
2691
0
            }
2692
8.49M
      ret->nodeTab[ret->nodeNr++] = nsNode;
2693
8.49M
  } else
2694
70.4M
      ret->nodeTab[ret->nodeNr++] = val;
2695
78.9M
    }
2696
171M
    return(ret);
2697
171M
}
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
203M
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2708
203M
    int i;
2709
2710
203M
    if ((cur == NULL) || (val == NULL)) return(0);
2711
203M
    if (val->type == XML_NAMESPACE_DECL) {
2712
2.41G
  for (i = 0; i < cur->nodeNr; i++) {
2713
2.40G
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2714
1.19G
    xmlNsPtr ns1, ns2;
2715
2716
1.19G
    ns1 = (xmlNsPtr) val;
2717
1.19G
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2718
1.19G
    if (ns1 == ns2)
2719
0
        return(1);
2720
1.19G
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2721
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2722
0
        return(1);
2723
1.19G
      }
2724
2.40G
  }
2725
188M
    } else {
2726
2.39G
  for (i = 0; i < cur->nodeNr; i++) {
2727
2.24G
      if (cur->nodeTab[i] == val)
2728
40.8M
    return(1);
2729
2.24G
  }
2730
188M
    }
2731
162M
    return(0);
2732
203M
}
2733
2734
static int
2735
49.9M
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2736
49.9M
    xmlNodePtr *temp;
2737
49.9M
    int newSize;
2738
2739
49.9M
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2740
49.9M
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2741
49.9M
    if (newSize < 0)
2742
0
        return(-1);
2743
49.9M
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2744
49.9M
    if (temp == NULL)
2745
0
        return(-1);
2746
49.9M
    cur->nodeMax = newSize;
2747
49.9M
    cur->nodeTab = temp;
2748
2749
49.9M
    return(0);
2750
49.9M
}
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.22M
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2762
1.22M
    int i;
2763
1.22M
    xmlNodePtr nsNode;
2764
2765
1.22M
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2766
1.22M
        (ns->type != XML_NAMESPACE_DECL) ||
2767
1.22M
  (node->type != XML_ELEMENT_NODE))
2768
0
  return(-1);
2769
2770
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2771
    /*
2772
     * prevent duplicates
2773
     */
2774
2.13M
    for (i = 0;i < cur->nodeNr;i++) {
2775
908k
        if ((cur->nodeTab[i] != NULL) &&
2776
908k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2777
908k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2778
908k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2779
0
      return(0);
2780
908k
    }
2781
2782
    /*
2783
     * grow the nodeTab if needed
2784
     */
2785
1.22M
    if (cur->nodeNr >= cur->nodeMax) {
2786
37.7k
        if (xmlXPathNodeSetGrow(cur) < 0)
2787
0
            return(-1);
2788
37.7k
    }
2789
1.22M
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2790
1.22M
    if(nsNode == NULL)
2791
0
        return(-1);
2792
1.22M
    cur->nodeTab[cur->nodeNr++] = nsNode;
2793
1.22M
    return(0);
2794
1.22M
}
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
198k
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2805
198k
    int i;
2806
2807
198k
    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
164M
    for (i = 0;i < cur->nodeNr;i++)
2814
164M
        if (cur->nodeTab[i] == val) return(0);
2815
2816
    /*
2817
     * grow the nodeTab if needed
2818
     */
2819
195k
    if (cur->nodeNr >= cur->nodeMax) {
2820
141k
        if (xmlXPathNodeSetGrow(cur) < 0)
2821
0
            return(-1);
2822
141k
    }
2823
2824
195k
    if (val->type == XML_NAMESPACE_DECL) {
2825
0
  xmlNsPtr ns = (xmlNsPtr) val;
2826
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2827
2828
0
        if (nsNode == NULL)
2829
0
            return(-1);
2830
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2831
0
    } else
2832
195k
  cur->nodeTab[cur->nodeNr++] = val;
2833
195k
    return(0);
2834
195k
}
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
446M
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2846
446M
    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
446M
    if (cur->nodeNr >= cur->nodeMax) {
2853
43.7M
        if (xmlXPathNodeSetGrow(cur) < 0)
2854
0
            return(-1);
2855
43.7M
    }
2856
2857
446M
    if (val->type == XML_NAMESPACE_DECL) {
2858
78.6k
  xmlNsPtr ns = (xmlNsPtr) val;
2859
78.6k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2860
2861
78.6k
        if (nsNode == NULL)
2862
0
            return(-1);
2863
78.6k
  cur->nodeTab[cur->nodeNr++] = nsNode;
2864
78.6k
    } else
2865
446M
  cur->nodeTab[cur->nodeNr++] = val;
2866
446M
    return(0);
2867
446M
}
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
366k
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2881
366k
    int i, j, initNr, skip;
2882
366k
    xmlNodePtr n1, n2;
2883
2884
366k
    if (val1 == NULL) {
2885
0
  val1 = xmlXPathNodeSetCreate(NULL);
2886
0
        if (val1 == NULL)
2887
0
            return (NULL);
2888
0
    }
2889
366k
    if (val2 == NULL)
2890
0
        return(val1);
2891
2892
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2893
366k
    initNr = val1->nodeNr;
2894
2895
75.5M
    for (i = 0;i < val2->nodeNr;i++) {
2896
75.1M
  n2 = val2->nodeTab[i];
2897
  /*
2898
   * check against duplicates
2899
   */
2900
75.1M
  skip = 0;
2901
6.67G
  for (j = 0; j < initNr; j++) {
2902
6.59G
      n1 = val1->nodeTab[j];
2903
6.59G
      if (n1 == n2) {
2904
361k
    skip = 1;
2905
361k
    break;
2906
6.59G
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2907
3.18M
           (n2->type == XML_NAMESPACE_DECL)) {
2908
6.24k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2909
6.24k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2910
6.24k
      ((xmlNsPtr) n2)->prefix)))
2911
6.24k
    {
2912
6.24k
        skip = 1;
2913
6.24k
        break;
2914
6.24k
    }
2915
6.24k
      }
2916
6.59G
  }
2917
75.1M
  if (skip)
2918
368k
      continue;
2919
2920
  /*
2921
   * grow the nodeTab if needed
2922
   */
2923
74.7M
        if (val1->nodeNr >= val1->nodeMax) {
2924
1.57M
            if (xmlXPathNodeSetGrow(val1) < 0)
2925
0
                goto error;
2926
1.57M
        }
2927
74.7M
  if (n2->type == XML_NAMESPACE_DECL) {
2928
1.23M
      xmlNsPtr ns = (xmlNsPtr) n2;
2929
1.23M
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2930
2931
1.23M
            if (nsNode == NULL)
2932
0
                goto error;
2933
1.23M
      val1->nodeTab[val1->nodeNr++] = nsNode;
2934
1.23M
  } else
2935
73.5M
      val1->nodeTab[val1->nodeNr++] = n2;
2936
74.7M
    }
2937
2938
366k
    return(val1);
2939
2940
0
error:
2941
0
    xmlXPathFreeNodeSet(val1);
2942
0
    return(NULL);
2943
366k
}
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
2.19M
{
2959
2.19M
    {
2960
2.19M
  int i, j, initNbSet1;
2961
2.19M
  xmlNodePtr n1, n2;
2962
2963
2.19M
  initNbSet1 = set1->nodeNr;
2964
21.1M
  for (i = 0;i < set2->nodeNr;i++) {
2965
18.9M
      n2 = set2->nodeTab[i];
2966
      /*
2967
      * Skip duplicates.
2968
      */
2969
3.68G
      for (j = 0; j < initNbSet1; j++) {
2970
3.68G
    n1 = set1->nodeTab[j];
2971
3.68G
    if (n1 == n2) {
2972
17.1M
        goto skip_node;
2973
3.67G
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2974
2.10k
        (n2->type == XML_NAMESPACE_DECL))
2975
0
    {
2976
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2977
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2978
0
      ((xmlNsPtr) n2)->prefix)))
2979
0
        {
2980
      /*
2981
      * Free the namespace node.
2982
      */
2983
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
2984
0
      goto skip_node;
2985
0
        }
2986
0
    }
2987
3.68G
      }
2988
      /*
2989
      * grow the nodeTab if needed
2990
      */
2991
1.79M
            if (set1->nodeNr >= set1->nodeMax) {
2992
197k
                if (xmlXPathNodeSetGrow(set1) < 0)
2993
0
                    goto error;
2994
197k
            }
2995
1.79M
      set1->nodeTab[set1->nodeNr++] = n2;
2996
18.9M
skip_node:
2997
18.9M
            set2->nodeTab[i] = NULL;
2998
18.9M
  }
2999
2.19M
    }
3000
2.19M
    set2->nodeNr = 0;
3001
2.19M
    return(set1);
3002
3003
0
error:
3004
0
    xmlXPathFreeNodeSet(set1);
3005
0
    xmlXPathNodeSetClear(set2, 1);
3006
0
    return(NULL);
3007
2.19M
}
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
16.7M
{
3022
16.7M
    {
3023
16.7M
  int i;
3024
16.7M
  xmlNodePtr n2;
3025
3026
121M
  for (i = 0;i < set2->nodeNr;i++) {
3027
105M
      n2 = set2->nodeTab[i];
3028
105M
            if (set1->nodeNr >= set1->nodeMax) {
3029
4.16M
                if (xmlXPathNodeSetGrow(set1) < 0)
3030
0
                    goto error;
3031
4.16M
            }
3032
105M
      set1->nodeTab[set1->nodeNr++] = n2;
3033
105M
            set2->nodeTab[i] = NULL;
3034
105M
  }
3035
16.7M
    }
3036
16.7M
    set2->nodeNr = 0;
3037
16.7M
    return(set1);
3038
3039
0
error:
3040
0
    xmlXPathFreeNodeSet(set1);
3041
0
    xmlXPathNodeSetClear(set2, 1);
3042
0
    return(NULL);
3043
16.7M
}
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
171M
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3102
171M
    if (obj == NULL) return;
3103
171M
    if (obj->nodeTab != NULL) {
3104
94.3M
  int i;
3105
3106
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3107
676M
  for (i = 0;i < obj->nodeNr;i++)
3108
582M
      if ((obj->nodeTab[i] != NULL) &&
3109
582M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3110
10.3M
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3111
94.3M
  xmlFree(obj->nodeTab);
3112
94.3M
    }
3113
171M
    xmlFree(obj);
3114
171M
}
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
4.21k
{
3128
4.21k
    if ((set == NULL) || (pos >= set->nodeNr))
3129
0
  return;
3130
4.21k
    else if ((hasNsNodes)) {
3131
1.51k
  int i;
3132
1.51k
  xmlNodePtr node;
3133
3134
12.0k
  for (i = pos; i < set->nodeNr; i++) {
3135
10.4k
      node = set->nodeTab[i];
3136
10.4k
      if ((node != NULL) &&
3137
10.4k
    (node->type == XML_NAMESPACE_DECL))
3138
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3139
10.4k
  }
3140
1.51k
    }
3141
4.21k
    set->nodeNr = pos;
3142
4.21k
}
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
2.70k
{
3155
2.70k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3156
2.70k
}
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
0
{
3168
0
    int i;
3169
0
    xmlNodePtr node;
3170
3171
0
    if ((set == NULL) || (set->nodeNr <= 1))
3172
0
  return;
3173
0
    for (i = 0; i < set->nodeNr - 1; i++) {
3174
0
        node = set->nodeTab[i];
3175
0
        if ((node != NULL) &&
3176
0
            (node->type == XML_NAMESPACE_DECL))
3177
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3178
0
    }
3179
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3180
0
    set->nodeNr = 1;
3181
0
}
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
78.9M
xmlXPathNewNodeSet(xmlNode *val) {
3192
78.9M
    xmlXPathObjectPtr ret;
3193
3194
78.9M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3195
78.9M
    if (ret == NULL)
3196
0
  return(NULL);
3197
78.9M
    memset(ret, 0 , sizeof(xmlXPathObject));
3198
78.9M
    ret->type = XPATH_NODESET;
3199
78.9M
    ret->boolval = 0;
3200
78.9M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3201
78.9M
    if (ret->nodesetval == NULL) {
3202
0
        xmlFree(ret);
3203
0
        return(NULL);
3204
0
    }
3205
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3206
78.9M
    return(ret);
3207
78.9M
}
3208
3209
/**
3210
 * Create a new xmlXPathObject of type Value Tree (XSLT) and initialize
3211
 * it with the tree root `val`
3212
 *
3213
 * @param val  the NodePtr value
3214
 * @returns the newly created object.
3215
 */
3216
xmlXPathObject *
3217
0
xmlXPathNewValueTree(xmlNode *val) {
3218
0
    xmlXPathObjectPtr ret;
3219
3220
0
    ret = xmlXPathNewNodeSet(val);
3221
0
    if (ret == NULL)
3222
0
  return(NULL);
3223
0
    ret->type = XPATH_XSLT_TREE;
3224
3225
0
    return(ret);
3226
0
}
3227
3228
/**
3229
 * Create a new xmlXPathObject of type NodeSet and initialize
3230
 * it with the Nodeset `val`
3231
 *
3232
 * @param val  an existing NodeSet
3233
 * @returns the newly created object.
3234
 */
3235
xmlXPathObject *
3236
xmlXPathNewNodeSetList(xmlNodeSet *val)
3237
0
{
3238
0
    xmlXPathObjectPtr ret;
3239
3240
0
    if (val == NULL)
3241
0
        ret = NULL;
3242
0
    else if (val->nodeTab == NULL)
3243
0
        ret = xmlXPathNewNodeSet(NULL);
3244
0
    else {
3245
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3246
0
        if (ret) {
3247
0
            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3248
0
            if (ret->nodesetval == NULL) {
3249
0
                xmlFree(ret);
3250
0
                return(NULL);
3251
0
            }
3252
0
        }
3253
0
    }
3254
3255
0
    return (ret);
3256
0
}
3257
3258
/**
3259
 * Wrap the Nodeset `val` in a new xmlXPathObject
3260
 *
3261
 * In case of error the node set is destroyed and NULL is returned.
3262
 *
3263
 * @param val  the NodePtr value
3264
 * @returns the newly created object.
3265
 */
3266
xmlXPathObject *
3267
68.9M
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3268
68.9M
    xmlXPathObjectPtr ret;
3269
3270
68.9M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3271
68.9M
    if (ret == NULL) {
3272
0
        xmlXPathFreeNodeSet(val);
3273
0
  return(NULL);
3274
0
    }
3275
68.9M
    memset(ret, 0 , sizeof(xmlXPathObject));
3276
68.9M
    ret->type = XPATH_NODESET;
3277
68.9M
    ret->nodesetval = val;
3278
68.9M
    return(ret);
3279
68.9M
}
3280
3281
/**
3282
 * Free up the xmlXPathObject `obj` but don't deallocate the objects in
3283
 * the list contrary to #xmlXPathFreeObject.
3284
 *
3285
 * @param obj  an existing NodeSetList object
3286
 */
3287
void
3288
0
xmlXPathFreeNodeSetList(xmlXPathObject *obj) {
3289
0
    if (obj == NULL) return;
3290
0
    xmlFree(obj);
3291
0
}
3292
3293
/**
3294
 * Implements the EXSLT - Sets difference() function:
3295
 *    node-set set:difference (node-set, node-set)
3296
 *
3297
 * @param nodes1  a node-set
3298
 * @param nodes2  a node-set
3299
 * @returns the difference between the two node sets, or nodes1 if
3300
 *         nodes2 is empty
3301
 */
3302
xmlNodeSet *
3303
0
xmlXPathDifference (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3304
0
    xmlNodeSetPtr ret;
3305
0
    int i, l1;
3306
0
    xmlNodePtr cur;
3307
3308
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3309
0
  return(nodes1);
3310
3311
0
    ret = xmlXPathNodeSetCreate(NULL);
3312
0
    if (ret == NULL)
3313
0
        return(NULL);
3314
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3315
0
  return(ret);
3316
3317
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3318
3319
0
    for (i = 0; i < l1; i++) {
3320
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3321
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3322
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3323
0
                xmlXPathFreeNodeSet(ret);
3324
0
          return(NULL);
3325
0
            }
3326
0
  }
3327
0
    }
3328
0
    return(ret);
3329
0
}
3330
3331
/**
3332
 * Implements the EXSLT - Sets intersection() function:
3333
 *    node-set set:intersection (node-set, node-set)
3334
 *
3335
 * @param nodes1  a node-set
3336
 * @param nodes2  a node-set
3337
 * @returns a node set comprising the nodes that are within both the
3338
 *         node sets passed as arguments
3339
 */
3340
xmlNodeSet *
3341
0
xmlXPathIntersection (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3342
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3343
0
    int i, l1;
3344
0
    xmlNodePtr cur;
3345
3346
0
    if (ret == NULL)
3347
0
        return(ret);
3348
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3349
0
  return(ret);
3350
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3351
0
  return(ret);
3352
3353
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3354
3355
0
    for (i = 0; i < l1; i++) {
3356
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3357
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3358
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3359
0
                xmlXPathFreeNodeSet(ret);
3360
0
          return(NULL);
3361
0
            }
3362
0
  }
3363
0
    }
3364
0
    return(ret);
3365
0
}
3366
3367
/**
3368
 * Implements the EXSLT - Sets distinct() function:
3369
 *    node-set set:distinct (node-set)
3370
 *
3371
 * @param nodes  a node-set, sorted by document order
3372
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3373
 *         it is empty
3374
 */
3375
xmlNodeSet *
3376
0
xmlXPathDistinctSorted (xmlNodeSet *nodes) {
3377
0
    xmlNodeSetPtr ret;
3378
0
    xmlHashTablePtr hash;
3379
0
    int i, l;
3380
0
    xmlChar * strval;
3381
0
    xmlNodePtr cur;
3382
3383
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3384
0
  return(nodes);
3385
3386
0
    ret = xmlXPathNodeSetCreate(NULL);
3387
0
    if (ret == NULL)
3388
0
        return(ret);
3389
0
    l = xmlXPathNodeSetGetLength(nodes);
3390
0
    hash = xmlHashCreate (l);
3391
0
    for (i = 0; i < l; i++) {
3392
0
  cur = xmlXPathNodeSetItem(nodes, i);
3393
0
  strval = xmlXPathCastNodeToString(cur);
3394
0
  if (xmlHashLookup(hash, strval) == NULL) {
3395
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3396
0
                xmlFree(strval);
3397
0
                goto error;
3398
0
            }
3399
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3400
0
          goto error;
3401
0
  } else {
3402
0
      xmlFree(strval);
3403
0
  }
3404
0
    }
3405
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3406
0
    return(ret);
3407
3408
0
error:
3409
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3410
0
    xmlXPathFreeNodeSet(ret);
3411
0
    return(NULL);
3412
0
}
3413
3414
/**
3415
 * Implements the EXSLT - Sets distinct() function:
3416
 *    node-set set:distinct (node-set)
3417
 * `nodes` is sorted by document order, then exslSetsDistinctSorted
3418
 * is called with the sorted node-set
3419
 *
3420
 * @param nodes  a node-set
3421
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3422
 *         it is empty
3423
 */
3424
xmlNodeSet *
3425
0
xmlXPathDistinct (xmlNodeSet *nodes) {
3426
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3427
0
  return(nodes);
3428
3429
0
    xmlXPathNodeSetSort(nodes);
3430
0
    return(xmlXPathDistinctSorted(nodes));
3431
0
}
3432
3433
/**
3434
 * Implements the EXSLT - Sets has-same-nodes function:
3435
 *    boolean set:has-same-node(node-set, node-set)
3436
 *
3437
 * @param nodes1  a node-set
3438
 * @param nodes2  a node-set
3439
 * @returns true (1) if `nodes1` shares any node with `nodes2`, false (0)
3440
 *         otherwise
3441
 */
3442
int
3443
0
xmlXPathHasSameNodes (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3444
0
    int i, l;
3445
0
    xmlNodePtr cur;
3446
3447
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3448
0
  xmlXPathNodeSetIsEmpty(nodes2))
3449
0
  return(0);
3450
3451
0
    l = xmlXPathNodeSetGetLength(nodes1);
3452
0
    for (i = 0; i < l; i++) {
3453
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3454
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3455
0
      return(1);
3456
0
    }
3457
0
    return(0);
3458
0
}
3459
3460
/**
3461
 * Implements the EXSLT - Sets leading() function:
3462
 *    node-set set:leading (node-set, node-set)
3463
 *
3464
 * @param nodes  a node-set, sorted by document order
3465
 * @param node  a node
3466
 * @returns the nodes in `nodes` that precede `node` in document order,
3467
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3468
 *         doesn't contain `node`
3469
 */
3470
xmlNodeSet *
3471
0
xmlXPathNodeLeadingSorted (xmlNodeSet *nodes, xmlNode *node) {
3472
0
    int i, l;
3473
0
    xmlNodePtr cur;
3474
0
    xmlNodeSetPtr ret;
3475
3476
0
    if (node == NULL)
3477
0
  return(nodes);
3478
3479
0
    ret = xmlXPathNodeSetCreate(NULL);
3480
0
    if (ret == NULL)
3481
0
        return(ret);
3482
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3483
0
  (!xmlXPathNodeSetContains(nodes, node)))
3484
0
  return(ret);
3485
3486
0
    l = xmlXPathNodeSetGetLength(nodes);
3487
0
    for (i = 0; i < l; i++) {
3488
0
  cur = xmlXPathNodeSetItem(nodes, i);
3489
0
  if (cur == node)
3490
0
      break;
3491
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3492
0
            xmlXPathFreeNodeSet(ret);
3493
0
      return(NULL);
3494
0
        }
3495
0
    }
3496
0
    return(ret);
3497
0
}
3498
3499
/**
3500
 * Implements the EXSLT - Sets leading() function:
3501
 *    node-set set:leading (node-set, node-set)
3502
 * `nodes` is sorted by document order, then exslSetsNodeLeadingSorted
3503
 * is called.
3504
 *
3505
 * @param nodes  a node-set
3506
 * @param node  a node
3507
 * @returns the nodes in `nodes` that precede `node` in document order,
3508
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3509
 *         doesn't contain `node`
3510
 */
3511
xmlNodeSet *
3512
0
xmlXPathNodeLeading (xmlNodeSet *nodes, xmlNode *node) {
3513
0
    xmlXPathNodeSetSort(nodes);
3514
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
3515
0
}
3516
3517
/**
3518
 * Implements the EXSLT - Sets leading() function:
3519
 *    node-set set:leading (node-set, node-set)
3520
 *
3521
 * @param nodes1  a node-set, sorted by document order
3522
 * @param nodes2  a node-set, sorted by document order
3523
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3524
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3525
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3526
 */
3527
xmlNodeSet *
3528
0
xmlXPathLeadingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3529
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3530
0
  return(nodes1);
3531
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3532
0
             xmlXPathNodeSetItem(nodes2, 1)));
3533
0
}
3534
3535
/**
3536
 * Implements the EXSLT - Sets leading() function:
3537
 *    node-set set:leading (node-set, node-set)
3538
 * `nodes1` and `nodes2` are sorted by document order, then
3539
 * exslSetsLeadingSorted is called.
3540
 *
3541
 * @param nodes1  a node-set
3542
 * @param nodes2  a node-set
3543
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3544
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3545
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3546
 */
3547
xmlNodeSet *
3548
0
xmlXPathLeading (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3549
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3550
0
  return(nodes1);
3551
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3552
0
  return(xmlXPathNodeSetCreate(NULL));
3553
0
    xmlXPathNodeSetSort(nodes1);
3554
0
    xmlXPathNodeSetSort(nodes2);
3555
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3556
0
             xmlXPathNodeSetItem(nodes2, 1)));
3557
0
}
3558
3559
/**
3560
 * Implements the EXSLT - Sets trailing() function:
3561
 *    node-set set:trailing (node-set, node-set)
3562
 *
3563
 * @param nodes  a node-set, sorted by document order
3564
 * @param node  a node
3565
 * @returns the nodes in `nodes` that follow `node` in document order,
3566
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3567
 *         doesn't contain `node`
3568
 */
3569
xmlNodeSet *
3570
0
xmlXPathNodeTrailingSorted (xmlNodeSet *nodes, xmlNode *node) {
3571
0
    int i, l;
3572
0
    xmlNodePtr cur;
3573
0
    xmlNodeSetPtr ret;
3574
3575
0
    if (node == NULL)
3576
0
  return(nodes);
3577
3578
0
    ret = xmlXPathNodeSetCreate(NULL);
3579
0
    if (ret == NULL)
3580
0
        return(ret);
3581
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3582
0
  (!xmlXPathNodeSetContains(nodes, node)))
3583
0
  return(ret);
3584
3585
0
    l = xmlXPathNodeSetGetLength(nodes);
3586
0
    for (i = l - 1; i >= 0; i--) {
3587
0
  cur = xmlXPathNodeSetItem(nodes, i);
3588
0
  if (cur == node)
3589
0
      break;
3590
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3591
0
            xmlXPathFreeNodeSet(ret);
3592
0
      return(NULL);
3593
0
        }
3594
0
    }
3595
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3596
0
    return(ret);
3597
0
}
3598
3599
/**
3600
 * Implements the EXSLT - Sets trailing() function:
3601
 *    node-set set:trailing (node-set, node-set)
3602
 * `nodes` is sorted by document order, then #xmlXPathNodeTrailingSorted
3603
 * is called.
3604
 *
3605
 * @param nodes  a node-set
3606
 * @param node  a node
3607
 * @returns the nodes in `nodes` that follow `node` in document order,
3608
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3609
 *         doesn't contain `node`
3610
 */
3611
xmlNodeSet *
3612
0
xmlXPathNodeTrailing (xmlNodeSet *nodes, xmlNode *node) {
3613
0
    xmlXPathNodeSetSort(nodes);
3614
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
3615
0
}
3616
3617
/**
3618
 * Implements the EXSLT - Sets trailing() function:
3619
 *    node-set set:trailing (node-set, node-set)
3620
 *
3621
 * @param nodes1  a node-set, sorted by document order
3622
 * @param nodes2  a node-set, sorted by document order
3623
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3624
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3625
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3626
 */
3627
xmlNodeSet *
3628
0
xmlXPathTrailingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3629
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3630
0
  return(nodes1);
3631
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3632
0
              xmlXPathNodeSetItem(nodes2, 0)));
3633
0
}
3634
3635
/**
3636
 * Implements the EXSLT - Sets trailing() function:
3637
 *    node-set set:trailing (node-set, node-set)
3638
 * `nodes1` and `nodes2` are sorted by document order, then
3639
 * #xmlXPathTrailingSorted is called.
3640
 *
3641
 * @param nodes1  a node-set
3642
 * @param nodes2  a node-set
3643
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3644
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3645
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3646
 */
3647
xmlNodeSet *
3648
0
xmlXPathTrailing (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3649
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3650
0
  return(nodes1);
3651
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3652
0
  return(xmlXPathNodeSetCreate(NULL));
3653
0
    xmlXPathNodeSetSort(nodes1);
3654
0
    xmlXPathNodeSetSort(nodes2);
3655
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3656
0
              xmlXPathNodeSetItem(nodes2, 0)));
3657
0
}
3658
3659
/************************************************************************
3660
 *                  *
3661
 *    Routines to handle extra functions      *
3662
 *                  *
3663
 ************************************************************************/
3664
3665
/**
3666
 * Register a new function. If `f` is NULL it unregisters the function
3667
 *
3668
 * @param ctxt  the XPath context
3669
 * @param name  the function name
3670
 * @param f  the function implementation or NULL
3671
 * @returns 0 in case of success, -1 in case of error
3672
 */
3673
int
3674
xmlXPathRegisterFunc(xmlXPathContext *ctxt, const xmlChar *name,
3675
80.9k
         xmlXPathFunction f) {
3676
80.9k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3677
80.9k
}
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
80.9k
           const xmlChar *ns_uri, xmlXPathFunction f) {
3691
80.9k
    int ret;
3692
80.9k
    void *payload;
3693
3694
80.9k
    if (ctxt == NULL)
3695
0
  return(-1);
3696
80.9k
    if (name == NULL)
3697
0
  return(-1);
3698
3699
80.9k
    if (ctxt->funcHash == NULL)
3700
62.4k
  ctxt->funcHash = xmlHashCreate(0);
3701
80.9k
    if (ctxt->funcHash == NULL) {
3702
0
        xmlXPathErrMemory(ctxt);
3703
0
  return(-1);
3704
0
    }
3705
80.9k
    if (f == NULL)
3706
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3707
80.9k
    memcpy(&payload, &f, sizeof(f));
3708
80.9k
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3709
80.9k
    if (ret < 0) {
3710
0
        xmlXPathErrMemory(ctxt);
3711
0
        return(-1);
3712
0
    }
3713
3714
80.9k
    return(0);
3715
80.9k
}
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
2.30k
          void *funcCtxt) {
3728
2.30k
    if (ctxt == NULL)
3729
0
  return;
3730
2.30k
    ctxt->funcLookupFunc = f;
3731
2.30k
    ctxt->funcLookupData = funcCtxt;
3732
2.30k
}
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
36.0k
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3744
36.0k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3745
36.0k
}
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
36.0k
       const xmlChar *ns_uri) {
3759
36.0k
    xmlXPathFunction ret;
3760
36.0k
    void *payload;
3761
3762
36.0k
    if (ctxt == NULL)
3763
0
  return(NULL);
3764
36.0k
    if (name == NULL)
3765
0
  return(NULL);
3766
3767
36.0k
    if (ns_uri == NULL) {
3768
36.0k
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3769
3770
40.8k
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3771
39.4k
            int funcIndex = xmlXPathSFHash[bucketIndex];
3772
3773
39.4k
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3774
39.4k
                       (char *) name) == 0)
3775
34.6k
                return(xmlXPathStandardFunctions[funcIndex].func);
3776
3777
4.84k
            bucketIndex += 1;
3778
4.84k
            if (bucketIndex >= SF_HASH_SIZE)
3779
0
                bucketIndex = 0;
3780
4.84k
        }
3781
36.0k
    }
3782
3783
1.38k
    if (ctxt->funcLookupFunc != NULL) {
3784
4
  xmlXPathFuncLookupFunc f;
3785
3786
4
  f = ctxt->funcLookupFunc;
3787
4
  ret = f(ctxt->funcLookupData, name, ns_uri);
3788
4
  if (ret != NULL)
3789
0
      return(ret);
3790
4
    }
3791
3792
1.38k
    if (ctxt->funcHash == NULL)
3793
0
  return(NULL);
3794
3795
1.38k
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3796
1.38k
    memcpy(&ret, &payload, sizeof(payload));
3797
3798
1.38k
    return(ret);
3799
1.38k
}
3800
3801
/**
3802
 * Cleanup the XPath context data associated to registered functions
3803
 *
3804
 * @param ctxt  the XPath context
3805
 */
3806
void
3807
72.2k
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3808
72.2k
    if (ctxt == NULL)
3809
0
  return;
3810
3811
72.2k
    xmlHashFree(ctxt->funcHash, NULL);
3812
72.2k
    ctxt->funcHash = NULL;
3813
72.2k
}
3814
3815
/************************************************************************
3816
 *                  *
3817
 *      Routines to handle Variables      *
3818
 *                  *
3819
 ************************************************************************/
3820
3821
/**
3822
 * Register a new variable value. If `value` is NULL it unregisters
3823
 * the variable
3824
 *
3825
 * @param ctxt  the XPath context
3826
 * @param name  the variable name
3827
 * @param value  the variable value or NULL
3828
 * @returns 0 in case of success, -1 in case of error
3829
 */
3830
int
3831
xmlXPathRegisterVariable(xmlXPathContext *ctxt, const xmlChar *name,
3832
0
       xmlXPathObject *value) {
3833
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3834
0
}
3835
3836
/**
3837
 * Register a new variable value. If `value` is NULL it unregisters
3838
 * the variable
3839
 *
3840
 * @param ctxt  the XPath context
3841
 * @param name  the variable name
3842
 * @param ns_uri  the variable namespace URI
3843
 * @param value  the variable value or NULL
3844
 * @returns 0 in case of success, -1 in case of error
3845
 */
3846
int
3847
xmlXPathRegisterVariableNS(xmlXPathContext *ctxt, const xmlChar *name,
3848
         const xmlChar *ns_uri,
3849
0
         xmlXPathObject *value) {
3850
0
    if (ctxt == NULL)
3851
0
  return(-1);
3852
0
    if (name == NULL)
3853
0
  return(-1);
3854
3855
0
    if (ctxt->varHash == NULL)
3856
0
  ctxt->varHash = xmlHashCreate(0);
3857
0
    if (ctxt->varHash == NULL)
3858
0
  return(-1);
3859
0
    if (value == NULL)
3860
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3861
0
                             xmlXPathFreeObjectEntry));
3862
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3863
0
             (void *) value, xmlXPathFreeObjectEntry));
3864
0
}
3865
3866
/**
3867
 * register an external mechanism to do variable lookup
3868
 *
3869
 * @param ctxt  the XPath context
3870
 * @param f  the lookup function
3871
 * @param data  the lookup data
3872
 */
3873
void
3874
xmlXPathRegisterVariableLookup(xmlXPathContext *ctxt,
3875
2.30k
   xmlXPathVariableLookupFunc f, void *data) {
3876
2.30k
    if (ctxt == NULL)
3877
0
  return;
3878
2.30k
    ctxt->varLookupFunc = f;
3879
2.30k
    ctxt->varLookupData = data;
3880
2.30k
}
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
115
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3892
115
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
3895
115
    if (ctxt->varLookupFunc != NULL) {
3896
3
  xmlXPathObjectPtr ret;
3897
3898
3
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3899
3
          (ctxt->varLookupData, name, NULL);
3900
3
  return(ret);
3901
3
    }
3902
112
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3903
115
}
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
119
       const xmlChar *ns_uri) {
3917
119
    if (ctxt == NULL)
3918
0
  return(NULL);
3919
3920
119
    if (ctxt->varLookupFunc != NULL) {
3921
0
  xmlXPathObjectPtr ret;
3922
3923
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3924
0
          (ctxt->varLookupData, name, ns_uri);
3925
0
  if (ret != NULL) return(ret);
3926
0
    }
3927
3928
119
    if (ctxt->varHash == NULL)
3929
119
  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
72.2k
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3943
72.2k
    if (ctxt == NULL)
3944
0
  return;
3945
3946
72.2k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3947
72.2k
    ctxt->varHash = NULL;
3948
72.2k
}
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
21.2k
         const xmlChar *ns_uri) {
3962
21.2k
    xmlChar *copy;
3963
3964
21.2k
    if (ctxt == NULL)
3965
0
  return(-1);
3966
21.2k
    if (prefix == NULL)
3967
0
  return(-1);
3968
21.2k
    if (prefix[0] == 0)
3969
0
  return(-1);
3970
3971
21.2k
    if (ctxt->nsHash == NULL)
3972
19.4k
  ctxt->nsHash = xmlHashCreate(10);
3973
21.2k
    if (ctxt->nsHash == NULL) {
3974
0
        xmlXPathErrMemory(ctxt);
3975
0
  return(-1);
3976
0
    }
3977
21.2k
    if (ns_uri == NULL)
3978
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3979
0
                            xmlHashDefaultDeallocator));
3980
3981
21.2k
    copy = xmlStrdup(ns_uri);
3982
21.2k
    if (copy == NULL) {
3983
0
        xmlXPathErrMemory(ctxt);
3984
0
        return(-1);
3985
0
    }
3986
21.2k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3987
21.2k
                           xmlHashDefaultDeallocator) < 0) {
3988
0
        xmlXPathErrMemory(ctxt);
3989
0
        xmlFree(copy);
3990
0
        return(-1);
3991
0
    }
3992
3993
21.2k
    return(0);
3994
21.2k
}
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
1.17M
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
4006
1.17M
    if (ctxt == NULL)
4007
0
  return(NULL);
4008
1.17M
    if (prefix == NULL)
4009
0
  return(NULL);
4010
4011
1.17M
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4012
97.2k
  return(XML_XML_NAMESPACE);
4013
4014
1.07M
    if (ctxt->namespaces != NULL) {
4015
38
  int i;
4016
4017
90
  for (i = 0;i < ctxt->nsNr;i++) {
4018
52
      if ((ctxt->namespaces[i] != NULL) &&
4019
52
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4020
0
    return(ctxt->namespaces[i]->href);
4021
52
  }
4022
38
    }
4023
4024
1.07M
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4025
1.07M
}
4026
4027
/**
4028
 * Cleanup the XPath context data associated to registered variables
4029
 *
4030
 * @param ctxt  the XPath context
4031
 */
4032
void
4033
72.2k
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4034
72.2k
    if (ctxt == NULL)
4035
0
  return;
4036
4037
72.2k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4038
72.2k
    ctxt->nsHash = NULL;
4039
72.2k
}
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
9.59M
xmlXPathNewFloat(double val) {
4057
9.59M
    xmlXPathObjectPtr ret;
4058
4059
9.59M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4060
9.59M
    if (ret == NULL)
4061
0
  return(NULL);
4062
9.59M
    memset(ret, 0 , sizeof(xmlXPathObject));
4063
9.59M
    ret->type = XPATH_NUMBER;
4064
9.59M
    ret->floatval = val;
4065
9.59M
    return(ret);
4066
9.59M
}
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
46.4M
xmlXPathNewBoolean(int val) {
4076
46.4M
    xmlXPathObjectPtr ret;
4077
4078
46.4M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4079
46.4M
    if (ret == NULL)
4080
0
  return(NULL);
4081
46.4M
    memset(ret, 0 , sizeof(xmlXPathObject));
4082
46.4M
    ret->type = XPATH_BOOLEAN;
4083
46.4M
    ret->boolval = (val != 0);
4084
46.4M
    return(ret);
4085
46.4M
}
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
932k
xmlXPathNewString(const xmlChar *val) {
4095
932k
    xmlXPathObjectPtr ret;
4096
4097
932k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4098
932k
    if (ret == NULL)
4099
0
  return(NULL);
4100
932k
    memset(ret, 0 , sizeof(xmlXPathObject));
4101
932k
    ret->type = XPATH_STRING;
4102
932k
    if (val == NULL)
4103
3.80k
        val = BAD_CAST "";
4104
932k
    ret->stringval = xmlStrdup(val);
4105
932k
    if (ret->stringval == NULL) {
4106
0
        xmlFree(ret);
4107
0
        return(NULL);
4108
0
    }
4109
932k
    return(ret);
4110
932k
}
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
8.41M
xmlXPathWrapString (xmlChar *val) {
4122
8.41M
    xmlXPathObjectPtr ret;
4123
4124
8.41M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4125
8.41M
    if (ret == NULL) {
4126
0
        xmlFree(val);
4127
0
  return(NULL);
4128
0
    }
4129
8.41M
    memset(ret, 0 , sizeof(xmlXPathObject));
4130
8.41M
    ret->type = XPATH_STRING;
4131
8.41M
    ret->stringval = val;
4132
8.41M
    return(ret);
4133
8.41M
}
4134
4135
/**
4136
 * Create a new xmlXPathObject of type string and of value `val`
4137
 *
4138
 * @param val  the char * value
4139
 * @returns the newly created object.
4140
 */
4141
xmlXPathObject *
4142
0
xmlXPathNewCString(const char *val) {
4143
0
    return(xmlXPathNewString(BAD_CAST val));
4144
0
}
4145
4146
/**
4147
 * Wraps a string into an XPath object.
4148
 *
4149
 * @param val  the char * value
4150
 * @returns the newly created object.
4151
 */
4152
xmlXPathObject *
4153
0
xmlXPathWrapCString (char * val) {
4154
0
    return(xmlXPathWrapString((xmlChar *)(val)));
4155
0
}
4156
4157
/**
4158
 * Wraps the `val` data into an XPath object.
4159
 *
4160
 * @param val  the user data
4161
 * @returns the newly created object.
4162
 */
4163
xmlXPathObject *
4164
0
xmlXPathWrapExternal (void *val) {
4165
0
    xmlXPathObjectPtr ret;
4166
4167
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4168
0
    if (ret == NULL)
4169
0
  return(NULL);
4170
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4171
0
    ret->type = XPATH_USERS;
4172
0
    ret->user = val;
4173
0
    return(ret);
4174
0
}
4175
4176
/**
4177
 * allocate a new copy of a given object
4178
 *
4179
 * @param val  the original object
4180
 * @returns the newly created object.
4181
 */
4182
xmlXPathObject *
4183
10.2M
xmlXPathObjectCopy(xmlXPathObject *val) {
4184
10.2M
    xmlXPathObjectPtr ret;
4185
4186
10.2M
    if (val == NULL)
4187
0
  return(NULL);
4188
4189
10.2M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4190
10.2M
    if (ret == NULL)
4191
0
  return(NULL);
4192
10.2M
    memcpy(ret, val , sizeof(xmlXPathObject));
4193
10.2M
    switch (val->type) {
4194
0
  case XPATH_BOOLEAN:
4195
1.26M
  case XPATH_NUMBER:
4196
1.26M
      break;
4197
9.03M
  case XPATH_STRING:
4198
9.03M
      ret->stringval = xmlStrdup(val->stringval);
4199
9.03M
            if (ret->stringval == NULL) {
4200
0
                xmlFree(ret);
4201
0
                return(NULL);
4202
0
            }
4203
9.03M
      break;
4204
9.03M
  case XPATH_XSLT_TREE:
4205
0
  case XPATH_NODESET:
4206
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4207
0
            if (ret->nodesetval == NULL) {
4208
0
                xmlFree(ret);
4209
0
                return(NULL);
4210
0
            }
4211
      /* Do not deallocate the copied tree value */
4212
0
      ret->boolval = 0;
4213
0
      break;
4214
0
        case XPATH_USERS:
4215
0
      ret->user = val->user;
4216
0
      break;
4217
0
        default:
4218
0
            xmlFree(ret);
4219
0
            ret = NULL;
4220
0
      break;
4221
10.2M
    }
4222
10.2M
    return(ret);
4223
10.2M
}
4224
4225
/**
4226
 * Free up an xmlXPathObject object.
4227
 *
4228
 * @param obj  the object to free
4229
 */
4230
void
4231
223M
xmlXPathFreeObject(xmlXPathObject *obj) {
4232
223M
    if (obj == NULL) return;
4233
223M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4234
147M
        if (obj->nodesetval != NULL)
4235
147M
            xmlXPathFreeNodeSet(obj->nodesetval);
4236
147M
    } else if (obj->type == XPATH_STRING) {
4237
18.3M
  if (obj->stringval != NULL)
4238
18.3M
      xmlFree(obj->stringval);
4239
18.3M
    }
4240
223M
    xmlFree(obj);
4241
223M
}
4242
4243
static void
4244
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4245
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4246
0
}
4247
4248
/**
4249
 * Depending on the state of the cache this frees the given
4250
 * XPath object or stores it in the cache.
4251
 *
4252
 * @param ctxt  XPath context
4253
 * @param obj  the xmlXPathObject to free or to cache
4254
 */
4255
static void
4256
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4257
219M
{
4258
219M
    if (obj == NULL)
4259
0
  return;
4260
219M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4261
218M
   xmlXPathFreeObject(obj);
4262
218M
    } else {
4263
1.12M
  xmlXPathContextCachePtr cache =
4264
1.12M
      (xmlXPathContextCachePtr) ctxt->cache;
4265
4266
1.12M
  switch (obj->type) {
4267
922k
      case XPATH_NODESET:
4268
922k
      case XPATH_XSLT_TREE:
4269
922k
    if (obj->nodesetval != NULL) {
4270
922k
        if ((obj->nodesetval->nodeMax <= 40) &&
4271
876k
      (cache->numNodeset < cache->maxNodeset)) {
4272
761k
                        obj->stringval = (void *) cache->nodesetObjs;
4273
761k
                        cache->nodesetObjs = obj;
4274
761k
                        cache->numNodeset += 1;
4275
761k
      goto obj_cached;
4276
761k
        } else {
4277
161k
      xmlXPathFreeNodeSet(obj->nodesetval);
4278
161k
      obj->nodesetval = NULL;
4279
161k
        }
4280
922k
    }
4281
161k
    break;
4282
161k
      case XPATH_STRING:
4283
50.2k
    if (obj->stringval != NULL)
4284
50.2k
        xmlFree(obj->stringval);
4285
50.2k
                obj->stringval = NULL;
4286
50.2k
    break;
4287
26.2k
      case XPATH_BOOLEAN:
4288
148k
      case XPATH_NUMBER:
4289
148k
    break;
4290
0
      default:
4291
0
    goto free_obj;
4292
1.12M
  }
4293
4294
  /*
4295
  * Fallback to adding to the misc-objects slot.
4296
  */
4297
360k
        if (cache->numMisc >= cache->maxMisc)
4298
0
      goto free_obj;
4299
360k
        obj->stringval = (void *) cache->miscObjs;
4300
360k
        cache->miscObjs = obj;
4301
360k
        cache->numMisc += 1;
4302
4303
1.12M
obj_cached:
4304
1.12M
        obj->boolval = 0;
4305
1.12M
  if (obj->nodesetval != NULL) {
4306
761k
      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
761k
      if (tmpset->nodeNr > 0) {
4313
755k
    int i;
4314
755k
    xmlNodePtr node;
4315
4316
1.52M
    for (i = 0; i < tmpset->nodeNr; i++) {
4317
770k
        node = tmpset->nodeTab[i];
4318
770k
        if ((node != NULL) &&
4319
770k
      (node->type == XML_NAMESPACE_DECL))
4320
0
        {
4321
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4322
0
        }
4323
770k
    }
4324
755k
      }
4325
761k
      tmpset->nodeNr = 0;
4326
761k
        }
4327
4328
1.12M
  return;
4329
4330
0
free_obj:
4331
  /*
4332
  * Cache is full; free the object.
4333
  */
4334
0
  if (obj->nodesetval != NULL)
4335
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4336
0
  xmlFree(obj);
4337
0
    }
4338
219M
}
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
26.8k
xmlXPathCastBooleanToString (int val) {
4355
26.8k
    xmlChar *ret;
4356
26.8k
    if (val)
4357
4.20k
  ret = xmlStrdup((const xmlChar *) "true");
4358
22.6k
    else
4359
22.6k
  ret = xmlStrdup((const xmlChar *) "false");
4360
26.8k
    return(ret);
4361
26.8k
}
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
24.0k
xmlXPathCastNumberToString (double val) {
4371
24.0k
    xmlChar *ret;
4372
24.0k
    switch (xmlXPathIsInf(val)) {
4373
720
    case 1:
4374
720
  ret = xmlStrdup((const xmlChar *) "Infinity");
4375
720
  break;
4376
892
    case -1:
4377
892
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4378
892
  break;
4379
22.4k
    default:
4380
22.4k
  if (xmlXPathIsNaN(val)) {
4381
12.3k
      ret = xmlStrdup((const xmlChar *) "NaN");
4382
12.3k
  } else if (val == 0) {
4383
            /* Omit sign for negative zero. */
4384
1.58k
      ret = xmlStrdup((const xmlChar *) "0");
4385
8.55k
  } else {
4386
      /* could be improved */
4387
8.55k
      char buf[100];
4388
8.55k
      xmlXPathFormatNumber(val, buf, 99);
4389
8.55k
      buf[99] = 0;
4390
8.55k
      ret = xmlStrdup((const xmlChar *) buf);
4391
8.55k
  }
4392
24.0k
    }
4393
24.0k
    return(ret);
4394
24.0k
}
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
7.55M
xmlXPathCastNodeToString (xmlNode *node) {
4404
7.55M
    return(xmlNodeGetContent(node));
4405
7.55M
}
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
30.1M
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4415
30.1M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4416
25.3M
  return(xmlStrdup((const xmlChar *) ""));
4417
4418
4.78M
    if (ns->nodeNr > 1)
4419
793k
  xmlXPathNodeSetSort(ns);
4420
4.78M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4421
30.1M
}
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
8.52M
xmlXPathCastToString(xmlXPathObject *val) {
4432
8.52M
    xmlChar *ret = NULL;
4433
4434
8.52M
    if (val == NULL)
4435
0
  return(xmlStrdup((const xmlChar *) ""));
4436
8.52M
    switch (val->type) {
4437
0
  case XPATH_UNDEFINED:
4438
0
      ret = xmlStrdup((const xmlChar *) "");
4439
0
      break;
4440
8.44M
        case XPATH_NODESET:
4441
8.44M
        case XPATH_XSLT_TREE:
4442
8.44M
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4443
8.44M
      break;
4444
28.1k
  case XPATH_STRING:
4445
28.1k
      return(xmlStrdup(val->stringval));
4446
26.8k
        case XPATH_BOOLEAN:
4447
26.8k
      ret = xmlXPathCastBooleanToString(val->boolval);
4448
26.8k
      break;
4449
24.0k
  case XPATH_NUMBER: {
4450
24.0k
      ret = xmlXPathCastNumberToString(val->floatval);
4451
24.0k
      break;
4452
8.44M
  }
4453
0
  case XPATH_USERS:
4454
      /* TODO */
4455
0
      ret = xmlStrdup((const xmlChar *) "");
4456
0
      break;
4457
8.52M
    }
4458
8.49M
    return(ret);
4459
8.52M
}
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
313
xmlXPathConvertString(xmlXPathObject *val) {
4470
313
    xmlChar *res = NULL;
4471
4472
313
    if (val == NULL)
4473
0
  return(xmlXPathNewCString(""));
4474
4475
313
    switch (val->type) {
4476
0
    case XPATH_UNDEFINED:
4477
0
  break;
4478
282
    case XPATH_NODESET:
4479
282
    case XPATH_XSLT_TREE:
4480
282
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4481
282
  break;
4482
0
    case XPATH_STRING:
4483
0
  return(val);
4484
0
    case XPATH_BOOLEAN:
4485
0
  res = xmlXPathCastBooleanToString(val->boolval);
4486
0
  break;
4487
31
    case XPATH_NUMBER:
4488
31
  res = xmlXPathCastNumberToString(val->floatval);
4489
31
  break;
4490
0
    case XPATH_USERS:
4491
  /* TODO */
4492
0
  break;
4493
313
    }
4494
313
    xmlXPathFreeObject(val);
4495
313
    if (res == NULL)
4496
0
  return(xmlXPathNewCString(""));
4497
313
    return(xmlXPathWrapString(res));
4498
313
}
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
4.78M
xmlXPathCastBooleanToNumber(int val) {
4508
4.78M
    if (val)
4509
56.3k
  return(1.0);
4510
4.72M
    return(0.0);
4511
4.78M
}
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
25.3M
xmlXPathCastStringToNumber(const xmlChar * val) {
4521
25.3M
    return(xmlXPathStringEvalNumber(val));
4522
25.3M
}
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
1.93M
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4533
1.93M
    xmlChar *strval;
4534
1.93M
    double ret;
4535
4536
1.93M
    if (node == NULL)
4537
0
  return(xmlXPathNAN);
4538
1.93M
    strval = xmlXPathCastNodeToString(node);
4539
1.93M
    if (strval == NULL) {
4540
0
        xmlXPathPErrMemory(ctxt);
4541
0
  return(xmlXPathNAN);
4542
0
    }
4543
1.93M
    ret = xmlXPathCastStringToNumber(strval);
4544
1.93M
    xmlFree(strval);
4545
4546
1.93M
    return(ret);
4547
1.93M
}
4548
4549
/**
4550
 * Converts a node to its number value
4551
 *
4552
 * @param node  a node
4553
 * @returns the number value
4554
 */
4555
double
4556
0
xmlXPathCastNodeToNumber (xmlNode *node) {
4557
0
    return(xmlXPathNodeToNumberInternal(NULL, node));
4558
0
}
4559
4560
/**
4561
 * Converts a node-set to its number value
4562
 *
4563
 * @param ns  a node-set
4564
 * @returns the number value
4565
 */
4566
double
4567
0
xmlXPathCastNodeSetToNumber (xmlNodeSet *ns) {
4568
0
    xmlChar *str;
4569
0
    double ret;
4570
4571
0
    if (ns == NULL)
4572
0
  return(xmlXPathNAN);
4573
0
    str = xmlXPathCastNodeSetToString(ns);
4574
0
    ret = xmlXPathCastStringToNumber(str);
4575
0
    xmlFree(str);
4576
0
    return(ret);
4577
0
}
4578
4579
/**
4580
 * Converts an XPath object to its number value
4581
 *
4582
 * @param val  an XPath object
4583
 * @returns the number value
4584
 */
4585
double
4586
0
xmlXPathCastToNumber(xmlXPathObject *val) {
4587
0
    return(xmlXPathCastToNumberInternal(NULL, val));
4588
0
}
4589
4590
/**
4591
 * Converts an existing object to its number() equivalent
4592
 *
4593
 * @param val  an XPath object
4594
 * @returns the new object, the old one is freed (or the operation
4595
 *         is done directly on `val`)
4596
 */
4597
xmlXPathObject *
4598
0
xmlXPathConvertNumber(xmlXPathObject *val) {
4599
0
    xmlXPathObjectPtr ret;
4600
4601
0
    if (val == NULL)
4602
0
  return(xmlXPathNewFloat(0.0));
4603
0
    if (val->type == XPATH_NUMBER)
4604
0
  return(val);
4605
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4606
0
    xmlXPathFreeObject(val);
4607
0
    return(ret);
4608
0
}
4609
4610
/**
4611
 * Converts a number to its boolean value
4612
 *
4613
 * @param val  a number
4614
 * @returns the boolean value
4615
 */
4616
int
4617
662k
xmlXPathCastNumberToBoolean (double val) {
4618
662k
     if (xmlXPathIsNaN(val) || (val == 0.0))
4619
632k
   return(0);
4620
30.3k
     return(1);
4621
662k
}
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
4.39k
xmlXPathCastStringToBoolean (const xmlChar *val) {
4631
4.39k
    if ((val == NULL) || (xmlStrlen(val) == 0))
4632
2.99k
  return(0);
4633
1.39k
    return(1);
4634
4.39k
}
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
4.10M
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4644
4.10M
    if ((ns == NULL) || (ns->nodeNr == 0))
4645
3.17M
  return(0);
4646
924k
    return(1);
4647
4.10M
}
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
4.34M
xmlXPathCastToBoolean (xmlXPathObject *val) {
4657
4.34M
    int ret = 0;
4658
4659
4.34M
    if (val == NULL)
4660
0
  return(0);
4661
4.34M
    switch (val->type) {
4662
0
    case XPATH_UNDEFINED:
4663
0
  ret = 0;
4664
0
  break;
4665
4.10M
    case XPATH_NODESET:
4666
4.10M
    case XPATH_XSLT_TREE:
4667
4.10M
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4668
4.10M
  break;
4669
4.39k
    case XPATH_STRING:
4670
4.39k
  ret = xmlXPathCastStringToBoolean(val->stringval);
4671
4.39k
  break;
4672
241k
    case XPATH_NUMBER:
4673
241k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4674
241k
  break;
4675
0
    case XPATH_BOOLEAN:
4676
0
  ret = val->boolval;
4677
0
  break;
4678
0
    case XPATH_USERS:
4679
  /* TODO */
4680
0
  ret = 0;
4681
0
  break;
4682
4.34M
    }
4683
4.34M
    return(ret);
4684
4.34M
}
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
72.2k
xmlXPathNewContext(xmlDoc *doc) {
4721
72.2k
    xmlXPathContextPtr ret;
4722
4723
72.2k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4724
72.2k
    if (ret == NULL)
4725
0
  return(NULL);
4726
72.2k
    memset(ret, 0 , sizeof(xmlXPathContext));
4727
72.2k
    ret->doc = doc;
4728
72.2k
    ret->node = NULL;
4729
4730
72.2k
    ret->varHash = NULL;
4731
4732
72.2k
    ret->nb_types = 0;
4733
72.2k
    ret->max_types = 0;
4734
72.2k
    ret->types = NULL;
4735
4736
72.2k
    ret->nb_axis = 0;
4737
72.2k
    ret->max_axis = 0;
4738
72.2k
    ret->axis = NULL;
4739
4740
72.2k
    ret->nsHash = NULL;
4741
72.2k
    ret->user = NULL;
4742
4743
72.2k
    ret->contextSize = -1;
4744
72.2k
    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
72.2k
    return(ret);
4754
72.2k
}
4755
4756
/**
4757
 * Free up an xmlXPathContext
4758
 *
4759
 * @param ctxt  the context to free
4760
 */
4761
void
4762
72.2k
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4763
72.2k
    if (ctxt == NULL) return;
4764
4765
72.2k
    if (ctxt->cache != NULL)
4766
9.93k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4767
72.2k
    xmlXPathRegisteredNsCleanup(ctxt);
4768
72.2k
    xmlXPathRegisteredFuncsCleanup(ctxt);
4769
72.2k
    xmlXPathRegisteredVariablesCleanup(ctxt);
4770
72.2k
    xmlResetError(&ctxt->lastError);
4771
72.2k
    xmlFree(ctxt);
4772
72.2k
}
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
89.8k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4808
89.8k
    xmlXPathParserContextPtr ret;
4809
4810
89.8k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4811
89.8k
    if (ret == NULL) {
4812
0
        xmlXPathErrMemory(ctxt);
4813
0
  return(NULL);
4814
0
    }
4815
89.8k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4816
89.8k
    ret->cur = ret->base = str;
4817
89.8k
    ret->context = ctxt;
4818
4819
89.8k
    ret->comp = xmlXPathNewCompExpr();
4820
89.8k
    if (ret->comp == NULL) {
4821
0
        xmlXPathErrMemory(ctxt);
4822
0
  xmlFree(ret->valueTab);
4823
0
  xmlFree(ret);
4824
0
  return(NULL);
4825
0
    }
4826
89.8k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4827
29.7k
        ret->comp->dict = ctxt->dict;
4828
29.7k
  xmlDictReference(ret->comp->dict);
4829
29.7k
    }
4830
4831
89.8k
    return(ret);
4832
89.8k
}
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
533k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4843
533k
    xmlXPathParserContextPtr ret;
4844
4845
533k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4846
533k
    if (ret == NULL) {
4847
0
        xmlXPathErrMemory(ctxt);
4848
0
  return(NULL);
4849
0
    }
4850
533k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4851
4852
    /* Allocate the value stack */
4853
533k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4854
533k
    ret->valueMax = 1;
4855
#else
4856
    ret->valueMax = 10;
4857
#endif
4858
533k
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4859
533k
    if (ret->valueTab == NULL) {
4860
0
  xmlFree(ret);
4861
0
  xmlXPathErrMemory(ctxt);
4862
0
  return(NULL);
4863
0
    }
4864
533k
    ret->valueNr = 0;
4865
533k
    ret->value = NULL;
4866
4867
533k
    ret->context = ctxt;
4868
533k
    ret->comp = comp;
4869
4870
533k
    return(ret);
4871
533k
}
4872
4873
/**
4874
 * Free up an xmlXPathParserContext
4875
 *
4876
 * @param ctxt  the context to free
4877
 */
4878
void
4879
623k
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4880
623k
    int i;
4881
4882
623k
    if (ctxt == NULL)
4883
0
        return;
4884
4885
623k
    if (ctxt->valueTab != NULL) {
4886
638k
        for (i = 0; i < ctxt->valueNr; i++) {
4887
47.1k
            if (ctxt->context)
4888
47.1k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4889
0
            else
4890
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4891
47.1k
        }
4892
591k
        xmlFree(ctxt->valueTab);
4893
591k
    }
4894
623k
    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
77.2k
  xmlXPathFreeCompExpr(ctxt->comp);
4902
77.2k
    }
4903
623k
    xmlFree(ctxt);
4904
623k
}
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
4.86M
xmlXPathNodeValHash(xmlNodePtr node) {
4921
4.86M
    int len = 2;
4922
4.86M
    const xmlChar * string = NULL;
4923
4.86M
    xmlNodePtr tmp = NULL;
4924
4.86M
    unsigned int ret = 0;
4925
4926
4.86M
    if (node == NULL)
4927
0
  return(0);
4928
4929
4.86M
    if (node->type == XML_DOCUMENT_NODE) {
4930
17.5k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4931
17.5k
  if (tmp == NULL)
4932
0
      node = node->children;
4933
17.5k
  else
4934
17.5k
      node = tmp;
4935
4936
17.5k
  if (node == NULL)
4937
0
      return(0);
4938
17.5k
    }
4939
4940
4.86M
    switch (node->type) {
4941
8.98k
  case XML_COMMENT_NODE:
4942
15.0k
  case XML_PI_NODE:
4943
15.3k
  case XML_CDATA_SECTION_NODE:
4944
92.6k
  case XML_TEXT_NODE:
4945
92.6k
      string = node->content;
4946
92.6k
      if (string == NULL)
4947
1.63k
    return(0);
4948
90.9k
      if (string[0] == 0)
4949
6.60k
    return(0);
4950
84.3k
      return(string[0] + (string[1] << 8));
4951
18.8k
  case XML_NAMESPACE_DECL:
4952
18.8k
      string = ((xmlNsPtr)node)->href;
4953
18.8k
      if (string == NULL)
4954
0
    return(0);
4955
18.8k
      if (string[0] == 0)
4956
95
    return(0);
4957
18.7k
      return(string[0] + (string[1] << 8));
4958
4.50M
  case XML_ATTRIBUTE_NODE:
4959
4.50M
      tmp = ((xmlAttrPtr) node)->children;
4960
4.50M
      break;
4961
244k
  case XML_ELEMENT_NODE:
4962
244k
      tmp = node->children;
4963
244k
      break;
4964
0
  default:
4965
0
      return(0);
4966
4.86M
    }
4967
5.18M
    while (tmp != NULL) {
4968
4.76M
  switch (tmp->type) {
4969
0
      case XML_CDATA_SECTION_NODE:
4970
4.60M
      case XML_TEXT_NODE:
4971
4.60M
    string = tmp->content;
4972
4.60M
    break;
4973
150k
      default:
4974
150k
                string = NULL;
4975
150k
    break;
4976
4.76M
  }
4977
4.76M
  if ((string != NULL) && (string[0] != 0)) {
4978
4.57M
      if (len == 1) {
4979
3.73k
    return(ret + (string[0] << 8));
4980
3.73k
      }
4981
4.57M
      if (string[1] == 0) {
4982
254k
    len = 1;
4983
254k
    ret = string[0];
4984
4.31M
      } else {
4985
4.31M
    return(string[0] + (string[1] << 8));
4986
4.31M
      }
4987
4.57M
  }
4988
  /*
4989
   * Skip to next node
4990
   */
4991
438k
        if ((tmp->children != NULL) &&
4992
92.3k
            (tmp->type != XML_DTD_NODE) &&
4993
92.3k
            (tmp->type != XML_ENTITY_REF_NODE) &&
4994
92.3k
            (tmp->children->type != XML_ENTITY_DECL)) {
4995
92.3k
            tmp = tmp->children;
4996
92.3k
            continue;
4997
92.3k
  }
4998
346k
  if (tmp == node)
4999
0
      break;
5000
5001
346k
  if (tmp->next != NULL) {
5002
58.1k
      tmp = tmp->next;
5003
58.1k
      continue;
5004
58.1k
  }
5005
5006
290k
  do {
5007
290k
      tmp = tmp->parent;
5008
290k
      if (tmp == NULL)
5009
0
    break;
5010
290k
      if (tmp == node) {
5011
286k
    tmp = NULL;
5012
286k
    break;
5013
286k
      }
5014
4.24k
      if (tmp->next != NULL) {
5015
1.81k
    tmp = tmp->next;
5016
1.81k
    break;
5017
1.81k
      }
5018
4.24k
  } while (tmp != NULL);
5019
288k
    }
5020
426k
    return(ret);
5021
4.74M
}
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
488k
xmlXPathStringHash(const xmlChar * string) {
5032
488k
    if (string == NULL)
5033
0
  return(0);
5034
488k
    if (string[0] == 0)
5035
4.15k
  return(0);
5036
483k
    return(string[0] + (string[1] << 8));
5037
488k
}
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
810k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5062
810k
    int i, ret = 0;
5063
810k
    xmlNodeSetPtr ns;
5064
810k
    xmlChar *str2;
5065
5066
810k
    if ((f == NULL) || (arg == NULL) ||
5067
810k
  ((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
810k
    ns = arg->nodesetval;
5073
810k
    if (ns != NULL) {
5074
1.39M
  for (i = 0;i < ns->nodeNr;i++) {
5075
582k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5076
582k
       if (str2 != NULL) {
5077
582k
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5078
582k
     xmlFree(str2);
5079
582k
     xmlXPathNumberFunction(ctxt, 1);
5080
582k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5081
582k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5082
582k
     if (ret)
5083
1.01k
         break;
5084
582k
       } else {
5085
0
                 xmlXPathPErrMemory(ctxt);
5086
0
             }
5087
582k
  }
5088
810k
    }
5089
810k
    xmlXPathReleaseObject(ctxt->context, arg);
5090
810k
    xmlXPathReleaseObject(ctxt->context, f);
5091
810k
    return(ret);
5092
810k
}
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
7.62M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5116
7.62M
    int i, ret = 0;
5117
7.62M
    xmlNodeSetPtr ns;
5118
7.62M
    xmlChar *str2;
5119
5120
7.62M
    if ((s == NULL) || (arg == NULL) ||
5121
7.62M
  ((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
7.62M
    ns = arg->nodesetval;
5127
7.62M
    if (ns != NULL) {
5128
7.75M
  for (i = 0;i < ns->nodeNr;i++) {
5129
134k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5130
134k
       if (str2 != NULL) {
5131
134k
     xmlXPathValuePush(ctxt,
5132
134k
         xmlXPathCacheNewString(ctxt, str2));
5133
134k
     xmlFree(str2);
5134
134k
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5135
134k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5136
134k
     if (ret)
5137
2.60k
         break;
5138
134k
       } else {
5139
0
                 xmlXPathPErrMemory(ctxt);
5140
0
             }
5141
134k
  }
5142
7.62M
    }
5143
7.62M
    xmlXPathReleaseObject(ctxt->context, arg);
5144
7.62M
    xmlXPathReleaseObject(ctxt->context, s);
5145
7.62M
    return(ret);
5146
7.62M
}
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
2.20M
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5179
2.20M
    int i, j, init = 0;
5180
2.20M
    double val1;
5181
2.20M
    double *values2;
5182
2.20M
    int ret = 0;
5183
2.20M
    xmlNodeSetPtr ns1;
5184
2.20M
    xmlNodeSetPtr ns2;
5185
5186
2.20M
    if ((arg1 == NULL) ||
5187
2.20M
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5188
0
  xmlXPathFreeObject(arg2);
5189
0
        return(0);
5190
0
    }
5191
2.20M
    if ((arg2 == NULL) ||
5192
2.20M
  ((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
2.20M
    ns1 = arg1->nodesetval;
5199
2.20M
    ns2 = arg2->nodesetval;
5200
5201
2.20M
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5202
2.12M
  xmlXPathFreeObject(arg1);
5203
2.12M
  xmlXPathFreeObject(arg2);
5204
2.12M
  return(0);
5205
2.12M
    }
5206
78.1k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5207
21.2k
  xmlXPathFreeObject(arg1);
5208
21.2k
  xmlXPathFreeObject(arg2);
5209
21.2k
  return(0);
5210
21.2k
    }
5211
5212
56.8k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5213
56.8k
    if (values2 == NULL) {
5214
0
        xmlXPathPErrMemory(ctxt);
5215
0
  xmlXPathFreeObject(arg1);
5216
0
  xmlXPathFreeObject(arg2);
5217
0
  return(0);
5218
0
    }
5219
775k
    for (i = 0;i < ns1->nodeNr;i++) {
5220
719k
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5221
719k
  if (xmlXPathIsNaN(val1))
5222
685k
      continue;
5223
1.21M
  for (j = 0;j < ns2->nodeNr;j++) {
5224
1.17M
      if (init == 0) {
5225
1.16M
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5226
1.16M
                                                          ns2->nodeTab[j]);
5227
1.16M
      }
5228
1.17M
      if (xmlXPathIsNaN(values2[j]))
5229
1.17M
    continue;
5230
5.50k
      if (inf && strict)
5231
1.97k
    ret = (val1 < values2[j]);
5232
3.52k
      else if (inf && !strict)
5233
620
    ret = (val1 <= values2[j]);
5234
2.90k
      else if (!inf && strict)
5235
2.26k
    ret = (val1 > values2[j]);
5236
644
      else if (!inf && !strict)
5237
644
    ret = (val1 >= values2[j]);
5238
5.50k
      if (ret)
5239
1.39k
    break;
5240
5.50k
  }
5241
33.9k
  if (ret)
5242
1.39k
      break;
5243
32.5k
  init = 1;
5244
32.5k
    }
5245
56.8k
    xmlFree(values2);
5246
56.8k
    xmlXPathFreeObject(arg1);
5247
56.8k
    xmlXPathFreeObject(arg2);
5248
56.8k
    return(ret);
5249
56.8k
}
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
10.7M
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5273
10.7M
    if ((val == NULL) || (arg == NULL) ||
5274
10.7M
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5275
0
        return(0);
5276
5277
10.7M
    switch(val->type) {
5278
810k
        case XPATH_NUMBER:
5279
810k
      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
7.62M
        case XPATH_STRING:
5284
7.62M
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5285
2.33M
        case XPATH_BOOLEAN:
5286
2.33M
      xmlXPathValuePush(ctxt, arg);
5287
2.33M
      xmlXPathBooleanFunction(ctxt, 1);
5288
2.33M
      xmlXPathValuePush(ctxt, val);
5289
2.33M
      return(xmlXPathCompareValues(ctxt, inf, strict));
5290
0
  default:
5291
0
            xmlXPathReleaseObject(ctxt->context, arg);
5292
0
            xmlXPathReleaseObject(ctxt->context, val);
5293
0
            XP_ERROR0(XPATH_INVALID_TYPE);
5294
10.7M
    }
5295
0
    return(0);
5296
10.7M
}
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
517k
{
5315
517k
    int i;
5316
517k
    xmlNodeSetPtr ns;
5317
517k
    xmlChar *str2;
5318
517k
    unsigned int hash;
5319
5320
517k
    if ((str == NULL) || (arg == NULL) ||
5321
517k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5322
0
        return (0);
5323
517k
    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
517k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5329
29.0k
        return (0);
5330
488k
    hash = xmlXPathStringHash(str);
5331
570k
    for (i = 0; i < ns->nodeNr; i++) {
5332
564k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5333
482k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5334
482k
            if (str2 == NULL) {
5335
0
                xmlXPathPErrMemory(ctxt);
5336
0
                return(0);
5337
0
            }
5338
482k
            if (xmlStrEqual(str, str2)) {
5339
479k
                xmlFree(str2);
5340
479k
    if (neq)
5341
868
        continue;
5342
478k
                return (1);
5343
479k
            } else if (neq) {
5344
959
    xmlFree(str2);
5345
959
    return (1);
5346
959
      }
5347
1.89k
            xmlFree(str2);
5348
81.9k
        } else if (neq)
5349
1.97k
      return (1);
5350
564k
    }
5351
6.62k
    return (0);
5352
488k
}
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
500k
    xmlXPathObjectPtr arg, double f, int neq) {
5371
500k
  int i, ret=0;
5372
500k
  xmlNodeSetPtr ns;
5373
500k
  xmlChar *str2;
5374
500k
  xmlXPathObjectPtr val;
5375
500k
  double v;
5376
5377
500k
    if ((arg == NULL) ||
5378
500k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5379
0
        return(0);
5380
5381
500k
    ns = arg->nodesetval;
5382
500k
    if (ns != NULL) {
5383
604k
  for (i=0;i<ns->nodeNr;i++) {
5384
108k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5385
108k
      if (str2 != NULL) {
5386
108k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5387
108k
    xmlFree(str2);
5388
108k
    xmlXPathNumberFunction(ctxt, 1);
5389
108k
                CHECK_ERROR0;
5390
108k
    val = xmlXPathValuePop(ctxt);
5391
108k
    v = val->floatval;
5392
108k
    xmlXPathReleaseObject(ctxt->context, val);
5393
108k
    if (!xmlXPathIsNaN(v)) {
5394
7.88k
        if ((!neq) && (v==f)) {
5395
3.49k
      ret = 1;
5396
3.49k
      break;
5397
4.38k
        } else if ((neq) && (v!=f)) {
5398
942
      ret = 1;
5399
942
      break;
5400
942
        }
5401
100k
    } else { /* NaN is unequal to any value */
5402
100k
        if (neq)
5403
10.4k
      ret = 1;
5404
100k
    }
5405
108k
      } else {
5406
0
                xmlXPathPErrMemory(ctxt);
5407
0
            }
5408
108k
  }
5409
500k
    }
5410
5411
500k
    return(ret);
5412
500k
}
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
266k
                      xmlXPathObjectPtr arg2, int neq) {
5434
266k
    int i, j;
5435
266k
    unsigned int *hashs1;
5436
266k
    unsigned int *hashs2;
5437
266k
    xmlChar **values1;
5438
266k
    xmlChar **values2;
5439
266k
    int ret = 0;
5440
266k
    xmlNodeSetPtr ns1;
5441
266k
    xmlNodeSetPtr ns2;
5442
5443
266k
    if ((arg1 == NULL) ||
5444
266k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5445
0
        return(0);
5446
266k
    if ((arg2 == NULL) ||
5447
266k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5448
0
        return(0);
5449
5450
266k
    ns1 = arg1->nodesetval;
5451
266k
    ns2 = arg2->nodesetval;
5452
5453
266k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5454
215k
  return(0);
5455
51.3k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5456
5.95k
  return(0);
5457
5458
    /*
5459
     * for equal, check if there is a node pertaining to both sets
5460
     */
5461
45.4k
    if (neq == 0)
5462
4.46M
  for (i = 0;i < ns1->nodeNr;i++)
5463
46.6M
      for (j = 0;j < ns2->nodeNr;j++)
5464
42.1M
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5465
5.28k
        return(1);
5466
5467
40.1k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5468
40.1k
    if (values1 == NULL) {
5469
0
        xmlXPathPErrMemory(ctxt);
5470
0
  return(0);
5471
0
    }
5472
40.1k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5473
40.1k
    if (hashs1 == NULL) {
5474
0
        xmlXPathPErrMemory(ctxt);
5475
0
  xmlFree(values1);
5476
0
  return(0);
5477
0
    }
5478
40.1k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5479
40.1k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5480
40.1k
    if (values2 == NULL) {
5481
0
        xmlXPathPErrMemory(ctxt);
5482
0
  xmlFree(hashs1);
5483
0
  xmlFree(values1);
5484
0
  return(0);
5485
0
    }
5486
40.1k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5487
40.1k
    if (hashs2 == NULL) {
5488
0
        xmlXPathPErrMemory(ctxt);
5489
0
  xmlFree(hashs1);
5490
0
  xmlFree(values1);
5491
0
  xmlFree(values2);
5492
0
  return(0);
5493
0
    }
5494
40.1k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5495
4.17M
    for (i = 0;i < ns1->nodeNr;i++) {
5496
4.14M
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5497
45.6M
  for (j = 0;j < ns2->nodeNr;j++) {
5498
41.5M
      if (i == 0)
5499
152k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5500
41.5M
      if (hashs1[i] != hashs2[j]) {
5501
40.9M
    if (neq) {
5502
2.77k
        ret = 1;
5503
2.77k
        break;
5504
2.77k
    }
5505
40.9M
      }
5506
623k
      else {
5507
623k
    if (values1[i] == NULL) {
5508
619k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5509
619k
                    if (values1[i] == NULL)
5510
0
                        xmlXPathPErrMemory(ctxt);
5511
619k
                }
5512
623k
    if (values2[j] == NULL) {
5513
22.2k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5514
22.2k
                    if (values2[j] == NULL)
5515
0
                        xmlXPathPErrMemory(ctxt);
5516
22.2k
                }
5517
623k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5518
623k
    if (ret)
5519
4.66k
        break;
5520
623k
      }
5521
41.5M
  }
5522
4.14M
  if (ret)
5523
7.44k
      break;
5524
4.14M
    }
5525
4.25M
    for (i = 0;i < ns1->nodeNr;i++)
5526
4.21M
  if (values1[i] != NULL)
5527
619k
      xmlFree(values1[i]);
5528
199k
    for (j = 0;j < ns2->nodeNr;j++)
5529
159k
  if (values2[j] != NULL)
5530
22.2k
      xmlFree(values2[j]);
5531
40.1k
    xmlFree(values1);
5532
40.1k
    xmlFree(values2);
5533
40.1k
    xmlFree(hashs1);
5534
40.1k
    xmlFree(hashs2);
5535
40.1k
    return(ret);
5536
40.1k
}
5537
5538
static int
5539
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5540
1.18M
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5541
1.18M
    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
1.18M
    switch (arg1->type) {
5547
0
        case XPATH_UNDEFINED:
5548
0
      break;
5549
1.00M
        case XPATH_BOOLEAN:
5550
1.00M
      switch (arg2->type) {
5551
0
          case XPATH_UNDEFINED:
5552
0
        break;
5553
673k
    case XPATH_BOOLEAN:
5554
673k
        ret = (arg1->boolval == arg2->boolval);
5555
673k
        break;
5556
326k
    case XPATH_NUMBER:
5557
326k
        ret = (arg1->boolval ==
5558
326k
         xmlXPathCastNumberToBoolean(arg2->floatval));
5559
326k
        break;
5560
7.16k
    case XPATH_STRING:
5561
7.16k
        if ((arg2->stringval == NULL) ||
5562
7.16k
      (arg2->stringval[0] == 0)) ret = 0;
5563
5.88k
        else
5564
5.88k
      ret = 1;
5565
7.16k
        ret = (arg1->boolval == ret);
5566
7.16k
        break;
5567
0
    case XPATH_USERS:
5568
        /* TODO */
5569
0
        break;
5570
0
    case XPATH_NODESET:
5571
0
    case XPATH_XSLT_TREE:
5572
0
        break;
5573
1.00M
      }
5574
1.00M
      break;
5575
1.00M
        case XPATH_NUMBER:
5576
170k
      switch (arg2->type) {
5577
0
          case XPATH_UNDEFINED:
5578
0
        break;
5579
95.3k
    case XPATH_BOOLEAN:
5580
95.3k
        ret = (arg2->boolval==
5581
95.3k
         xmlXPathCastNumberToBoolean(arg1->floatval));
5582
95.3k
        break;
5583
7.82k
    case XPATH_STRING:
5584
7.82k
        xmlXPathValuePush(ctxt, arg2);
5585
7.82k
        xmlXPathNumberFunction(ctxt, 1);
5586
7.82k
        arg2 = xmlXPathValuePop(ctxt);
5587
7.82k
                    if (ctxt->error)
5588
0
                        break;
5589
                    /* Falls through. */
5590
75.1k
    case XPATH_NUMBER:
5591
        /* Hand check NaN and Infinity equalities */
5592
75.1k
        if (xmlXPathIsNaN(arg1->floatval) ||
5593
65.0k
          xmlXPathIsNaN(arg2->floatval)) {
5594
65.0k
            ret = 0;
5595
65.0k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5596
1.73k
            if (xmlXPathIsInf(arg2->floatval) == 1)
5597
458
          ret = 1;
5598
1.27k
      else
5599
1.27k
          ret = 0;
5600
8.34k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5601
1.60k
      if (xmlXPathIsInf(arg2->floatval) == -1)
5602
658
          ret = 1;
5603
944
      else
5604
944
          ret = 0;
5605
6.74k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5606
1.12k
      if (xmlXPathIsInf(arg1->floatval) == 1)
5607
0
          ret = 1;
5608
1.12k
      else
5609
1.12k
          ret = 0;
5610
5.62k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5611
671
      if (xmlXPathIsInf(arg1->floatval) == -1)
5612
0
          ret = 1;
5613
671
      else
5614
671
          ret = 0;
5615
4.95k
        } else {
5616
4.95k
            ret = (arg1->floatval == arg2->floatval);
5617
4.95k
        }
5618
75.1k
        break;
5619
0
    case XPATH_USERS:
5620
        /* TODO */
5621
0
        break;
5622
0
    case XPATH_NODESET:
5623
0
    case XPATH_XSLT_TREE:
5624
0
        break;
5625
170k
      }
5626
170k
      break;
5627
170k
        case XPATH_STRING:
5628
10.6k
      switch (arg2->type) {
5629
0
          case XPATH_UNDEFINED:
5630
0
        break;
5631
2.99k
    case XPATH_BOOLEAN:
5632
2.99k
        if ((arg1->stringval == NULL) ||
5633
2.99k
      (arg1->stringval[0] == 0)) ret = 0;
5634
1.01k
        else
5635
1.01k
      ret = 1;
5636
2.99k
        ret = (arg2->boolval == ret);
5637
2.99k
        break;
5638
2.01k
    case XPATH_STRING:
5639
2.01k
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5640
2.01k
        break;
5641
5.64k
    case XPATH_NUMBER:
5642
5.64k
        xmlXPathValuePush(ctxt, arg1);
5643
5.64k
        xmlXPathNumberFunction(ctxt, 1);
5644
5.64k
        arg1 = xmlXPathValuePop(ctxt);
5645
5.64k
                    if (ctxt->error)
5646
0
                        break;
5647
        /* Hand check NaN and Infinity equalities */
5648
5.64k
        if (xmlXPathIsNaN(arg1->floatval) ||
5649
3.43k
          xmlXPathIsNaN(arg2->floatval)) {
5650
3.43k
            ret = 0;
5651
3.43k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5652
4
      if (xmlXPathIsInf(arg2->floatval) == 1)
5653
2
          ret = 1;
5654
2
      else
5655
2
          ret = 0;
5656
2.20k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5657
4
      if (xmlXPathIsInf(arg2->floatval) == -1)
5658
2
          ret = 1;
5659
2
      else
5660
2
          ret = 0;
5661
2.20k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5662
644
      if (xmlXPathIsInf(arg1->floatval) == 1)
5663
0
          ret = 1;
5664
644
      else
5665
644
          ret = 0;
5666
1.55k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5667
226
      if (xmlXPathIsInf(arg1->floatval) == -1)
5668
0
          ret = 1;
5669
226
      else
5670
226
          ret = 0;
5671
1.33k
        } else {
5672
1.33k
            ret = (arg1->floatval == arg2->floatval);
5673
1.33k
        }
5674
5.64k
        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
10.6k
      }
5682
10.6k
      break;
5683
10.6k
        case XPATH_USERS:
5684
      /* TODO */
5685
0
      break;
5686
0
  case XPATH_NODESET:
5687
0
  case XPATH_XSLT_TREE:
5688
0
      break;
5689
1.18M
    }
5690
1.18M
    xmlXPathReleaseObject(ctxt->context, arg1);
5691
1.18M
    xmlXPathReleaseObject(ctxt->context, arg2);
5692
1.18M
    return(ret);
5693
1.18M
}
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
18.7M
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5703
18.7M
    xmlXPathObjectPtr arg1, arg2, argtmp;
5704
18.7M
    int ret = 0;
5705
5706
18.7M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5707
18.7M
    arg2 = xmlXPathValuePop(ctxt);
5708
18.7M
    arg1 = xmlXPathValuePop(ctxt);
5709
18.7M
    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
18.7M
    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
18.7M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5726
17.5M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5727
  /*
5728
   *Hack it to assure arg1 is the nodeset
5729
   */
5730
17.5M
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5731
8.63M
    argtmp = arg2;
5732
8.63M
    arg2 = arg1;
5733
8.63M
    arg1 = argtmp;
5734
8.63M
  }
5735
17.5M
  switch (arg2->type) {
5736
0
      case XPATH_UNDEFINED:
5737
0
    break;
5738
259k
      case XPATH_NODESET:
5739
259k
      case XPATH_XSLT_TREE:
5740
259k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5741
259k
    break;
5742
16.3M
      case XPATH_BOOLEAN:
5743
16.3M
    if ((arg1->nodesetval == NULL) ||
5744
16.3M
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5745
59.2k
    else
5746
59.2k
        ret = 1;
5747
16.3M
    ret = (ret == arg2->boolval);
5748
16.3M
    break;
5749
488k
      case XPATH_NUMBER:
5750
488k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5751
488k
    break;
5752
509k
      case XPATH_STRING:
5753
509k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5754
509k
                                                 arg2->stringval, 0);
5755
509k
    break;
5756
0
      case XPATH_USERS:
5757
    /* TODO */
5758
0
    break;
5759
17.5M
  }
5760
17.5M
  xmlXPathReleaseObject(ctxt->context, arg1);
5761
17.5M
  xmlXPathReleaseObject(ctxt->context, arg2);
5762
17.5M
  return(ret);
5763
17.5M
    }
5764
5765
1.17M
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5766
18.7M
}
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
1.36M
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5776
1.36M
    xmlXPathObjectPtr arg1, arg2, argtmp;
5777
1.36M
    int ret = 0;
5778
5779
1.36M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5780
1.36M
    arg2 = xmlXPathValuePop(ctxt);
5781
1.36M
    arg1 = xmlXPathValuePop(ctxt);
5782
1.36M
    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
1.36M
    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
1.36M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5799
1.34M
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5800
  /*
5801
   *Hack it to assure arg1 is the nodeset
5802
   */
5803
1.34M
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5804
22.2k
    argtmp = arg2;
5805
22.2k
    arg2 = arg1;
5806
22.2k
    arg1 = argtmp;
5807
22.2k
  }
5808
1.34M
  switch (arg2->type) {
5809
0
      case XPATH_UNDEFINED:
5810
0
    break;
5811
7.49k
      case XPATH_NODESET:
5812
7.49k
      case XPATH_XSLT_TREE:
5813
7.49k
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5814
7.49k
    break;
5815
1.31M
      case XPATH_BOOLEAN:
5816
1.31M
    if ((arg1->nodesetval == NULL) ||
5817
1.31M
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5818
2.86k
    else
5819
2.86k
        ret = 1;
5820
1.31M
    ret = (ret != arg2->boolval);
5821
1.31M
    break;
5822
12.2k
      case XPATH_NUMBER:
5823
12.2k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5824
12.2k
    break;
5825
7.29k
      case XPATH_STRING:
5826
7.29k
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5827
7.29k
                                                 arg2->stringval, 1);
5828
7.29k
    break;
5829
0
      case XPATH_USERS:
5830
    /* TODO */
5831
0
    break;
5832
1.34M
  }
5833
1.34M
  xmlXPathReleaseObject(ctxt->context, arg1);
5834
1.34M
  xmlXPathReleaseObject(ctxt->context, arg2);
5835
1.34M
  return(ret);
5836
1.34M
    }
5837
5838
16.0k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5839
1.36M
}
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
16.6M
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5865
16.6M
    int ret = 0, arg1i = 0, arg2i = 0;
5866
16.6M
    xmlXPathObjectPtr arg1, arg2;
5867
5868
16.6M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5869
16.6M
    arg2 = xmlXPathValuePop(ctxt);
5870
16.6M
    arg1 = xmlXPathValuePop(ctxt);
5871
16.6M
    if ((arg1 == NULL) || (arg2 == NULL)) {
5872
0
  if (arg1 != NULL)
5873
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5874
0
  else
5875
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5876
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5877
0
    }
5878
5879
16.6M
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5880
12.9M
      (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
12.9M
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5887
12.4M
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5888
2.20M
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5889
10.7M
  } else {
5890
10.7M
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5891
500k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5892
500k
                                arg1, arg2);
5893
10.2M
      } else {
5894
10.2M
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5895
10.2M
                                arg2, arg1);
5896
10.2M
      }
5897
10.7M
  }
5898
12.9M
  return(ret);
5899
12.9M
    }
5900
5901
3.68M
    if (arg1->type != XPATH_NUMBER) {
5902
3.00M
  xmlXPathValuePush(ctxt, arg1);
5903
3.00M
  xmlXPathNumberFunction(ctxt, 1);
5904
3.00M
  arg1 = xmlXPathValuePop(ctxt);
5905
3.00M
    }
5906
3.68M
    if (arg2->type != XPATH_NUMBER) {
5907
2.47M
  xmlXPathValuePush(ctxt, arg2);
5908
2.47M
  xmlXPathNumberFunction(ctxt, 1);
5909
2.47M
  arg2 = xmlXPathValuePop(ctxt);
5910
2.47M
    }
5911
3.68M
    if (ctxt->error)
5912
0
        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
3.68M
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5919
1.28M
  ret=0;
5920
2.39M
    } else {
5921
2.39M
  arg1i=xmlXPathIsInf(arg1->floatval);
5922
2.39M
  arg2i=xmlXPathIsInf(arg2->floatval);
5923
2.39M
  if (inf && strict) {
5924
332k
      if ((arg1i == -1 && arg2i != -1) ||
5925
330k
    (arg2i == 1 && arg1i != 1)) {
5926
6.04k
    ret = 1;
5927
326k
      } else if (arg1i == 0 && arg2i == 0) {
5928
317k
    ret = (arg1->floatval < arg2->floatval);
5929
317k
      } else {
5930
8.51k
    ret = 0;
5931
8.51k
      }
5932
332k
  }
5933
2.06M
  else if (inf && !strict) {
5934
1.99M
      if (arg1i == -1 || arg2i == 1) {
5935
1.15k
    ret = 1;
5936
1.99M
      } else if (arg1i == 0 && arg2i == 0) {
5937
1.98M
    ret = (arg1->floatval <= arg2->floatval);
5938
1.98M
      } else {
5939
1.78k
    ret = 0;
5940
1.78k
      }
5941
1.99M
  }
5942
75.1k
  else if (!inf && strict) {
5943
66.6k
      if ((arg1i == 1 && arg2i != 1) ||
5944
65.1k
    (arg2i == -1 && arg1i != -1)) {
5945
3.56k
    ret = 1;
5946
63.1k
      } else if (arg1i == 0 && arg2i == 0) {
5947
57.9k
    ret = (arg1->floatval > arg2->floatval);
5948
57.9k
      } else {
5949
5.17k
    ret = 0;
5950
5.17k
      }
5951
66.6k
  }
5952
8.48k
  else if (!inf && !strict) {
5953
8.48k
      if (arg1i == 1 || arg2i == -1) {
5954
2.20k
    ret = 1;
5955
6.28k
      } else if (arg1i == 0 && arg2i == 0) {
5956
2.54k
    ret = (arg1->floatval >= arg2->floatval);
5957
3.73k
      } else {
5958
3.73k
    ret = 0;
5959
3.73k
      }
5960
8.48k
  }
5961
2.39M
    }
5962
3.68M
error:
5963
3.68M
    xmlXPathReleaseObject(ctxt->context, arg1);
5964
3.68M
    xmlXPathReleaseObject(ctxt->context, arg2);
5965
3.68M
    return(ret);
5966
3.68M
}
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
866k
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5977
866k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5978
866k
    CAST_TO_NUMBER;
5979
866k
    CHECK_TYPE(XPATH_NUMBER);
5980
866k
    ctxt->value->floatval = -ctxt->value->floatval;
5981
866k
}
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
147k
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5992
147k
    xmlXPathObjectPtr arg;
5993
147k
    double val;
5994
5995
147k
    arg = xmlXPathValuePop(ctxt);
5996
147k
    if (arg == NULL)
5997
147k
  XP_ERROR(XPATH_INVALID_OPERAND);
5998
147k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5999
147k
    xmlXPathReleaseObject(ctxt->context, arg);
6000
147k
    CAST_TO_NUMBER;
6001
147k
    CHECK_TYPE(XPATH_NUMBER);
6002
147k
    ctxt->value->floatval += val;
6003
147k
}
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
866k
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
6014
866k
    xmlXPathObjectPtr arg;
6015
866k
    double val;
6016
6017
866k
    arg = xmlXPathValuePop(ctxt);
6018
866k
    if (arg == NULL)
6019
866k
  XP_ERROR(XPATH_INVALID_OPERAND);
6020
866k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6021
866k
    xmlXPathReleaseObject(ctxt->context, arg);
6022
866k
    CAST_TO_NUMBER;
6023
866k
    CHECK_TYPE(XPATH_NUMBER);
6024
866k
    ctxt->value->floatval -= val;
6025
866k
}
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
18.6M
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6036
18.6M
    xmlXPathObjectPtr arg;
6037
18.6M
    double val;
6038
6039
18.6M
    arg = xmlXPathValuePop(ctxt);
6040
18.6M
    if (arg == NULL)
6041
18.6M
  XP_ERROR(XPATH_INVALID_OPERAND);
6042
18.6M
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6043
18.6M
    xmlXPathReleaseObject(ctxt->context, arg);
6044
18.6M
    CAST_TO_NUMBER;
6045
18.6M
    CHECK_TYPE(XPATH_NUMBER);
6046
18.6M
    ctxt->value->floatval *= val;
6047
18.6M
}
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.46k
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6059
1.46k
    xmlXPathObjectPtr arg;
6060
1.46k
    double val;
6061
6062
1.46k
    arg = xmlXPathValuePop(ctxt);
6063
1.46k
    if (arg == NULL)
6064
1.46k
  XP_ERROR(XPATH_INVALID_OPERAND);
6065
1.46k
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6066
1.46k
    xmlXPathReleaseObject(ctxt->context, arg);
6067
1.46k
    CAST_TO_NUMBER;
6068
1.46k
    CHECK_TYPE(XPATH_NUMBER);
6069
1.46k
    ctxt->value->floatval /= val;
6070
1.46k
}
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
72.6k
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6081
72.6k
    xmlXPathObjectPtr arg;
6082
72.6k
    double arg1, arg2;
6083
6084
72.6k
    arg = xmlXPathValuePop(ctxt);
6085
72.6k
    if (arg == NULL)
6086
72.6k
  XP_ERROR(XPATH_INVALID_OPERAND);
6087
72.6k
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6088
72.6k
    xmlXPathReleaseObject(ctxt->context, arg);
6089
72.6k
    CAST_TO_NUMBER;
6090
72.6k
    CHECK_TYPE(XPATH_NUMBER);
6091
72.6k
    arg1 = ctxt->value->floatval;
6092
72.6k
    if (arg2 == 0)
6093
542
  ctxt->value->floatval = xmlXPathNAN;
6094
72.1k
    else {
6095
72.1k
  ctxt->value->floatval = fmod(arg1, arg2);
6096
72.1k
    }
6097
72.6k
}
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
2.46M
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6139
2.46M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6140
2.46M
    if (cur == NULL)
6141
1.23M
        return(ctxt->context->node);
6142
1.23M
    return(NULL);
6143
2.46M
}
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
19.8M
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6155
19.8M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6156
19.8M
    if (cur == NULL) {
6157
9.99M
  if (ctxt->context->node == NULL) return(NULL);
6158
9.99M
  switch (ctxt->context->node->type) {
6159
3.80M
            case XML_ELEMENT_NODE:
6160
8.38M
            case XML_TEXT_NODE:
6161
8.39M
            case XML_CDATA_SECTION_NODE:
6162
8.39M
            case XML_ENTITY_REF_NODE:
6163
8.39M
            case XML_ENTITY_NODE:
6164
9.02M
            case XML_PI_NODE:
6165
9.84M
            case XML_COMMENT_NODE:
6166
9.84M
            case XML_NOTATION_NODE:
6167
9.84M
            case XML_DTD_NODE:
6168
9.84M
    return(ctxt->context->node->children);
6169
48.0k
            case XML_DOCUMENT_NODE:
6170
48.0k
            case XML_DOCUMENT_TYPE_NODE:
6171
48.0k
            case XML_DOCUMENT_FRAG_NODE:
6172
48.0k
            case XML_HTML_DOCUMENT_NODE:
6173
48.0k
    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
18.8k
            case XML_ATTRIBUTE_NODE:
6178
100k
      case XML_NAMESPACE_DECL:
6179
100k
      case XML_XINCLUDE_START:
6180
100k
      case XML_XINCLUDE_END:
6181
100k
    return(NULL);
6182
9.99M
  }
6183
0
  return(NULL);
6184
9.99M
    }
6185
9.82M
    if ((cur->type == XML_DOCUMENT_NODE) ||
6186
9.82M
        (cur->type == XML_HTML_DOCUMENT_NODE))
6187
0
  return(NULL);
6188
9.82M
    return(cur->next);
6189
9.82M
}
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
275M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6201
275M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6202
275M
    if (cur == NULL) {
6203
150M
  cur = ctxt->context->node;
6204
150M
  if (cur == NULL) return(NULL);
6205
  /*
6206
  * Get the first element child.
6207
  */
6208
150M
  switch (cur->type) {
6209
119M
            case XML_ELEMENT_NODE:
6210
119M
      case XML_DOCUMENT_FRAG_NODE:
6211
119M
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6212
119M
            case XML_ENTITY_NODE:
6213
119M
    cur = cur->children;
6214
119M
    if (cur != NULL) {
6215
13.2M
        if (cur->type == XML_ELEMENT_NODE)
6216
3.92M
      return(cur);
6217
12.3M
        do {
6218
12.3M
      cur = cur->next;
6219
12.3M
        } while ((cur != NULL) &&
6220
8.27M
      (cur->type != XML_ELEMENT_NODE));
6221
9.29M
        return(cur);
6222
13.2M
    }
6223
106M
    return(NULL);
6224
3.72M
            case XML_DOCUMENT_NODE:
6225
3.72M
            case XML_HTML_DOCUMENT_NODE:
6226
3.72M
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6227
27.0M
      default:
6228
27.0M
    return(NULL);
6229
150M
  }
6230
0
  return(NULL);
6231
150M
    }
6232
    /*
6233
    * Get the next sibling element node.
6234
    */
6235
124M
    switch (cur->type) {
6236
124M
  case XML_ELEMENT_NODE:
6237
124M
  case XML_TEXT_NODE:
6238
124M
  case XML_ENTITY_REF_NODE:
6239
124M
  case XML_ENTITY_NODE:
6240
124M
  case XML_CDATA_SECTION_NODE:
6241
124M
  case XML_PI_NODE:
6242
124M
  case XML_COMMENT_NODE:
6243
124M
  case XML_XINCLUDE_END:
6244
124M
      break;
6245
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6246
0
  default:
6247
0
      return(NULL);
6248
124M
    }
6249
124M
    if (cur->next != NULL) {
6250
118M
  if (cur->next->type == XML_ELEMENT_NODE)
6251
98.2M
      return(cur->next);
6252
19.8M
  cur = cur->next;
6253
22.9M
  do {
6254
22.9M
      cur = cur->next;
6255
22.9M
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6256
19.8M
  return(cur);
6257
118M
    }
6258
6.39M
    return(NULL);
6259
124M
}
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
474M
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6272
474M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6273
474M
    if (cur == NULL) {
6274
3.70M
  if (ctxt->context->node == NULL)
6275
0
      return(NULL);
6276
3.70M
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6277
3.61M
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6278
110k
      return(NULL);
6279
6280
3.59M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6281
441k
      return(ctxt->context->doc->children);
6282
3.15M
        return(ctxt->context->node->children);
6283
3.59M
    }
6284
6285
470M
    if (cur->type == XML_NAMESPACE_DECL)
6286
0
        return(NULL);
6287
470M
    if (cur->children != NULL) {
6288
  /*
6289
   * Do not descend on entities declarations
6290
   */
6291
61.2M
  if (cur->children->type != XML_ENTITY_DECL) {
6292
61.2M
      cur = cur->children;
6293
      /*
6294
       * Skip DTDs
6295
       */
6296
61.2M
      if (cur->type != XML_DTD_NODE)
6297
61.2M
    return(cur);
6298
61.2M
  }
6299
61.2M
    }
6300
6301
409M
    if (cur == ctxt->context->node) return(NULL);
6302
6303
408M
    while (cur->next != NULL) {
6304
367M
  cur = cur->next;
6305
367M
  if ((cur->type != XML_ENTITY_DECL) &&
6306
367M
      (cur->type != XML_DTD_NODE))
6307
367M
      return(cur);
6308
367M
    }
6309
6310
62.5M
    do {
6311
62.5M
        cur = cur->parent;
6312
62.5M
  if (cur == NULL) break;
6313
62.5M
  if (cur == ctxt->context->node) return(NULL);
6314
60.1M
  if (cur->next != NULL) {
6315
39.3M
      cur = cur->next;
6316
39.3M
      return(cur);
6317
39.3M
  }
6318
60.1M
    } while (cur != NULL);
6319
0
    return(cur);
6320
41.7M
}
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
206M
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6335
206M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6336
206M
    if (cur == NULL)
6337
1.99M
        return(ctxt->context->node);
6338
6339
204M
    if (ctxt->context->node == NULL)
6340
0
        return(NULL);
6341
204M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6342
204M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6343
105k
        return(NULL);
6344
6345
204M
    return(xmlXPathNextDescendant(ctxt, cur));
6346
204M
}
6347
6348
/**
6349
 * Traversal function for the "parent" direction
6350
 * The parent axis contains the parent of the context node, if there is one.
6351
 *
6352
 * @param ctxt  the XPath Parser context
6353
 * @param cur  the current node in the traversal
6354
 * @returns the next element following that axis
6355
 */
6356
xmlNode *
6357
2.13M
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6358
2.13M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6359
    /*
6360
     * the parent of an attribute or namespace node is the element
6361
     * to which the attribute or namespace node is attached
6362
     * Namespace handling !!!
6363
     */
6364
2.13M
    if (cur == NULL) {
6365
1.07M
  if (ctxt->context->node == NULL) return(NULL);
6366
1.07M
  switch (ctxt->context->node->type) {
6367
264k
            case XML_ELEMENT_NODE:
6368
892k
            case XML_TEXT_NODE:
6369
893k
            case XML_CDATA_SECTION_NODE:
6370
893k
            case XML_ENTITY_REF_NODE:
6371
893k
            case XML_ENTITY_NODE:
6372
901k
            case XML_PI_NODE:
6373
1.03M
            case XML_COMMENT_NODE:
6374
1.03M
            case XML_NOTATION_NODE:
6375
1.03M
            case XML_DTD_NODE:
6376
1.03M
      case XML_ELEMENT_DECL:
6377
1.03M
      case XML_ATTRIBUTE_DECL:
6378
1.03M
      case XML_XINCLUDE_START:
6379
1.03M
      case XML_XINCLUDE_END:
6380
1.03M
      case XML_ENTITY_DECL:
6381
1.03M
    if (ctxt->context->node->parent == NULL)
6382
0
        return((xmlNodePtr) ctxt->context->doc);
6383
1.03M
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6384
1.02M
        ((ctxt->context->node->parent->name[0] == ' ') ||
6385
1.02M
         (xmlStrEqual(ctxt->context->node->parent->name,
6386
1.02M
         BAD_CAST "fake node libxslt"))))
6387
0
        return(NULL);
6388
1.03M
    return(ctxt->context->node->parent);
6389
3.89k
            case XML_ATTRIBUTE_NODE: {
6390
3.89k
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6391
6392
3.89k
    return(att->parent);
6393
1.03M
      }
6394
15.2k
            case XML_DOCUMENT_NODE:
6395
15.2k
            case XML_DOCUMENT_TYPE_NODE:
6396
15.2k
            case XML_DOCUMENT_FRAG_NODE:
6397
15.2k
            case XML_HTML_DOCUMENT_NODE:
6398
15.2k
                return(NULL);
6399
19.6k
      case XML_NAMESPACE_DECL: {
6400
19.6k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6401
6402
19.6k
    if ((ns->next != NULL) &&
6403
19.6k
        (ns->next->type != XML_NAMESPACE_DECL))
6404
19.6k
        return((xmlNodePtr) ns->next);
6405
0
                return(NULL);
6406
19.6k
      }
6407
1.07M
  }
6408
1.07M
    }
6409
1.06M
    return(NULL);
6410
2.13M
}
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
7.27M
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6426
7.27M
    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
7.27M
    if (cur == NULL) {
6433
105k
  if (ctxt->context->node == NULL) return(NULL);
6434
105k
  switch (ctxt->context->node->type) {
6435
66.8k
            case XML_ELEMENT_NODE:
6436
92.1k
            case XML_TEXT_NODE:
6437
93.0k
            case XML_CDATA_SECTION_NODE:
6438
93.0k
            case XML_ENTITY_REF_NODE:
6439
93.0k
            case XML_ENTITY_NODE:
6440
93.9k
            case XML_PI_NODE:
6441
95.3k
            case XML_COMMENT_NODE:
6442
95.3k
      case XML_DTD_NODE:
6443
95.3k
      case XML_ELEMENT_DECL:
6444
95.3k
      case XML_ATTRIBUTE_DECL:
6445
95.3k
      case XML_ENTITY_DECL:
6446
95.3k
            case XML_NOTATION_NODE:
6447
95.3k
      case XML_XINCLUDE_START:
6448
95.3k
      case XML_XINCLUDE_END:
6449
95.3k
    if (ctxt->context->node->parent == NULL)
6450
0
        return((xmlNodePtr) ctxt->context->doc);
6451
95.3k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6452
92.5k
        ((ctxt->context->node->parent->name[0] == ' ') ||
6453
92.5k
         (xmlStrEqual(ctxt->context->node->parent->name,
6454
92.5k
         BAD_CAST "fake node libxslt"))))
6455
0
        return(NULL);
6456
95.3k
    return(ctxt->context->node->parent);
6457
1.56k
            case XML_ATTRIBUTE_NODE: {
6458
1.56k
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6459
6460
1.56k
    return(tmp->parent);
6461
95.3k
      }
6462
2.30k
            case XML_DOCUMENT_NODE:
6463
2.30k
            case XML_DOCUMENT_TYPE_NODE:
6464
2.30k
            case XML_DOCUMENT_FRAG_NODE:
6465
2.30k
            case XML_HTML_DOCUMENT_NODE:
6466
2.30k
                return(NULL);
6467
6.11k
      case XML_NAMESPACE_DECL: {
6468
6.11k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6469
6470
6.11k
    if ((ns->next != NULL) &&
6471
6.11k
        (ns->next->type != XML_NAMESPACE_DECL))
6472
6.11k
        return((xmlNodePtr) ns->next);
6473
    /* Bad, how did that namespace end up here ? */
6474
0
                return(NULL);
6475
6.11k
      }
6476
105k
  }
6477
0
  return(NULL);
6478
105k
    }
6479
7.16M
    if (cur == ctxt->context->doc->children)
6480
60.5k
  return((xmlNodePtr) ctxt->context->doc);
6481
7.10M
    if (cur == (xmlNodePtr) ctxt->context->doc)
6482
583k
  return(NULL);
6483
6.52M
    switch (cur->type) {
6484
6.13M
  case XML_ELEMENT_NODE:
6485
6.22M
  case XML_TEXT_NODE:
6486
6.22M
  case XML_CDATA_SECTION_NODE:
6487
6.22M
  case XML_ENTITY_REF_NODE:
6488
6.22M
  case XML_ENTITY_NODE:
6489
6.23M
  case XML_PI_NODE:
6490
6.23M
  case XML_COMMENT_NODE:
6491
6.23M
  case XML_NOTATION_NODE:
6492
6.23M
  case XML_DTD_NODE:
6493
6.23M
        case XML_ELEMENT_DECL:
6494
6.23M
        case XML_ATTRIBUTE_DECL:
6495
6.23M
        case XML_ENTITY_DECL:
6496
6.23M
  case XML_XINCLUDE_START:
6497
6.23M
  case XML_XINCLUDE_END:
6498
6.23M
      if (cur->parent == NULL)
6499
0
    return(NULL);
6500
6.23M
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6501
5.71M
    ((cur->parent->name[0] == ' ') ||
6502
5.71M
     (xmlStrEqual(cur->parent->name,
6503
5.71M
            BAD_CAST "fake node libxslt"))))
6504
0
    return(NULL);
6505
6.23M
      return(cur->parent);
6506
15.2k
  case XML_ATTRIBUTE_NODE: {
6507
15.2k
      xmlAttrPtr att = (xmlAttrPtr) cur;
6508
6509
15.2k
      return(att->parent);
6510
6.23M
  }
6511
274k
  case XML_NAMESPACE_DECL: {
6512
274k
      xmlNsPtr ns = (xmlNsPtr) cur;
6513
6514
274k
      if ((ns->next != NULL) &&
6515
274k
          (ns->next->type != XML_NAMESPACE_DECL))
6516
274k
          return((xmlNodePtr) ns->next);
6517
      /* Bad, how did that namespace end up here ? */
6518
0
            return(NULL);
6519
274k
  }
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
6.52M
    }
6526
0
    return(NULL);
6527
6.52M
}
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
5.76M
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6542
5.76M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6543
5.76M
    if (cur == NULL)
6544
480k
        return(ctxt->context->node);
6545
5.28M
    return(xmlXPathNextAncestor(ctxt, cur));
6546
5.76M
}
6547
6548
/**
6549
 * Traversal function for the "following-sibling" direction
6550
 * The following-sibling axis contains the following siblings of the context
6551
 * node in document order.
6552
 *
6553
 * @param ctxt  the XPath Parser context
6554
 * @param cur  the current node in the traversal
6555
 * @returns the next element following that axis
6556
 */
6557
xmlNode *
6558
1.73k
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6559
1.73k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6560
1.73k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6561
1.29k
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6562
438
        return(NULL);
6563
6564
1.29k
    if (cur == (xmlNodePtr) ctxt->context->doc)
6565
0
        return(NULL);
6566
6567
1.29k
    if (cur == NULL)
6568
766
        cur = ctxt->context->node;
6569
6570
1.29k
    if (cur->type == XML_DOCUMENT_NODE)
6571
596
        return(NULL);
6572
6573
700
    return(cur->next);
6574
1.29k
}
6575
6576
/**
6577
 * Traversal function for the "preceding-sibling" direction
6578
 * The preceding-sibling axis contains the preceding siblings of the context
6579
 * node in reverse document order; the first preceding sibling is first on the
6580
 * axis; the sibling preceding that node is the second on the axis and so on.
6581
 *
6582
 * @param ctxt  the XPath Parser context
6583
 * @param cur  the current node in the traversal
6584
 * @returns the next element following that axis
6585
 */
6586
xmlNode *
6587
1.38M
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6588
1.38M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6589
1.38M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6590
1.33M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6591
150k
        return(NULL);
6592
6593
1.23M
    if (cur == (xmlNodePtr) ctxt->context->doc)
6594
0
        return(NULL);
6595
6596
1.23M
    if (cur == NULL) {
6597
137k
        cur = ctxt->context->node;
6598
1.09M
    } else if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6599
220
        cur = cur->prev;
6600
220
        if (cur == NULL)
6601
0
            cur = ctxt->context->node;
6602
220
    }
6603
6604
1.23M
    if (cur->type == XML_DOCUMENT_NODE)
6605
1.32k
        return(NULL);
6606
6607
1.22M
    return(cur->prev);
6608
1.23M
}
6609
6610
/**
6611
 * Traversal function for the "following" direction
6612
 * The following axis contains all nodes in the same document as the context
6613
 * node that are after the context node in document order, excluding any
6614
 * descendants and excluding attribute nodes and namespace nodes; the nodes
6615
 * are ordered in document order
6616
 *
6617
 * @param ctxt  the XPath Parser context
6618
 * @param cur  the current node in the traversal
6619
 * @returns the next element following that axis
6620
 */
6621
xmlNode *
6622
37.5k
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6623
37.5k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6624
37.5k
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6625
31.0k
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6626
3.44k
        return(cur->children);
6627
6628
34.1k
    if (cur == NULL) {
6629
6.52k
        cur = ctxt->context->node;
6630
6.52k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6631
430
            cur = cur->parent;
6632
6.09k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6633
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6634
6635
0
            if ((ns->next == NULL) ||
6636
0
                (ns->next->type == XML_NAMESPACE_DECL))
6637
0
                return (NULL);
6638
0
            cur = (xmlNodePtr) ns->next;
6639
0
        }
6640
6.52k
    }
6641
6642
    /* ERROR */
6643
34.1k
    if (cur == NULL)
6644
0
        return(NULL);
6645
6646
34.1k
    if (cur->type == XML_DOCUMENT_NODE)
6647
440
        return(NULL);
6648
6649
33.6k
    if (cur->next != NULL)
6650
22.7k
        return(cur->next);
6651
6652
16.9k
    do {
6653
16.9k
        cur = cur->parent;
6654
16.9k
        if (cur == NULL)
6655
0
            break;
6656
16.9k
        if (cur == (xmlNodePtr) ctxt->context->doc)
6657
6.08k
            return(NULL);
6658
10.8k
        if (cur->next != NULL && cur->type != XML_DOCUMENT_NODE)
6659
4.90k
            return(cur->next);
6660
10.8k
    } while (cur != NULL);
6661
6662
0
    return(cur);
6663
10.9k
}
6664
6665
/*
6666
 * @param ancestor  the ancestor node
6667
 * @param node  the current node
6668
 *
6669
 * Check that `ancestor` is a `node`'s ancestor
6670
 *
6671
 * @returns 1 if `ancestor` is a `node`'s ancestor, 0 otherwise.
6672
 */
6673
static int
6674
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6675
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
6676
0
    if (node->type == XML_NAMESPACE_DECL)
6677
0
        return(0);
6678
0
    if (ancestor->type == XML_NAMESPACE_DECL)
6679
0
        return(0);
6680
    /* nodes need to be in the same document */
6681
0
    if (ancestor->doc != node->doc) return(0);
6682
    /* avoid searching if ancestor or node is the root node */
6683
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
6684
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
6685
0
    while (node->parent != NULL) {
6686
0
        if (node->parent == ancestor)
6687
0
            return(1);
6688
0
  node = node->parent;
6689
0
    }
6690
0
    return(0);
6691
0
}
6692
6693
/**
6694
 * Traversal function for the "preceding" direction
6695
 * the preceding axis contains all nodes in the same document as the context
6696
 * node that are before the context node in document order, excluding any
6697
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6698
 * ordered in reverse document order
6699
 *
6700
 * @param ctxt  the XPath Parser context
6701
 * @param cur  the current node in the traversal
6702
 * @returns the next element following that axis
6703
 */
6704
xmlNode *
6705
xmlXPathNextPreceding(xmlXPathParserContext *ctxt, xmlNode *cur)
6706
0
{
6707
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6708
0
    if (cur == NULL) {
6709
0
        cur = ctxt->context->node;
6710
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6711
0
            cur = cur->parent;
6712
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6713
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6714
6715
0
            if ((ns->next == NULL) ||
6716
0
                (ns->next->type == XML_NAMESPACE_DECL))
6717
0
                return (NULL);
6718
0
            cur = (xmlNodePtr) ns->next;
6719
0
        }
6720
0
    }
6721
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
6722
0
  return (NULL);
6723
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6724
0
  cur = cur->prev;
6725
0
    do {
6726
0
        if (cur->prev != NULL) {
6727
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6728
0
            return (cur);
6729
0
        }
6730
6731
0
        cur = cur->parent;
6732
0
        if (cur == NULL)
6733
0
            return (NULL);
6734
0
        if (cur == ctxt->context->doc->children)
6735
0
            return (NULL);
6736
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
6737
0
    return (cur);
6738
0
}
6739
6740
/**
6741
 * Traversal function for the "preceding" direction
6742
 * the preceding axis contains all nodes in the same document as the context
6743
 * node that are before the context node in document order, excluding any
6744
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6745
 * ordered in reverse document order
6746
 * This is a faster implementation but internal only since it requires a
6747
 * state kept in the parser context: ctxt->ancestor.
6748
 *
6749
 * @param ctxt  the XPath Parser context
6750
 * @param cur  the current node in the traversal
6751
 * @returns the next element following that axis
6752
 */
6753
static xmlNodePtr
6754
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6755
                              xmlNodePtr cur)
6756
490k
{
6757
490k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6758
490k
    if (cur == NULL) {
6759
12.7k
        cur = ctxt->context->node;
6760
12.7k
        if (cur == NULL)
6761
0
            return (NULL);
6762
12.7k
        if (cur->type == XML_ATTRIBUTE_NODE) {
6763
1.00k
            cur = cur->parent;
6764
11.7k
        } else if (cur->type == XML_NAMESPACE_DECL) {
6765
5.23k
            xmlNsPtr ns = (xmlNsPtr) cur;
6766
6767
5.23k
            if ((ns->next == NULL) ||
6768
5.23k
                (ns->next->type == XML_NAMESPACE_DECL))
6769
0
                return (NULL);
6770
5.23k
            cur = (xmlNodePtr) ns->next;
6771
5.23k
        }
6772
12.7k
        ctxt->ancestor = cur->parent;
6773
12.7k
    }
6774
6775
490k
    if (cur->type == XML_NAMESPACE_DECL || cur->type == XML_DOCUMENT_NODE)
6776
100
        return(NULL);
6777
6778
490k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6779
74
  cur = cur->prev;
6780
6781
563k
    while (cur->prev == NULL) {
6782
181k
        cur = cur->parent;
6783
181k
        if (cur == NULL)
6784
12.2k
            return (NULL);
6785
169k
        if (cur == ctxt->context->doc->children)
6786
440
            return (NULL);
6787
169k
        if (cur != ctxt->ancestor)
6788
95.9k
            return (cur);
6789
73.1k
        ctxt->ancestor = cur->parent;
6790
73.1k
    }
6791
6792
381k
    if (cur->type == XML_DOCUMENT_NODE)
6793
0
        return(NULL);
6794
6795
381k
    cur = cur->prev;
6796
477k
    while (cur->last != NULL)
6797
95.9k
        cur = cur->last;
6798
381k
    return (cur);
6799
381k
}
6800
6801
/**
6802
 * Traversal function for the "namespace" direction
6803
 * the namespace axis contains the namespace nodes of the context node;
6804
 * the order of nodes on this axis is implementation-defined; the axis will
6805
 * be empty unless the context node is an element
6806
 *
6807
 * We keep the XML namespace node at the end of the list.
6808
 *
6809
 * @param ctxt  the XPath Parser context
6810
 * @param cur  the current attribute in the traversal
6811
 * @returns the next element following that axis
6812
 */
6813
xmlNode *
6814
3.47M
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6815
3.47M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6816
3.47M
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6817
1.77M
    if (cur == NULL) {
6818
546k
        if (ctxt->context->tmpNsList != NULL)
6819
0
      xmlFree(ctxt->context->tmpNsList);
6820
546k
  ctxt->context->tmpNsNr = 0;
6821
546k
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6822
546k
                             &ctxt->context->tmpNsList) < 0) {
6823
0
            xmlXPathPErrMemory(ctxt);
6824
0
            return(NULL);
6825
0
        }
6826
546k
        if (ctxt->context->tmpNsList != NULL) {
6827
1.17M
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6828
677k
                ctxt->context->tmpNsNr++;
6829
677k
            }
6830
492k
        }
6831
546k
  return((xmlNodePtr) xmlXPathXMLNamespace);
6832
546k
    }
6833
1.22M
    if (ctxt->context->tmpNsNr > 0) {
6834
677k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6835
677k
    } else {
6836
546k
  if (ctxt->context->tmpNsList != NULL)
6837
492k
      xmlFree(ctxt->context->tmpNsList);
6838
546k
  ctxt->context->tmpNsList = NULL;
6839
546k
  return(NULL);
6840
546k
    }
6841
1.22M
}
6842
6843
/**
6844
 * Traversal function for the "attribute" direction
6845
 * TODO: support DTD inherited default attributes
6846
 *
6847
 * @param ctxt  the XPath Parser context
6848
 * @param cur  the current attribute in the traversal
6849
 * @returns the next element following that axis
6850
 */
6851
xmlNode *
6852
152M
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6853
152M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6854
152M
    if (ctxt->context->node == NULL)
6855
0
  return(NULL);
6856
152M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6857
47.3M
  return(NULL);
6858
105M
    if (cur == NULL) {
6859
92.0M
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6860
0
      return(NULL);
6861
92.0M
        return((xmlNodePtr)ctxt->context->node->properties);
6862
92.0M
    }
6863
13.5M
    return((xmlNodePtr)cur->next);
6864
105M
}
6865
6866
/************************************************************************
6867
 *                  *
6868
 *    NodeTest Functions          *
6869
 *                  *
6870
 ************************************************************************/
6871
6872
#define IS_FUNCTION     200
6873
6874
6875
/************************************************************************
6876
 *                  *
6877
 *    Implicit tree core function library     *
6878
 *                  *
6879
 ************************************************************************/
6880
6881
/**
6882
 * Initialize the context to the root of the document
6883
 *
6884
 * @param ctxt  the XPath Parser context
6885
 */
6886
void
6887
12.8M
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6888
12.8M
    if ((ctxt == NULL) || (ctxt->context == NULL))
6889
0
  return;
6890
12.8M
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6891
12.8M
                                            (xmlNodePtr) ctxt->context->doc));
6892
12.8M
}
6893
6894
/************************************************************************
6895
 *                  *
6896
 *    The explicit core function library      *
6897
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6898
 *                  *
6899
 ************************************************************************/
6900
6901
6902
/**
6903
 * Implement the last() XPath function
6904
 *    number last()
6905
 * The last function returns the number of nodes in the context node list.
6906
 *
6907
 * @param ctxt  the XPath Parser context
6908
 * @param nargs  the number of arguments
6909
 */
6910
void
6911
0
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6912
0
    CHECK_ARITY(0);
6913
0
    if (ctxt->context->contextSize >= 0) {
6914
0
  xmlXPathValuePush(ctxt,
6915
0
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6916
0
    } else {
6917
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6918
0
    }
6919
0
}
6920
6921
/**
6922
 * Implement the position() XPath function
6923
 *    number position()
6924
 * The position function returns the position of the context node in the
6925
 * context node list. The first position is 1, and so the last position
6926
 * will be equal to last().
6927
 *
6928
 * @param ctxt  the XPath Parser context
6929
 * @param nargs  the number of arguments
6930
 */
6931
void
6932
0
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6933
0
    CHECK_ARITY(0);
6934
0
    if (ctxt->context->proximityPosition >= 0) {
6935
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6936
0
            (double) ctxt->context->proximityPosition));
6937
0
    } else {
6938
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6939
0
    }
6940
0
}
6941
6942
/**
6943
 * Implement the count() XPath function
6944
 *    number count(node-set)
6945
 *
6946
 * @param ctxt  the XPath Parser context
6947
 * @param nargs  the number of arguments
6948
 */
6949
void
6950
13.1k
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6951
13.1k
    xmlXPathObjectPtr cur;
6952
6953
39.5k
    CHECK_ARITY(1);
6954
39.5k
    if ((ctxt->value == NULL) ||
6955
13.1k
  ((ctxt->value->type != XPATH_NODESET) &&
6956
10
   (ctxt->value->type != XPATH_XSLT_TREE)))
6957
13.1k
  XP_ERROR(XPATH_INVALID_TYPE);
6958
13.1k
    cur = xmlXPathValuePop(ctxt);
6959
6960
13.1k
    if ((cur == NULL) || (cur->nodesetval == NULL))
6961
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6962
13.1k
    else
6963
13.1k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6964
13.1k
      (double) cur->nodesetval->nodeNr));
6965
13.1k
    xmlXPathReleaseObject(ctxt->context, cur);
6966
13.1k
}
6967
6968
/**
6969
 * Selects elements by their unique ID.
6970
 *
6971
 * @param doc  the document
6972
 * @param ids  a whitespace separated list of IDs
6973
 * @returns a node-set of selected elements.
6974
 */
6975
static xmlNodeSetPtr
6976
36.4k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6977
36.4k
    xmlNodeSetPtr ret;
6978
36.4k
    const xmlChar *cur = ids;
6979
36.4k
    xmlChar *ID;
6980
36.4k
    xmlAttrPtr attr;
6981
36.4k
    xmlNodePtr elem = NULL;
6982
6983
36.4k
    if (ids == NULL) return(NULL);
6984
6985
36.4k
    ret = xmlXPathNodeSetCreate(NULL);
6986
36.4k
    if (ret == NULL)
6987
0
        return(ret);
6988
6989
36.4k
    while (IS_BLANK_CH(*cur)) cur++;
6990
141k
    while (*cur != 0) {
6991
4.13M
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6992
4.02M
      cur++;
6993
6994
105k
        ID = xmlStrndup(ids, cur - ids);
6995
105k
  if (ID == NULL) {
6996
0
            xmlXPathFreeNodeSet(ret);
6997
0
            return(NULL);
6998
0
        }
6999
        /*
7000
         * We used to check the fact that the value passed
7001
         * was an NCName, but this generated much troubles for
7002
         * me and Aleksey Sanin, people blatantly violated that
7003
         * constraint, like Visa3D spec.
7004
         * if (xmlValidateNCName(ID, 1) == 0)
7005
         */
7006
105k
        attr = xmlGetID(doc, ID);
7007
105k
        xmlFree(ID);
7008
105k
        if (attr != NULL) {
7009
16.0k
            if (attr->type == XML_ATTRIBUTE_NODE)
7010
16.0k
                elem = attr->parent;
7011
0
            else if (attr->type == XML_ELEMENT_NODE)
7012
0
                elem = (xmlNodePtr) attr;
7013
0
            else
7014
0
                elem = NULL;
7015
16.0k
            if (elem != NULL) {
7016
16.0k
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7017
0
                    xmlXPathFreeNodeSet(ret);
7018
0
                    return(NULL);
7019
0
                }
7020
16.0k
            }
7021
16.0k
        }
7022
7023
682k
  while (IS_BLANK_CH(*cur)) cur++;
7024
105k
  ids = cur;
7025
105k
    }
7026
36.4k
    return(ret);
7027
36.4k
}
7028
7029
/**
7030
 * Implement the id() XPath function
7031
 *    node-set id(object)
7032
 * The id function selects elements by their unique ID
7033
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7034
 * then the result is the union of the result of applying id to the
7035
 * string value of each of the nodes in the argument node-set. When the
7036
 * argument to id is of any other type, the argument is converted to a
7037
 * string as if by a call to the string function; the string is split
7038
 * into a whitespace-separated list of tokens (whitespace is any sequence
7039
 * of characters matching the production S); the result is a node-set
7040
 * containing the elements in the same document as the context node that
7041
 * have a unique ID equal to any of the tokens in the list.
7042
 *
7043
 * @param ctxt  the XPath Parser context
7044
 * @param nargs  the number of arguments
7045
 */
7046
void
7047
42.2k
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7048
42.2k
    xmlChar *tokens;
7049
42.2k
    xmlNodeSetPtr ret;
7050
42.2k
    xmlXPathObjectPtr obj;
7051
7052
121k
    CHECK_ARITY(1);
7053
121k
    obj = xmlXPathValuePop(ctxt);
7054
121k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7055
39.5k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7056
11.0k
  xmlNodeSetPtr ns;
7057
11.0k
  int i;
7058
7059
11.0k
  ret = xmlXPathNodeSetCreate(NULL);
7060
11.0k
        if (ret == NULL)
7061
0
            xmlXPathPErrMemory(ctxt);
7062
7063
11.0k
  if (obj->nodesetval != NULL) {
7064
18.9k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7065
7.90k
    tokens =
7066
7.90k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7067
7.90k
                if (tokens == NULL)
7068
0
                    xmlXPathPErrMemory(ctxt);
7069
7.90k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7070
7.90k
                if (ns == NULL)
7071
0
                    xmlXPathPErrMemory(ctxt);
7072
7.90k
    ret = xmlXPathNodeSetMerge(ret, ns);
7073
7.90k
                if (ret == NULL)
7074
0
                    xmlXPathPErrMemory(ctxt);
7075
7.90k
    xmlXPathFreeNodeSet(ns);
7076
7.90k
    if (tokens != NULL)
7077
7.90k
        xmlFree(tokens);
7078
7.90k
      }
7079
11.0k
  }
7080
11.0k
  xmlXPathReleaseObject(ctxt->context, obj);
7081
11.0k
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7082
11.0k
  return;
7083
11.0k
    }
7084
28.5k
    tokens = xmlXPathCastToString(obj);
7085
28.5k
    if (tokens == NULL)
7086
0
        xmlXPathPErrMemory(ctxt);
7087
28.5k
    xmlXPathReleaseObject(ctxt->context, obj);
7088
28.5k
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7089
28.5k
    if (ret == NULL)
7090
0
        xmlXPathPErrMemory(ctxt);
7091
28.5k
    xmlFree(tokens);
7092
28.5k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7093
28.5k
}
7094
7095
/**
7096
 * Implement the local-name() XPath function
7097
 *    string local-name(node-set?)
7098
 * The local-name function returns a string containing the local part
7099
 * of the name of the node in the argument node-set that is first in
7100
 * document order. If the node-set is empty or the first node has no
7101
 * name, an empty string is returned. If the argument is omitted it
7102
 * defaults to the context node.
7103
 *
7104
 * @param ctxt  the XPath Parser context
7105
 * @param nargs  the number of arguments
7106
 */
7107
void
7108
15.3k
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7109
15.3k
    xmlXPathObjectPtr cur;
7110
7111
15.3k
    if (ctxt == NULL) return;
7112
7113
15.3k
    if (nargs == 0) {
7114
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7115
0
  nargs = 1;
7116
0
    }
7117
7118
45.9k
    CHECK_ARITY(1);
7119
45.9k
    if ((ctxt->value == NULL) ||
7120
15.3k
  ((ctxt->value->type != XPATH_NODESET) &&
7121
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7122
15.3k
  XP_ERROR(XPATH_INVALID_TYPE);
7123
15.3k
    cur = xmlXPathValuePop(ctxt);
7124
7125
15.3k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7126
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7127
15.3k
    } else {
7128
15.3k
  int i = 0; /* Should be first in document order !!!!! */
7129
15.3k
  switch (cur->nodesetval->nodeTab[i]->type) {
7130
0
  case XML_ELEMENT_NODE:
7131
0
  case XML_ATTRIBUTE_NODE:
7132
674
  case XML_PI_NODE:
7133
674
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7134
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7135
674
      else
7136
674
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7137
674
      cur->nodesetval->nodeTab[i]->name));
7138
674
      break;
7139
8.04k
  case XML_NAMESPACE_DECL:
7140
8.04k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7141
8.04k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7142
8.04k
      break;
7143
6.58k
  default:
7144
6.58k
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7145
15.3k
  }
7146
15.3k
    }
7147
15.3k
    xmlXPathReleaseObject(ctxt->context, cur);
7148
15.3k
}
7149
7150
/**
7151
 * Implement the namespace-uri() XPath function
7152
 *    string namespace-uri(node-set?)
7153
 * The namespace-uri function returns a string containing the
7154
 * namespace URI of the expanded name of the node in the argument
7155
 * node-set that is first in document order. If the node-set is empty,
7156
 * the first node has no name, or the expanded name has no namespace
7157
 * URI, an empty string is returned. If the argument is omitted it
7158
 * defaults to the context node.
7159
 *
7160
 * @param ctxt  the XPath Parser context
7161
 * @param nargs  the number of arguments
7162
 */
7163
void
7164
0
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7165
0
    xmlXPathObjectPtr cur;
7166
7167
0
    if (ctxt == NULL) return;
7168
7169
0
    if (nargs == 0) {
7170
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7171
0
  nargs = 1;
7172
0
    }
7173
0
    CHECK_ARITY(1);
7174
0
    if ((ctxt->value == NULL) ||
7175
0
  ((ctxt->value->type != XPATH_NODESET) &&
7176
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7177
0
  XP_ERROR(XPATH_INVALID_TYPE);
7178
0
    cur = xmlXPathValuePop(ctxt);
7179
7180
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7181
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7182
0
    } else {
7183
0
  int i = 0; /* Should be first in document order !!!!! */
7184
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7185
0
  case XML_ELEMENT_NODE:
7186
0
  case XML_ATTRIBUTE_NODE:
7187
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7188
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7189
0
      else
7190
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7191
0
        cur->nodesetval->nodeTab[i]->ns->href));
7192
0
      break;
7193
0
  default:
7194
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7195
0
  }
7196
0
    }
7197
0
    xmlXPathReleaseObject(ctxt->context, cur);
7198
0
}
7199
7200
/**
7201
 * Implement the name() XPath function
7202
 *    string name(node-set?)
7203
 * The name function returns a string containing a QName representing
7204
 * the name of the node in the argument node-set that is first in document
7205
 * order. The QName must represent the name with respect to the namespace
7206
 * declarations in effect on the node whose name is being represented.
7207
 * Typically, this will be the form in which the name occurred in the XML
7208
 * source. This need not be the case if there are namespace declarations
7209
 * in effect on the node that associate multiple prefixes with the same
7210
 * namespace. However, an implementation may include information about
7211
 * the original prefix in its representation of nodes; in this case, an
7212
 * implementation can ensure that the returned string is always the same
7213
 * as the QName used in the XML source. If the argument it omitted it
7214
 * defaults to the context node.
7215
 * Libxml keep the original prefix so the "real qualified name" used is
7216
 * returned.
7217
 *
7218
 * @param ctxt  the XPath Parser context
7219
 * @param nargs  the number of arguments
7220
 */
7221
static void
7222
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7223
37.9k
{
7224
37.9k
    xmlXPathObjectPtr cur;
7225
7226
37.9k
    if (nargs == 0) {
7227
35.6k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7228
35.6k
        nargs = 1;
7229
35.6k
    }
7230
7231
113k
    CHECK_ARITY(1);
7232
113k
    if ((ctxt->value == NULL) ||
7233
37.9k
        ((ctxt->value->type != XPATH_NODESET) &&
7234
7
         (ctxt->value->type != XPATH_XSLT_TREE)))
7235
37.9k
        XP_ERROR(XPATH_INVALID_TYPE);
7236
37.9k
    cur = xmlXPathValuePop(ctxt);
7237
7238
37.9k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7239
1.37k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7240
36.5k
    } else {
7241
36.5k
        int i = 0;              /* Should be first in document order !!!!! */
7242
7243
36.5k
        switch (cur->nodesetval->nodeTab[i]->type) {
7244
17.5k
            case XML_ELEMENT_NODE:
7245
21.2k
            case XML_ATTRIBUTE_NODE:
7246
21.2k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7247
0
        xmlXPathValuePush(ctxt,
7248
0
      xmlXPathCacheNewCString(ctxt, ""));
7249
21.2k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7250
20.6k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7251
20.6k
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7252
20.6k
          cur->nodesetval->nodeTab[i]->name));
7253
20.6k
    } else {
7254
540
        xmlChar *fullname;
7255
7256
540
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7257
540
             cur->nodesetval->nodeTab[i]->ns->prefix,
7258
540
             NULL, 0);
7259
540
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7260
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7261
540
        if (fullname == NULL)
7262
0
                        xmlXPathPErrMemory(ctxt);
7263
540
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7264
540
                }
7265
21.2k
                break;
7266
15.3k
            default:
7267
15.3k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7268
15.3k
        cur->nodesetval->nodeTab[i]));
7269
15.3k
                xmlXPathLocalNameFunction(ctxt, 1);
7270
36.5k
        }
7271
36.5k
    }
7272
37.9k
    xmlXPathReleaseObject(ctxt->context, cur);
7273
37.9k
}
7274
7275
7276
/**
7277
 * Implement the string() XPath function
7278
 *    string string(object?)
7279
 * The string function converts an object to a string as follows:
7280
 *    - A node-set is converted to a string by returning the value of
7281
 *      the node in the node-set that is first in document order.
7282
 *      If the node-set is empty, an empty string is returned.
7283
 *    - A number is converted to a string as follows
7284
 *      + NaN is converted to the string NaN
7285
 *      + positive zero is converted to the string 0
7286
 *      + negative zero is converted to the string 0
7287
 *      + positive infinity is converted to the string Infinity
7288
 *      + negative infinity is converted to the string -Infinity
7289
 *      + if the number is an integer, the number is represented in
7290
 *        decimal form as a Number with no decimal point and no leading
7291
 *        zeros, preceded by a minus sign (-) if the number is negative
7292
 *      + otherwise, the number is represented in decimal form as a
7293
 *        Number including a decimal point with at least one digit
7294
 *        before the decimal point and at least one digit after the
7295
 *        decimal point, preceded by a minus sign (-) if the number
7296
 *        is negative; there must be no leading zeros before the decimal
7297
 *        point apart possibly from the one required digit immediately
7298
 *        before the decimal point; beyond the one required digit
7299
 *        after the decimal point there must be as many, but only as
7300
 *        many, more digits as are needed to uniquely distinguish the
7301
 *        number from all other IEEE 754 numeric values.
7302
 *    - The boolean false value is converted to the string false.
7303
 *      The boolean true value is converted to the string true.
7304
 *
7305
 * If the argument is omitted, it defaults to a node-set with the
7306
 * context node as its only member.
7307
 *
7308
 * @param ctxt  the XPath Parser context
7309
 * @param nargs  the number of arguments
7310
 */
7311
void
7312
8.40M
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7313
8.40M
    xmlXPathObjectPtr cur;
7314
8.40M
    xmlChar *stringval;
7315
7316
8.40M
    if (ctxt == NULL) return;
7317
8.40M
    if (nargs == 0) {
7318
516
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7319
516
        if (stringval == NULL)
7320
0
            xmlXPathPErrMemory(ctxt);
7321
516
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7322
516
  return;
7323
516
    }
7324
7325
33.6M
    CHECK_ARITY(1);
7326
33.6M
    cur = xmlXPathValuePop(ctxt);
7327
33.6M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7328
8.40M
    if (cur->type != XPATH_STRING) {
7329
8.40M
        stringval = xmlXPathCastToString(cur);
7330
8.40M
        if (stringval == NULL)
7331
0
            xmlXPathPErrMemory(ctxt);
7332
8.40M
        xmlXPathReleaseObject(ctxt->context, cur);
7333
8.40M
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7334
8.40M
    }
7335
8.40M
    xmlXPathValuePush(ctxt, cur);
7336
8.40M
}
7337
7338
/**
7339
 * Implement the string-length() XPath function
7340
 *    number string-length(string?)
7341
 * The string-length returns the number of characters in the string
7342
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7343
 * the context node converted to a string, in other words the value
7344
 * of the context node.
7345
 *
7346
 * @param ctxt  the XPath Parser context
7347
 * @param nargs  the number of arguments
7348
 */
7349
void
7350
0
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7351
0
    xmlXPathObjectPtr cur;
7352
7353
0
    if (nargs == 0) {
7354
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
7355
0
      return;
7356
0
  if (ctxt->context->node == NULL) {
7357
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7358
0
  } else {
7359
0
      xmlChar *content;
7360
7361
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
7362
0
            if (content == NULL)
7363
0
                xmlXPathPErrMemory(ctxt);
7364
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7365
0
    xmlUTF8Strlen(content)));
7366
0
      xmlFree(content);
7367
0
  }
7368
0
  return;
7369
0
    }
7370
0
    CHECK_ARITY(1);
7371
0
    CAST_TO_STRING;
7372
0
    CHECK_TYPE(XPATH_STRING);
7373
0
    cur = xmlXPathValuePop(ctxt);
7374
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7375
0
  xmlUTF8Strlen(cur->stringval)));
7376
0
    xmlXPathReleaseObject(ctxt->context, cur);
7377
0
}
7378
7379
/**
7380
 * Implement the concat() XPath function
7381
 *    string concat(string, string, string*)
7382
 * The concat function returns the concatenation of its arguments.
7383
 *
7384
 * @param ctxt  the XPath Parser context
7385
 * @param nargs  the number of arguments
7386
 */
7387
void
7388
0
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7389
0
    xmlXPathObjectPtr cur, newobj;
7390
0
    xmlChar *tmp;
7391
7392
0
    if (ctxt == NULL) return;
7393
0
    if (nargs < 2) {
7394
0
  CHECK_ARITY(2);
7395
0
    }
7396
7397
0
    CAST_TO_STRING;
7398
0
    cur = xmlXPathValuePop(ctxt);
7399
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7400
0
  xmlXPathReleaseObject(ctxt->context, cur);
7401
0
  return;
7402
0
    }
7403
0
    nargs--;
7404
7405
0
    while (nargs > 0) {
7406
0
  CAST_TO_STRING;
7407
0
  newobj = xmlXPathValuePop(ctxt);
7408
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7409
0
      xmlXPathReleaseObject(ctxt->context, newobj);
7410
0
      xmlXPathReleaseObject(ctxt->context, cur);
7411
0
      XP_ERROR(XPATH_INVALID_TYPE);
7412
0
  }
7413
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7414
0
        if (tmp == NULL)
7415
0
            xmlXPathPErrMemory(ctxt);
7416
0
  newobj->stringval = cur->stringval;
7417
0
  cur->stringval = tmp;
7418
0
  xmlXPathReleaseObject(ctxt->context, newobj);
7419
0
  nargs--;
7420
0
    }
7421
0
    xmlXPathValuePush(ctxt, cur);
7422
0
}
7423
7424
/**
7425
 * Implement the contains() XPath function
7426
 *    boolean contains(string, string)
7427
 * The contains function returns true if the first argument string
7428
 * contains the second argument string, and otherwise returns false.
7429
 *
7430
 * @param ctxt  the XPath Parser context
7431
 * @param nargs  the number of arguments
7432
 */
7433
void
7434
0
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7435
0
    xmlXPathObjectPtr hay, needle;
7436
7437
0
    CHECK_ARITY(2);
7438
0
    CAST_TO_STRING;
7439
0
    CHECK_TYPE(XPATH_STRING);
7440
0
    needle = xmlXPathValuePop(ctxt);
7441
0
    CAST_TO_STRING;
7442
0
    hay = xmlXPathValuePop(ctxt);
7443
7444
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7445
0
  xmlXPathReleaseObject(ctxt->context, hay);
7446
0
  xmlXPathReleaseObject(ctxt->context, needle);
7447
0
  XP_ERROR(XPATH_INVALID_TYPE);
7448
0
    }
7449
0
    if (xmlStrstr(hay->stringval, needle->stringval))
7450
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7451
0
    else
7452
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7453
0
    xmlXPathReleaseObject(ctxt->context, hay);
7454
0
    xmlXPathReleaseObject(ctxt->context, needle);
7455
0
}
7456
7457
/**
7458
 * Implement the starts-with() XPath function
7459
 *    boolean starts-with(string, string)
7460
 * The starts-with function returns true if the first argument string
7461
 * starts with the second argument string, and otherwise returns false.
7462
 *
7463
 * @param ctxt  the XPath Parser context
7464
 * @param nargs  the number of arguments
7465
 */
7466
void
7467
1.29k
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7468
1.29k
    xmlXPathObjectPtr hay, needle;
7469
1.29k
    int n;
7470
7471
3.89k
    CHECK_ARITY(2);
7472
3.89k
    CAST_TO_STRING;
7473
3.89k
    CHECK_TYPE(XPATH_STRING);
7474
1.29k
    needle = xmlXPathValuePop(ctxt);
7475
1.29k
    CAST_TO_STRING;
7476
1.29k
    hay = xmlXPathValuePop(ctxt);
7477
7478
1.29k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7479
0
  xmlXPathReleaseObject(ctxt->context, hay);
7480
0
  xmlXPathReleaseObject(ctxt->context, needle);
7481
0
  XP_ERROR(XPATH_INVALID_TYPE);
7482
0
    }
7483
1.29k
    n = xmlStrlen(needle->stringval);
7484
1.29k
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7485
568
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7486
728
    else
7487
728
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7488
1.29k
    xmlXPathReleaseObject(ctxt->context, hay);
7489
1.29k
    xmlXPathReleaseObject(ctxt->context, needle);
7490
1.29k
}
7491
7492
/**
7493
 * Implement the substring() XPath function
7494
 *    string substring(string, number, number?)
7495
 * The substring function returns the substring of the first argument
7496
 * starting at the position specified in the second argument with
7497
 * length specified in the third argument. For example,
7498
 * substring("12345",2,3) returns "234". If the third argument is not
7499
 * specified, it returns the substring starting at the position specified
7500
 * in the second argument and continuing to the end of the string. For
7501
 * example, substring("12345",2) returns "2345".  More precisely, each
7502
 * character in the string (see [3.6 Strings]) is considered to have a
7503
 * numeric position: the position of the first character is 1, the position
7504
 * of the second character is 2 and so on. The returned substring contains
7505
 * those characters for which the position of the character is greater than
7506
 * or equal to the second argument and, if the third argument is specified,
7507
 * less than the sum of the second and third arguments; the comparisons
7508
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7509
 *  - substring("12345", 1.5, 2.6) returns "234"
7510
 *  - substring("12345", 0, 3) returns "12"
7511
 *  - substring("12345", 0 div 0, 3) returns ""
7512
 *  - substring("12345", 1, 0 div 0) returns ""
7513
 *  - substring("12345", -42, 1 div 0) returns "12345"
7514
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
7515
 *
7516
 * @param ctxt  the XPath Parser context
7517
 * @param nargs  the number of arguments
7518
 */
7519
void
7520
12.7k
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7521
12.7k
    xmlXPathObjectPtr str, start, len;
7522
12.7k
    double le=0, in;
7523
12.7k
    int i = 1, j = INT_MAX;
7524
7525
12.7k
    if (nargs < 2) {
7526
2
  CHECK_ARITY(2);
7527
2
    }
7528
12.7k
    if (nargs > 3) {
7529
2
  CHECK_ARITY(3);
7530
2
    }
7531
    /*
7532
     * take care of possible last (position) argument
7533
    */
7534
12.7k
    if (nargs == 3) {
7535
5.30k
  CAST_TO_NUMBER;
7536
5.30k
  CHECK_TYPE(XPATH_NUMBER);
7537
5.30k
  len = xmlXPathValuePop(ctxt);
7538
5.30k
  le = len->floatval;
7539
5.30k
  xmlXPathReleaseObject(ctxt->context, len);
7540
5.30k
    }
7541
7542
12.7k
    CAST_TO_NUMBER;
7543
12.7k
    CHECK_TYPE(XPATH_NUMBER);
7544
12.7k
    start = xmlXPathValuePop(ctxt);
7545
12.7k
    in = start->floatval;
7546
12.7k
    xmlXPathReleaseObject(ctxt->context, start);
7547
12.7k
    CAST_TO_STRING;
7548
12.7k
    CHECK_TYPE(XPATH_STRING);
7549
12.7k
    str = xmlXPathValuePop(ctxt);
7550
7551
12.7k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7552
1.07k
        i = INT_MAX;
7553
11.7k
    } else if (in >= 1.0) {
7554
9.18k
        i = (int)in;
7555
9.18k
        if (in - floor(in) >= 0.5)
7556
2.59k
            i += 1;
7557
9.18k
    }
7558
7559
12.7k
    if (nargs == 3) {
7560
5.30k
        double rin, rle, end;
7561
7562
5.30k
        rin = floor(in);
7563
5.30k
        if (in - rin >= 0.5)
7564
1.11k
            rin += 1.0;
7565
7566
5.30k
        rle = floor(le);
7567
5.30k
        if (le - rle >= 0.5)
7568
434
            rle += 1.0;
7569
7570
5.30k
        end = rin + rle;
7571
5.30k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7572
1.22k
            j = 1;
7573
4.07k
        } else if (end < INT_MAX) {
7574
3.59k
            j = (int)end;
7575
3.59k
        }
7576
5.30k
    }
7577
7578
12.7k
    i -= 1;
7579
12.7k
    j -= 1;
7580
7581
12.7k
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7582
7.32k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7583
7.32k
        if (ret == NULL)
7584
0
            xmlXPathPErrMemory(ctxt);
7585
7.32k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7586
7.32k
  xmlFree(ret);
7587
7.32k
    } else {
7588
5.45k
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7589
5.45k
    }
7590
7591
12.7k
    xmlXPathReleaseObject(ctxt->context, str);
7592
12.7k
}
7593
7594
/**
7595
 * Implement the substring-before() XPath function
7596
 *    string substring-before(string, string)
7597
 * The substring-before function returns the substring of the first
7598
 * argument string that precedes the first occurrence of the second
7599
 * argument string in the first argument string, or the empty string
7600
 * if the first argument string does not contain the second argument
7601
 * string. For example, substring-before("1999/04/01","/") returns 1999.
7602
 *
7603
 * @param ctxt  the XPath Parser context
7604
 * @param nargs  the number of arguments
7605
 */
7606
void
7607
10.2k
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7608
10.2k
    xmlXPathObjectPtr str = NULL;
7609
10.2k
    xmlXPathObjectPtr find = NULL;
7610
10.2k
    const xmlChar *point;
7611
10.2k
    xmlChar *result;
7612
7613
30.7k
    CHECK_ARITY(2);
7614
30.7k
    CAST_TO_STRING;
7615
30.7k
    find = xmlXPathValuePop(ctxt);
7616
30.7k
    CAST_TO_STRING;
7617
30.7k
    str = xmlXPathValuePop(ctxt);
7618
30.7k
    if (ctxt->error != 0)
7619
0
        goto error;
7620
7621
10.2k
    point = xmlStrstr(str->stringval, find->stringval);
7622
10.2k
    if (point == NULL) {
7623
8.89k
        result = xmlStrdup(BAD_CAST "");
7624
8.89k
    } else {
7625
1.34k
        result = xmlStrndup(str->stringval, point - str->stringval);
7626
1.34k
    }
7627
10.2k
    if (result == NULL) {
7628
0
        xmlXPathPErrMemory(ctxt);
7629
0
        goto error;
7630
0
    }
7631
10.2k
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7632
7633
10.2k
error:
7634
10.2k
    xmlXPathReleaseObject(ctxt->context, str);
7635
10.2k
    xmlXPathReleaseObject(ctxt->context, find);
7636
10.2k
}
7637
7638
/**
7639
 * Implement the substring-after() XPath function
7640
 *    string substring-after(string, string)
7641
 * The substring-after function returns the substring of the first
7642
 * argument string that follows the first occurrence of the second
7643
 * argument string in the first argument string, or the empty string
7644
 * if the first argument string does not contain the second argument
7645
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7646
 * and substring-after("1999/04/01","19") returns 99/04/01.
7647
 *
7648
 * @param ctxt  the XPath Parser context
7649
 * @param nargs  the number of arguments
7650
 */
7651
void
7652
918
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7653
918
    xmlXPathObjectPtr str = NULL;
7654
918
    xmlXPathObjectPtr find = NULL;
7655
918
    const xmlChar *point;
7656
918
    xmlChar *result;
7657
7658
2.74k
    CHECK_ARITY(2);
7659
2.74k
    CAST_TO_STRING;
7660
2.74k
    find = xmlXPathValuePop(ctxt);
7661
2.74k
    CAST_TO_STRING;
7662
2.74k
    str = xmlXPathValuePop(ctxt);
7663
2.74k
    if (ctxt->error != 0)
7664
0
        goto error;
7665
7666
912
    point = xmlStrstr(str->stringval, find->stringval);
7667
912
    if (point == NULL) {
7668
204
        result = xmlStrdup(BAD_CAST "");
7669
708
    } else {
7670
708
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7671
708
    }
7672
912
    if (result == NULL) {
7673
0
        xmlXPathPErrMemory(ctxt);
7674
0
        goto error;
7675
0
    }
7676
912
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7677
7678
912
error:
7679
912
    xmlXPathReleaseObject(ctxt->context, str);
7680
912
    xmlXPathReleaseObject(ctxt->context, find);
7681
912
}
7682
7683
/**
7684
 * Implement the normalize-space() XPath function
7685
 *    string normalize-space(string?)
7686
 * The normalize-space function returns the argument string with white
7687
 * space normalized by stripping leading and trailing whitespace
7688
 * and replacing sequences of whitespace characters by a single
7689
 * space. Whitespace characters are the same allowed by the S production
7690
 * in XML. If the argument is omitted, it defaults to the context
7691
 * node converted to a string, in other words the value of the context node.
7692
 *
7693
 * @param ctxt  the XPath Parser context
7694
 * @param nargs  the number of arguments
7695
 */
7696
void
7697
1.52k
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7698
1.52k
    xmlChar *source, *target;
7699
1.52k
    int blank;
7700
7701
1.52k
    if (ctxt == NULL) return;
7702
1.52k
    if (nargs == 0) {
7703
        /* Use current context node */
7704
138
        source = xmlXPathCastNodeToString(ctxt->context->node);
7705
138
        if (source == NULL)
7706
0
            xmlXPathPErrMemory(ctxt);
7707
138
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7708
138
        nargs = 1;
7709
138
    }
7710
7711
4.57k
    CHECK_ARITY(1);
7712
4.57k
    CAST_TO_STRING;
7713
4.57k
    CHECK_TYPE(XPATH_STRING);
7714
1.52k
    source = ctxt->value->stringval;
7715
1.52k
    if (source == NULL)
7716
0
        return;
7717
1.52k
    target = source;
7718
7719
    /* Skip leading whitespaces */
7720
1.52k
    while (IS_BLANK_CH(*source))
7721
3.40k
        source++;
7722
7723
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7724
1.52k
    blank = 0;
7725
22.8k
    while (*source) {
7726
21.3k
        if (IS_BLANK_CH(*source)) {
7727
8.75k
      blank = 1;
7728
12.6k
        } else {
7729
12.6k
            if (blank) {
7730
3.00k
                *target++ = 0x20;
7731
3.00k
                blank = 0;
7732
3.00k
            }
7733
12.6k
            *target++ = *source;
7734
12.6k
        }
7735
21.3k
        source++;
7736
21.3k
    }
7737
1.52k
    *target = 0;
7738
1.52k
}
7739
7740
/**
7741
 * Implement the translate() XPath function
7742
 *    string translate(string, string, string)
7743
 * The translate function returns the first argument string with
7744
 * occurrences of characters in the second argument string replaced
7745
 * by the character at the corresponding position in the third argument
7746
 * string. For example, translate("bar","abc","ABC") returns the string
7747
 * BAr. If there is a character in the second argument string with no
7748
 * character at a corresponding position in the third argument string
7749
 * (because the second argument string is longer than the third argument
7750
 * string), then occurrences of that character in the first argument
7751
 * string are removed. For example,
7752
 * translate("--aaa--","abc-","ABC") returns "AAA".
7753
 * If a character occurs more than once in second
7754
 * argument string, then the first occurrence determines the replacement
7755
 * character. If the third argument string is longer than the second
7756
 * argument string, then excess characters are ignored.
7757
 *
7758
 * @param ctxt  the XPath Parser context
7759
 * @param nargs  the number of arguments
7760
 */
7761
void
7762
884
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7763
884
    xmlXPathObjectPtr str = NULL;
7764
884
    xmlXPathObjectPtr from = NULL;
7765
884
    xmlXPathObjectPtr to = NULL;
7766
884
    xmlBufPtr target;
7767
884
    int offset, max;
7768
884
    int ch;
7769
884
    const xmlChar *point;
7770
884
    xmlChar *cptr, *content;
7771
7772
2.62k
    CHECK_ARITY(3);
7773
7774
2.62k
    CAST_TO_STRING;
7775
2.62k
    to = xmlXPathValuePop(ctxt);
7776
2.62k
    CAST_TO_STRING;
7777
2.62k
    from = xmlXPathValuePop(ctxt);
7778
2.62k
    CAST_TO_STRING;
7779
2.62k
    str = xmlXPathValuePop(ctxt);
7780
2.62k
    if (ctxt->error != 0)
7781
0
        goto error;
7782
7783
    /*
7784
     * Account for quadratic runtime
7785
     */
7786
872
    if (ctxt->context->opLimit != 0) {
7787
0
        unsigned long f1 = xmlStrlen(from->stringval);
7788
0
        unsigned long f2 = xmlStrlen(str->stringval);
7789
7790
0
        if ((f1 > 0) && (f2 > 0)) {
7791
0
            unsigned long p;
7792
7793
0
            f1 = f1 / 10 + 1;
7794
0
            f2 = f2 / 10 + 1;
7795
0
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7796
0
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7797
0
                goto error;
7798
0
        }
7799
0
    }
7800
7801
872
    target = xmlBufCreate(50);
7802
872
    if (target == NULL) {
7803
0
        xmlXPathPErrMemory(ctxt);
7804
0
        goto error;
7805
0
    }
7806
7807
872
    max = xmlUTF8Strlen(to->stringval);
7808
4.15M
    for (cptr = str->stringval; (ch=*cptr); ) {
7809
4.15M
        offset = xmlUTF8Strloc(from->stringval, cptr);
7810
4.15M
        if (offset >= 0) {
7811
4.13M
            if (offset < max) {
7812
2.75M
                point = xmlUTF8Strpos(to->stringval, offset);
7813
2.75M
                if (point)
7814
2.75M
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7815
2.75M
            }
7816
4.13M
        } else
7817
24.2k
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7818
7819
        /* Step to next character in input */
7820
4.15M
        cptr++;
7821
4.15M
        if ( ch & 0x80 ) {
7822
            /* if not simple ascii, verify proper format */
7823
1.82k
            if ( (ch & 0xc0) != 0xc0 ) {
7824
0
                xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7825
0
                break;
7826
0
            }
7827
            /* then skip over remaining bytes for this char */
7828
5.00k
            while ( (ch <<= 1) & 0x80 )
7829
3.17k
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7830
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7831
0
                    break;
7832
0
                }
7833
1.82k
            if (ch & 0x80) /* must have had error encountered */
7834
0
                break;
7835
1.82k
        }
7836
4.15M
    }
7837
7838
872
    content = xmlBufDetach(target);
7839
872
    if (content == NULL)
7840
0
        xmlXPathPErrMemory(ctxt);
7841
872
    else
7842
872
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7843
872
    xmlBufFree(target);
7844
872
error:
7845
872
    xmlXPathReleaseObject(ctxt->context, str);
7846
872
    xmlXPathReleaseObject(ctxt->context, from);
7847
872
    xmlXPathReleaseObject(ctxt->context, to);
7848
872
}
7849
7850
/**
7851
 * Implement the boolean() XPath function
7852
 *    boolean boolean(object)
7853
 * The boolean function converts its argument to a boolean as follows:
7854
 *    - a number is true if and only if it is neither positive or
7855
 *      negative zero nor NaN
7856
 *    - a node-set is true if and only if it is non-empty
7857
 *    - a string is true if and only if its length is non-zero
7858
 *
7859
 * @param ctxt  the XPath Parser context
7860
 * @param nargs  the number of arguments
7861
 */
7862
void
7863
6.50M
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7864
6.50M
    xmlXPathObjectPtr cur;
7865
7866
19.5M
    CHECK_ARITY(1);
7867
19.5M
    cur = xmlXPathValuePop(ctxt);
7868
19.5M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7869
6.50M
    if (cur->type != XPATH_BOOLEAN) {
7870
4.34M
        int boolval = xmlXPathCastToBoolean(cur);
7871
7872
4.34M
        xmlXPathReleaseObject(ctxt->context, cur);
7873
4.34M
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7874
4.34M
    }
7875
6.50M
    xmlXPathValuePush(ctxt, cur);
7876
6.50M
}
7877
7878
/**
7879
 * Implement the not() XPath function
7880
 *    boolean not(boolean)
7881
 * The not function returns true if its argument is false,
7882
 * and false otherwise.
7883
 *
7884
 * @param ctxt  the XPath Parser context
7885
 * @param nargs  the number of arguments
7886
 */
7887
void
7888
1.95k
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7889
5.84k
    CHECK_ARITY(1);
7890
5.84k
    CAST_TO_BOOLEAN;
7891
5.84k
    CHECK_TYPE(XPATH_BOOLEAN);
7892
1.94k
    ctxt->value->boolval = ! ctxt->value->boolval;
7893
1.94k
}
7894
7895
/**
7896
 * Implement the true() XPath function
7897
 *    boolean true()
7898
 *
7899
 * @param ctxt  the XPath Parser context
7900
 * @param nargs  the number of arguments
7901
 */
7902
void
7903
34
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7904
94
    CHECK_ARITY(0);
7905
94
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7906
94
}
7907
7908
/**
7909
 * Implement the false() XPath function
7910
 *    boolean false()
7911
 *
7912
 * @param ctxt  the XPath Parser context
7913
 * @param nargs  the number of arguments
7914
 */
7915
void
7916
24
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7917
68
    CHECK_ARITY(0);
7918
68
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7919
68
}
7920
7921
/**
7922
 * Implement the lang() XPath function
7923
 *    boolean lang(string)
7924
 * The lang function returns true or false depending on whether the
7925
 * language of the context node as specified by xml:lang attributes
7926
 * is the same as or is a sublanguage of the language specified by
7927
 * the argument string. The language of the context node is determined
7928
 * by the value of the xml:lang attribute on the context node, or, if
7929
 * the context node has no xml:lang attribute, by the value of the
7930
 * xml:lang attribute on the nearest ancestor of the context node that
7931
 * has an xml:lang attribute. If there is no such attribute, then
7932
 * lang returns false. If there is such an attribute, then lang returns
7933
 * true if the attribute value is equal to the argument ignoring case,
7934
 * or if there is some suffix starting with - such that the attribute
7935
 * value is equal to the argument ignoring that suffix of the attribute
7936
 * value and ignoring case.
7937
 *
7938
 * @param ctxt  the XPath Parser context
7939
 * @param nargs  the number of arguments
7940
 */
7941
void
7942
8.36M
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7943
8.36M
    xmlXPathObjectPtr val;
7944
8.36M
    xmlNodePtr cur;
7945
8.36M
    xmlChar *theLang = NULL;
7946
8.36M
    const xmlChar *lang;
7947
8.36M
    int ret = 0;
7948
8.36M
    int i;
7949
7950
25.0M
    CHECK_ARITY(1);
7951
25.0M
    CAST_TO_STRING;
7952
25.0M
    CHECK_TYPE(XPATH_STRING);
7953
8.36M
    val = xmlXPathValuePop(ctxt);
7954
8.36M
    lang = val->stringval;
7955
8.36M
    cur = ctxt->context->node;
7956
41.7M
    while (cur != NULL) {
7957
33.4M
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7958
33.4M
                                &theLang) < 0)
7959
0
            xmlXPathPErrMemory(ctxt);
7960
33.4M
        if (theLang != NULL)
7961
49.6k
            break;
7962
33.3M
        cur = cur->parent;
7963
33.3M
    }
7964
8.36M
    if ((theLang != NULL) && (lang != NULL)) {
7965
50.6k
        for (i = 0;lang[i] != 0;i++)
7966
1.40k
            if (toupper(lang[i]) != toupper(theLang[i]))
7967
394
                goto not_equal;
7968
49.2k
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7969
48.8k
            ret = 1;
7970
49.2k
    }
7971
8.36M
not_equal:
7972
8.36M
    if (theLang != NULL)
7973
49.6k
  xmlFree((void *)theLang);
7974
7975
8.36M
    xmlXPathReleaseObject(ctxt->context, val);
7976
8.36M
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7977
8.36M
}
7978
7979
/**
7980
 * Implement the number() XPath function
7981
 *    number number(object?)
7982
 *
7983
 * @param ctxt  the XPath Parser context
7984
 * @param nargs  the number of arguments
7985
 */
7986
void
7987
9.40M
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7988
9.40M
    xmlXPathObjectPtr cur;
7989
9.40M
    double res;
7990
7991
9.40M
    if (ctxt == NULL) return;
7992
9.40M
    if (nargs == 0) {
7993
0
  if (ctxt->context->node == NULL) {
7994
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7995
0
  } else {
7996
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7997
0
            if (content == NULL)
7998
0
                xmlXPathPErrMemory(ctxt);
7999
8000
0
      res = xmlXPathStringEvalNumber(content);
8001
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8002
0
      xmlFree(content);
8003
0
  }
8004
0
  return;
8005
0
    }
8006
8007
37.6M
    CHECK_ARITY(1);
8008
37.6M
    cur = xmlXPathValuePop(ctxt);
8009
37.6M
    if (cur->type != XPATH_NUMBER) {
8010
9.40M
        double floatval;
8011
8012
9.40M
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8013
9.40M
        xmlXPathReleaseObject(ctxt->context, cur);
8014
9.40M
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
8015
9.40M
    }
8016
37.6M
    xmlXPathValuePush(ctxt, cur);
8017
37.6M
}
8018
8019
/**
8020
 * Implement the sum() XPath function
8021
 *    number sum(node-set)
8022
 * The sum function returns the sum of the values of the nodes in
8023
 * the argument node-set.
8024
 *
8025
 * @param ctxt  the XPath Parser context
8026
 * @param nargs  the number of arguments
8027
 */
8028
void
8029
1.04k
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
8030
1.04k
    xmlXPathObjectPtr cur;
8031
1.04k
    int i;
8032
1.04k
    double res = 0.0;
8033
8034
3.13k
    CHECK_ARITY(1);
8035
3.13k
    if ((ctxt->value == NULL) ||
8036
1.04k
  ((ctxt->value->type != XPATH_NODESET) &&
8037
2
   (ctxt->value->type != XPATH_XSLT_TREE)))
8038
1.04k
  XP_ERROR(XPATH_INVALID_TYPE);
8039
1.04k
    cur = xmlXPathValuePop(ctxt);
8040
8041
1.04k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8042
53.5k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8043
53.0k
      res += xmlXPathNodeToNumberInternal(ctxt,
8044
53.0k
                                                cur->nodesetval->nodeTab[i]);
8045
53.0k
  }
8046
512
    }
8047
1.04k
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8048
1.04k
    xmlXPathReleaseObject(ctxt->context, cur);
8049
1.04k
}
8050
8051
/**
8052
 * Implement the floor() XPath function
8053
 *    number floor(number)
8054
 * The floor function returns the largest (closest to positive infinity)
8055
 * number that is not greater than the argument and that is an integer.
8056
 *
8057
 * @param ctxt  the XPath Parser context
8058
 * @param nargs  the number of arguments
8059
 */
8060
void
8061
154
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8062
458
    CHECK_ARITY(1);
8063
458
    CAST_TO_NUMBER;
8064
458
    CHECK_TYPE(XPATH_NUMBER);
8065
8066
152
    ctxt->value->floatval = floor(ctxt->value->floatval);
8067
152
}
8068
8069
/**
8070
 * Implement the ceiling() XPath function
8071
 *    number ceiling(number)
8072
 * The ceiling function returns the smallest (closest to negative infinity)
8073
 * number that is not less than the argument and that is an integer.
8074
 *
8075
 * @param ctxt  the XPath Parser context
8076
 * @param nargs  the number of arguments
8077
 */
8078
void
8079
0
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8080
0
    CHECK_ARITY(1);
8081
0
    CAST_TO_NUMBER;
8082
0
    CHECK_TYPE(XPATH_NUMBER);
8083
8084
#ifdef _AIX
8085
    /* Work around buggy ceil() function on AIX */
8086
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8087
#else
8088
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8089
0
#endif
8090
0
}
8091
8092
/**
8093
 * Implement the round() XPath function
8094
 *    number round(number)
8095
 * The round function returns the number that is closest to the
8096
 * argument and that is an integer. If there are two such numbers,
8097
 * then the one that is closest to positive infinity is returned.
8098
 *
8099
 * @param ctxt  the XPath Parser context
8100
 * @param nargs  the number of arguments
8101
 */
8102
void
8103
0
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8104
0
    double f;
8105
8106
0
    CHECK_ARITY(1);
8107
0
    CAST_TO_NUMBER;
8108
0
    CHECK_TYPE(XPATH_NUMBER);
8109
8110
0
    f = ctxt->value->floatval;
8111
8112
0
    if ((f >= -0.5) && (f < 0.5)) {
8113
        /* Handles negative zero. */
8114
0
        ctxt->value->floatval *= 0.0;
8115
0
    }
8116
0
    else {
8117
0
        double rounded = floor(f);
8118
0
        if (f - rounded >= 0.5)
8119
0
            rounded += 1.0;
8120
0
        ctxt->value->floatval = rounded;
8121
0
    }
8122
0
}
8123
8124
/************************************************************************
8125
 *                  *
8126
 *      The Parser          *
8127
 *                  *
8128
 ************************************************************************/
8129
8130
/*
8131
 * a few forward declarations since we use a recursive call based
8132
 * implementation.
8133
 */
8134
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8135
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8136
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8137
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8138
8139
/**
8140
 * Parse an XML non-colonized name.
8141
 *
8142
 * @param ctxt  the XPath Parser context
8143
 * @returns the nc name or NULL
8144
 */
8145
8146
xmlChar *
8147
708k
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8148
708k
    const xmlChar *end;
8149
708k
    xmlChar *ret;
8150
8151
708k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8152
8153
708k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8154
708k
    if (end == NULL) {
8155
5
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8156
0
    }
8157
708k
    if (end == ctxt->cur)
8158
55.8k
        return(NULL);
8159
8160
652k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8161
652k
    if (ret == NULL)
8162
0
        xmlXPathPErrMemory(ctxt);
8163
652k
    ctxt->cur = end;
8164
652k
    return(ret);
8165
708k
}
8166
8167
8168
/**
8169
 * Parse an XML qualified name
8170
 *
8171
 * @param ctxt  the XPath Parser context
8172
 * @param prefix  a xmlChar **
8173
 * @returns the function returns the local part, and prefix is updated
8174
 *   to get the Prefix if any.
8175
 */
8176
8177
static xmlChar *
8178
81.7k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8179
81.7k
    xmlChar *ret = NULL;
8180
8181
81.7k
    *prefix = NULL;
8182
81.7k
    ret = xmlXPathParseNCName(ctxt);
8183
81.7k
    if (ret && CUR == ':') {
8184
2.52k
        *prefix = ret;
8185
2.52k
  NEXT;
8186
2.52k
  ret = xmlXPathParseNCName(ctxt);
8187
2.52k
    }
8188
81.7k
    return(ret);
8189
81.7k
}
8190
8191
/**
8192
 * parse an XML name
8193
 *
8194
 * @param ctxt  the XPath Parser context
8195
 * @returns the name or NULL
8196
 */
8197
8198
xmlChar *
8199
68.0k
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8200
68.0k
    const xmlChar *end;
8201
68.0k
    xmlChar *ret;
8202
8203
68.0k
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8204
8205
68.0k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8206
68.0k
    if (end == NULL) {
8207
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8208
0
    }
8209
68.0k
    if (end == ctxt->cur)
8210
6.29k
        return(NULL);
8211
8212
61.7k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8213
61.7k
    if (ret == NULL)
8214
0
        xmlXPathPErrMemory(ctxt);
8215
61.7k
    ctxt->cur = end;
8216
61.7k
    return(ret);
8217
68.0k
}
8218
8219
146k
#define MAX_FRAC 20
8220
8221
/**
8222
 *  [30a]  Float  ::= Number ('e' Digits?)?
8223
 *
8224
 *  [30]   Number ::=   Digits ('.' Digits?)?
8225
 *                    | '.' Digits
8226
 *  [31]   Digits ::=   [0-9]+
8227
 *
8228
 * Compile a Number in the string
8229
 * In complement of the Number expression, this function also handles
8230
 * negative values : '-' Number.
8231
 *
8232
 * @param str  A string to scan
8233
 * @returns the double value.
8234
 */
8235
double
8236
25.3M
xmlXPathStringEvalNumber(const xmlChar *str) {
8237
25.3M
    const xmlChar *cur = str;
8238
25.3M
    double ret;
8239
25.3M
    int ok = 0;
8240
25.3M
    int isneg = 0;
8241
25.3M
    int exponent = 0;
8242
25.3M
    int is_exponent_negative = 0;
8243
25.3M
#ifdef __GNUC__
8244
25.3M
    unsigned long tmp = 0;
8245
25.3M
    double temp;
8246
25.3M
#endif
8247
25.3M
    if (cur == NULL) return(0);
8248
36.4M
    while (IS_BLANK_CH(*cur)) cur++;
8249
25.3M
    if (*cur == '-') {
8250
108k
  isneg = 1;
8251
108k
  cur++;
8252
108k
    }
8253
25.3M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8254
24.2M
        return(xmlXPathNAN);
8255
24.2M
    }
8256
8257
1.12M
#ifdef __GNUC__
8258
    /*
8259
     * tmp/temp is a workaround against a gcc compiler bug
8260
     * http://veillard.com/gcc.bug
8261
     */
8262
1.12M
    ret = 0;
8263
3.98M
    while ((*cur >= '0') && (*cur <= '9')) {
8264
2.85M
  ret = ret * 10;
8265
2.85M
  tmp = (*cur - '0');
8266
2.85M
  ok = 1;
8267
2.85M
  cur++;
8268
2.85M
  temp = (double) tmp;
8269
2.85M
  ret = ret + temp;
8270
2.85M
    }
8271
#else
8272
    ret = 0;
8273
    while ((*cur >= '0') && (*cur <= '9')) {
8274
  ret = ret * 10 + (*cur - '0');
8275
  ok = 1;
8276
  cur++;
8277
    }
8278
#endif
8279
8280
1.12M
    if (*cur == '.') {
8281
524k
  int v, frac = 0, max;
8282
524k
  double fraction = 0;
8283
8284
524k
        cur++;
8285
524k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8286
387k
      return(xmlXPathNAN);
8287
387k
  }
8288
2.67M
        while (*cur == '0') {
8289
2.53M
      frac = frac + 1;
8290
2.53M
      cur++;
8291
2.53M
        }
8292
137k
        max = frac + MAX_FRAC;
8293
365k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8294
228k
      v = (*cur - '0');
8295
228k
      fraction = fraction * 10 + v;
8296
228k
      frac = frac + 1;
8297
228k
      cur++;
8298
228k
  }
8299
137k
  fraction /= pow(10.0, frac);
8300
137k
  ret = ret + fraction;
8301
141k
  while ((*cur >= '0') && (*cur <= '9'))
8302
3.89k
      cur++;
8303
137k
    }
8304
740k
    if ((*cur == 'e') || (*cur == 'E')) {
8305
143k
      cur++;
8306
143k
      if (*cur == '-') {
8307
45.0k
  is_exponent_negative = 1;
8308
45.0k
  cur++;
8309
98.6k
      } else if (*cur == '+') {
8310
773
        cur++;
8311
773
      }
8312
225k
      while ((*cur >= '0') && (*cur <= '9')) {
8313
81.7k
        if (exponent < 1000000)
8314
75.8k
    exponent = exponent * 10 + (*cur - '0');
8315
81.7k
  cur++;
8316
81.7k
      }
8317
143k
    }
8318
4.19M
    while (IS_BLANK_CH(*cur)) cur++;
8319
740k
    if (*cur != 0) return(xmlXPathNAN);
8320
347k
    if (isneg) ret = -ret;
8321
347k
    if (is_exponent_negative) exponent = -exponent;
8322
347k
    ret *= pow(10.0, (double)exponent);
8323
347k
    return(ret);
8324
740k
}
8325
8326
/**
8327
 *  [30]   Number ::=   Digits ('.' Digits?)?
8328
 *                    | '.' Digits
8329
 *  [31]   Digits ::=   [0-9]+
8330
 *
8331
 * Compile a Number, then push it on the stack
8332
 *
8333
 * @param ctxt  the XPath Parser context
8334
 */
8335
static void
8336
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8337
251k
{
8338
251k
    double ret = 0.0;
8339
251k
    int ok = 0;
8340
251k
    int exponent = 0;
8341
251k
    int is_exponent_negative = 0;
8342
251k
    xmlXPathObjectPtr num;
8343
251k
#ifdef __GNUC__
8344
251k
    unsigned long tmp = 0;
8345
251k
    double temp;
8346
251k
#endif
8347
8348
251k
    CHECK_ERROR;
8349
251k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8350
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8351
0
    }
8352
251k
#ifdef __GNUC__
8353
    /*
8354
     * tmp/temp is a workaround against a gcc compiler bug
8355
     * http://veillard.com/gcc.bug
8356
     */
8357
251k
    ret = 0;
8358
2.20M
    while ((CUR >= '0') && (CUR <= '9')) {
8359
1.95M
  ret = ret * 10;
8360
1.95M
  tmp = (CUR - '0');
8361
1.95M
        ok = 1;
8362
1.95M
        NEXT;
8363
1.95M
  temp = (double) tmp;
8364
1.95M
  ret = ret + temp;
8365
1.95M
    }
8366
#else
8367
    ret = 0;
8368
    while ((CUR >= '0') && (CUR <= '9')) {
8369
  ret = ret * 10 + (CUR - '0');
8370
  ok = 1;
8371
  NEXT;
8372
    }
8373
#endif
8374
251k
    if (CUR == '.') {
8375
8.92k
  int v, frac = 0, max;
8376
8.92k
  double fraction = 0;
8377
8378
8.92k
        NEXT;
8379
8.92k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8380
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8381
0
        }
8382
158k
        while (CUR == '0') {
8383
149k
            frac = frac + 1;
8384
149k
            NEXT;
8385
149k
        }
8386
8.92k
        max = frac + MAX_FRAC;
8387
41.1k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8388
32.2k
      v = (CUR - '0');
8389
32.2k
      fraction = fraction * 10 + v;
8390
32.2k
      frac = frac + 1;
8391
32.2k
            NEXT;
8392
32.2k
        }
8393
8.92k
        fraction /= pow(10.0, frac);
8394
8.92k
        ret = ret + fraction;
8395
22.3k
        while ((CUR >= '0') && (CUR <= '9'))
8396
13.4k
            NEXT;
8397
8.92k
    }
8398
251k
    if ((CUR == 'e') || (CUR == 'E')) {
8399
9.74k
        NEXT;
8400
9.74k
        if (CUR == '-') {
8401
571
            is_exponent_negative = 1;
8402
571
            NEXT;
8403
9.16k
        } else if (CUR == '+') {
8404
501
      NEXT;
8405
501
  }
8406
97.9k
        while ((CUR >= '0') && (CUR <= '9')) {
8407
88.1k
            if (exponent < 1000000)
8408
61.7k
                exponent = exponent * 10 + (CUR - '0');
8409
88.1k
            NEXT;
8410
88.1k
        }
8411
9.74k
        if (is_exponent_negative)
8412
571
            exponent = -exponent;
8413
9.74k
        ret *= pow(10.0, (double) exponent);
8414
9.74k
    }
8415
251k
    num = xmlXPathCacheNewFloat(ctxt, ret);
8416
251k
    if (num == NULL) {
8417
0
  ctxt->error = XPATH_MEMORY_ERROR;
8418
251k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8419
251k
                              NULL) == -1) {
8420
2
        xmlXPathReleaseObject(ctxt->context, num);
8421
2
    }
8422
251k
}
8423
8424
/**
8425
 * Parse a Literal
8426
 *
8427
 *  [29]   Literal ::=   '"' [^"]* '"'
8428
 *                    | "'" [^']* "'"
8429
 *
8430
 * @param ctxt  the XPath Parser context
8431
 * @returns the value found or NULL in case of error
8432
 */
8433
static xmlChar *
8434
107k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8435
107k
    const xmlChar *q;
8436
107k
    xmlChar *ret = NULL;
8437
107k
    int quote;
8438
8439
107k
    if (CUR == '"') {
8440
60.5k
        quote = '"';
8441
60.5k
    } else if (CUR == '\'') {
8442
46.8k
        quote = '\'';
8443
46.8k
    } else {
8444
11
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8445
0
    }
8446
8447
107k
    NEXT;
8448
107k
    q = CUR_PTR;
8449
7.77M
    while (CUR != quote) {
8450
7.66M
        int ch;
8451
7.66M
        int len = 4;
8452
8453
7.66M
        if (CUR == 0)
8454
7.66M
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8455
7.66M
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8456
7.66M
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8457
7.66M
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8458
7.66M
        CUR_PTR += len;
8459
7.66M
    }
8460
106k
    ret = xmlStrndup(q, CUR_PTR - q);
8461
106k
    if (ret == NULL)
8462
0
        xmlXPathPErrMemory(ctxt);
8463
106k
    NEXT;
8464
106k
    return(ret);
8465
107k
}
8466
8467
/**
8468
 * Parse a Literal and push it on the stack.
8469
 *
8470
 *  [29]   Literal ::=   '"' [^"]* '"'
8471
 *                    | "'" [^']* "'"
8472
 *
8473
 * TODO: Memory allocation could be improved.
8474
 *
8475
 * @param ctxt  the XPath Parser context
8476
 */
8477
static void
8478
107k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8479
107k
    xmlChar *ret = NULL;
8480
107k
    xmlXPathObjectPtr lit;
8481
8482
107k
    ret = xmlXPathParseLiteral(ctxt);
8483
107k
    if (ret == NULL)
8484
521
        return;
8485
106k
    lit = xmlXPathCacheNewString(ctxt, ret);
8486
106k
    if (lit == NULL) {
8487
0
        ctxt->error = XPATH_MEMORY_ERROR;
8488
106k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8489
106k
                              NULL) == -1) {
8490
2
        xmlXPathReleaseObject(ctxt->context, lit);
8491
2
    }
8492
106k
    xmlFree(ret);
8493
106k
}
8494
8495
/**
8496
 * Parse a VariableReference, evaluate it and push it on the stack.
8497
 *
8498
 * The variable bindings consist of a mapping from variable names
8499
 * to variable values. The value of a variable is an object, which can be
8500
 * of any of the types that are possible for the value of an expression,
8501
 * and may also be of additional types not specified here.
8502
 *
8503
 * Early evaluation is possible since:
8504
 * The variable bindings [...] used to evaluate a subexpression are
8505
 * always the same as those used to evaluate the containing expression.
8506
 *
8507
 *  [36]   VariableReference ::=   '$' QName
8508
 * @param ctxt  the XPath Parser context
8509
 */
8510
static void
8511
4.12k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8512
4.12k
    xmlChar *name;
8513
4.12k
    xmlChar *prefix;
8514
8515
4.12k
    SKIP_BLANKS;
8516
4.12k
    if (CUR != '$') {
8517
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8518
0
    }
8519
4.12k
    NEXT;
8520
4.12k
    name = xmlXPathParseQName(ctxt, &prefix);
8521
4.12k
    if (name == NULL) {
8522
435
        xmlFree(prefix);
8523
435
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8524
0
    }
8525
3.68k
    ctxt->comp->last = -1;
8526
3.68k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8527
0
        xmlFree(prefix);
8528
0
        xmlFree(name);
8529
0
    }
8530
3.68k
    SKIP_BLANKS;
8531
3.68k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8532
267
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8533
0
    }
8534
3.68k
}
8535
8536
/**
8537
 * Is the name given a NodeType one.
8538
 *
8539
 *  [38]   NodeType ::=   'comment'
8540
 *                    | 'text'
8541
 *                    | 'processing-instruction'
8542
 *                    | 'node'
8543
 *
8544
 * @param name  a name string
8545
 * @returns 1 if true 0 otherwise
8546
 */
8547
int
8548
89.8k
xmlXPathIsNodeType(const xmlChar *name) {
8549
89.8k
    if (name == NULL)
8550
0
  return(0);
8551
8552
89.8k
    if (xmlStrEqual(name, BAD_CAST "node"))
8553
1.37k
  return(1);
8554
88.4k
    if (xmlStrEqual(name, BAD_CAST "text"))
8555
3.33k
  return(1);
8556
85.1k
    if (xmlStrEqual(name, BAD_CAST "comment"))
8557
2.31k
  return(1);
8558
82.7k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8559
321
  return(1);
8560
82.4k
    return(0);
8561
82.7k
}
8562
8563
/**
8564
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
8565
 *  [17]   Argument ::=   Expr
8566
 *
8567
 * Compile a function call, the evaluation of all arguments are
8568
 * pushed on the stack
8569
 *
8570
 * @param ctxt  the XPath Parser context
8571
 */
8572
static void
8573
77.6k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8574
77.6k
    xmlChar *name;
8575
77.6k
    xmlChar *prefix;
8576
77.6k
    int nbargs = 0;
8577
77.6k
    int sort = 1;
8578
8579
77.6k
    name = xmlXPathParseQName(ctxt, &prefix);
8580
77.6k
    if (name == NULL) {
8581
247
  xmlFree(prefix);
8582
247
  XP_ERROR(XPATH_EXPR_ERROR);
8583
0
    }
8584
77.4k
    SKIP_BLANKS;
8585
8586
77.4k
    if (CUR != '(') {
8587
45
  xmlFree(name);
8588
45
  xmlFree(prefix);
8589
45
  XP_ERROR(XPATH_EXPR_ERROR);
8590
0
    }
8591
77.3k
    NEXT;
8592
77.3k
    SKIP_BLANKS;
8593
8594
    /*
8595
    * Optimization for count(): we don't need the node-set to be sorted.
8596
    */
8597
77.3k
    if ((prefix == NULL) && (name[0] == 'c') &&
8598
3.53k
  xmlStrEqual(name, BAD_CAST "count"))
8599
2.10k
    {
8600
2.10k
  sort = 0;
8601
2.10k
    }
8602
77.3k
    ctxt->comp->last = -1;
8603
77.3k
    if (CUR != ')') {
8604
134k
  while (CUR != 0) {
8605
134k
      int op1 = ctxt->comp->last;
8606
134k
      ctxt->comp->last = -1;
8607
134k
      xmlXPathCompileExpr(ctxt, sort);
8608
134k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8609
5.42k
    xmlFree(name);
8610
5.42k
    xmlFree(prefix);
8611
5.42k
    return;
8612
5.42k
      }
8613
128k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8614
128k
      nbargs++;
8615
128k
      if (CUR == ')') break;
8616
86.8k
      if (CUR != ',') {
8617
5.13k
    xmlFree(name);
8618
5.13k
    xmlFree(prefix);
8619
5.13k
    XP_ERROR(XPATH_EXPR_ERROR);
8620
0
      }
8621
81.7k
      NEXT;
8622
81.7k
      SKIP_BLANKS;
8623
81.7k
  }
8624
53.0k
    }
8625
66.7k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8626
4
        xmlFree(prefix);
8627
4
        xmlFree(name);
8628
4
    }
8629
66.7k
    NEXT;
8630
66.7k
    SKIP_BLANKS;
8631
66.7k
}
8632
8633
/**
8634
 *  [15]   PrimaryExpr ::=   VariableReference
8635
 *                | '(' Expr ')'
8636
 *                | Literal
8637
 *                | Number
8638
 *                | FunctionCall
8639
 *
8640
 * Compile a primary expression.
8641
 *
8642
 * @param ctxt  the XPath Parser context
8643
 */
8644
static void
8645
464k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8646
464k
    SKIP_BLANKS;
8647
464k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8648
460k
    else if (CUR == '(') {
8649
23.7k
  NEXT;
8650
23.7k
  SKIP_BLANKS;
8651
23.7k
  xmlXPathCompileExpr(ctxt, 1);
8652
23.7k
  CHECK_ERROR;
8653
20.2k
  if (CUR != ')') {
8654
896
      XP_ERROR(XPATH_EXPR_ERROR);
8655
0
  }
8656
19.3k
  NEXT;
8657
19.3k
  SKIP_BLANKS;
8658
436k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8659
251k
  xmlXPathCompNumber(ctxt);
8660
251k
    } else if ((CUR == '\'') || (CUR == '"')) {
8661
107k
  xmlXPathCompLiteral(ctxt);
8662
107k
    } else {
8663
77.6k
  xmlXPathCompFunctionCall(ctxt);
8664
77.6k
    }
8665
460k
    SKIP_BLANKS;
8666
460k
}
8667
8668
/**
8669
 *  [20]   FilterExpr ::=   PrimaryExpr
8670
 *               | FilterExpr Predicate
8671
 *
8672
 * Compile a filter expression.
8673
 * Square brackets are used to filter expressions in the same way that
8674
 * they are used in location paths. It is an error if the expression to
8675
 * be filtered does not evaluate to a node-set. The context node list
8676
 * used for evaluating the expression in square brackets is the node-set
8677
 * to be filtered listed in document order.
8678
 *
8679
 * @param ctxt  the XPath Parser context
8680
 */
8681
8682
static void
8683
464k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8684
464k
    xmlXPathCompPrimaryExpr(ctxt);
8685
464k
    CHECK_ERROR;
8686
447k
    SKIP_BLANKS;
8687
8688
494k
    while (CUR == '[') {
8689
46.7k
  xmlXPathCompPredicate(ctxt, 1);
8690
46.7k
  SKIP_BLANKS;
8691
46.7k
    }
8692
8693
8694
447k
}
8695
8696
/**
8697
 * Trickery: parse an XML name but without consuming the input flow
8698
 * Needed to avoid insanity in the parser state.
8699
 *
8700
 * @param ctxt  the XPath Parser context
8701
 * @returns the Name parsed or NULL
8702
 */
8703
8704
static xmlChar *
8705
472k
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8706
472k
    const xmlChar *end;
8707
472k
    xmlChar *ret;
8708
8709
472k
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8710
472k
    if (end == NULL) {
8711
5
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8712
0
    }
8713
472k
    if (end == ctxt->cur)
8714
11.7k
        return(NULL);
8715
8716
460k
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8717
460k
    if (ret == NULL)
8718
0
        xmlXPathPErrMemory(ctxt);
8719
460k
    return(ret);
8720
472k
}
8721
8722
/**
8723
 *  [19]   PathExpr ::=   LocationPath
8724
 *               | FilterExpr
8725
 *               | FilterExpr '/' RelativeLocationPath
8726
 *               | FilterExpr '//' RelativeLocationPath
8727
 *
8728
 * Compile a path expression.
8729
 *
8730
 * @param ctxt  the XPath Parser context
8731
 */
8732
8733
static void
8734
26.9M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8735
26.9M
    int lc = 1;           /* Should we branch to LocationPath ?         */
8736
26.9M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8737
8738
26.9M
    SKIP_BLANKS;
8739
26.9M
    if ((CUR == '$') || (CUR == '(') ||
8740
26.8M
  (IS_ASCII_DIGIT(CUR)) ||
8741
26.6M
        (CUR == '\'') || (CUR == '"') ||
8742
26.5M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8743
386k
  lc = 0;
8744
26.5M
    } else if (CUR == '*') {
8745
  /* relative or absolute location path */
8746
25.7M
  lc = 1;
8747
25.7M
    } else if (CUR == '/') {
8748
  /* relative or absolute location path */
8749
274k
  lc = 1;
8750
506k
    } else if (CUR == '@') {
8751
  /* relative abbreviated attribute location path */
8752
12.5k
  lc = 1;
8753
493k
    } else if (CUR == '.') {
8754
  /* relative abbreviated attribute location path */
8755
21.2k
  lc = 1;
8756
472k
    } else {
8757
  /*
8758
   * Problem is finding if we have a name here whether it's:
8759
   *   - a nodetype
8760
   *   - a function call in which case it's followed by '('
8761
   *   - an axis in which case it's followed by ':'
8762
   *   - a element name
8763
   * We do an a priori analysis here rather than having to
8764
   * maintain parsed token content through the recursive function
8765
   * calls. This looks uglier but makes the code easier to
8766
   * read/write/debug.
8767
   */
8768
472k
  SKIP_BLANKS;
8769
472k
  name = xmlXPathScanName(ctxt);
8770
472k
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8771
10.7k
      lc = 1;
8772
10.7k
      xmlFree(name);
8773
461k
  } else if (name != NULL) {
8774
449k
      int len =xmlStrlen(name);
8775
8776
8777
2.57M
      while (NXT(len) != 0) {
8778
2.56M
    if (NXT(len) == '/') {
8779
        /* element name */
8780
15.9k
        lc = 1;
8781
15.9k
        break;
8782
2.54M
    } else if (IS_BLANK_CH(NXT(len))) {
8783
        /* ignore blanks */
8784
2.12M
        ;
8785
2.12M
    } else if (NXT(len) == ':') {
8786
1.32k
        lc = 1;
8787
1.32k
        break;
8788
420k
    } else if ((NXT(len) == '(')) {
8789
        /* Node Type or Function */
8790
81.8k
        if (xmlXPathIsNodeType(name)) {
8791
4.17k
      lc = 1;
8792
77.6k
        } else {
8793
77.6k
      lc = 0;
8794
77.6k
        }
8795
81.8k
                    break;
8796
338k
    } else if ((NXT(len) == '[')) {
8797
        /* element name */
8798
5.29k
        lc = 1;
8799
5.29k
        break;
8800
332k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8801
277k
         (NXT(len) == '=')) {
8802
153k
        lc = 1;
8803
153k
        break;
8804
179k
    } else {
8805
179k
        lc = 1;
8806
179k
        break;
8807
179k
    }
8808
2.12M
    len++;
8809
2.12M
      }
8810
449k
      if (NXT(len) == 0) {
8811
    /* element name */
8812
12.6k
    lc = 1;
8813
12.6k
      }
8814
449k
      xmlFree(name);
8815
449k
  } else {
8816
      /* make sure all cases are covered explicitly */
8817
11.8k
      XP_ERROR(XPATH_EXPR_ERROR);
8818
0
  }
8819
472k
    }
8820
8821
26.9M
    if (lc) {
8822
26.4M
  if (CUR == '/') {
8823
274k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8824
26.1M
  } else {
8825
26.1M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8826
26.1M
  }
8827
26.4M
  xmlXPathCompLocationPath(ctxt);
8828
26.4M
    } else {
8829
464k
  xmlXPathCompFilterExpr(ctxt);
8830
464k
  CHECK_ERROR;
8831
444k
  if ((CUR == '/') && (NXT(1) == '/')) {
8832
1.93k
      SKIP(2);
8833
1.93k
      SKIP_BLANKS;
8834
8835
1.93k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8836
1.93k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8837
8838
1.93k
      xmlXPathCompRelativeLocationPath(ctxt);
8839
442k
  } else if (CUR == '/') {
8840
4.17k
      xmlXPathCompRelativeLocationPath(ctxt);
8841
4.17k
  }
8842
444k
    }
8843
26.8M
    SKIP_BLANKS;
8844
26.8M
}
8845
8846
/**
8847
 *  [18]   UnionExpr ::=   PathExpr
8848
 *               | UnionExpr '|' PathExpr
8849
 *
8850
 * Compile an union expression.
8851
 *
8852
 * @param ctxt  the XPath Parser context
8853
 */
8854
8855
static void
8856
26.8M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8857
26.8M
    xmlXPathCompPathExpr(ctxt);
8858
26.8M
    CHECK_ERROR;
8859
26.8M
    SKIP_BLANKS;
8860
26.8M
    while (CUR == '|') {
8861
67.3k
  int op1 = ctxt->comp->last;
8862
67.3k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8863
8864
67.3k
  NEXT;
8865
67.3k
  SKIP_BLANKS;
8866
67.3k
  xmlXPathCompPathExpr(ctxt);
8867
8868
67.3k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8869
8870
67.3k
  SKIP_BLANKS;
8871
67.3k
    }
8872
26.8M
}
8873
8874
/**
8875
 *  [27]   UnaryExpr ::=   UnionExpr
8876
 *                   | '-' UnaryExpr
8877
 *
8878
 * Compile an unary expression.
8879
 *
8880
 * @param ctxt  the XPath Parser context
8881
 */
8882
8883
static void
8884
26.8M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8885
26.8M
    int minus = 0;
8886
26.8M
    int found = 0;
8887
8888
26.8M
    SKIP_BLANKS;
8889
29.1M
    while (CUR == '-') {
8890
2.27M
        minus = 1 - minus;
8891
2.27M
  found = 1;
8892
2.27M
  NEXT;
8893
2.27M
  SKIP_BLANKS;
8894
2.27M
    }
8895
8896
26.8M
    xmlXPathCompUnionExpr(ctxt);
8897
26.8M
    CHECK_ERROR;
8898
26.8M
    if (found) {
8899
329k
  if (minus)
8900
244k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8901
85.6k
  else
8902
85.6k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8903
329k
    }
8904
26.8M
}
8905
8906
/**
8907
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
8908
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
8909
 *                   | MultiplicativeExpr 'div' UnaryExpr
8910
 *                   | MultiplicativeExpr 'mod' UnaryExpr
8911
 *  [34]   MultiplyOperator ::=   '*'
8912
 *
8913
 * Compile an Additive expression.
8914
 *
8915
 * @param ctxt  the XPath Parser context
8916
 */
8917
8918
static void
8919
1.05M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8920
1.05M
    xmlXPathCompUnaryExpr(ctxt);
8921
1.05M
    CHECK_ERROR;
8922
1.01M
    SKIP_BLANKS;
8923
26.8M
    while ((CUR == '*') ||
8924
1.01M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8925
25.8M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8926
25.8M
  int op = -1;
8927
25.8M
  int op1 = ctxt->comp->last;
8928
8929
25.8M
        if (CUR == '*') {
8930
25.7M
      op = 0;
8931
25.7M
      NEXT;
8932
25.7M
  } else if (CUR == 'd') {
8933
1.76k
      op = 1;
8934
1.76k
      SKIP(3);
8935
1.76k
  } else if (CUR == 'm') {
8936
1.37k
      op = 2;
8937
1.37k
      SKIP(3);
8938
1.37k
  }
8939
25.8M
  SKIP_BLANKS;
8940
25.8M
        xmlXPathCompUnaryExpr(ctxt);
8941
25.8M
  CHECK_ERROR;
8942
25.7M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8943
25.7M
  SKIP_BLANKS;
8944
25.7M
    }
8945
1.01M
}
8946
8947
/**
8948
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
8949
 *                   | AdditiveExpr '+' MultiplicativeExpr
8950
 *                   | AdditiveExpr '-' MultiplicativeExpr
8951
 *
8952
 * Compile an Additive expression.
8953
 *
8954
 * @param ctxt  the XPath Parser context
8955
 */
8956
8957
static void
8958
694k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8959
8960
694k
    xmlXPathCompMultiplicativeExpr(ctxt);
8961
694k
    CHECK_ERROR;
8962
658k
    SKIP_BLANKS;
8963
1.01M
    while ((CUR == '+') || (CUR == '-')) {
8964
357k
  int plus;
8965
357k
  int op1 = ctxt->comp->last;
8966
8967
357k
        if (CUR == '+') plus = 1;
8968
281k
  else plus = 0;
8969
357k
  NEXT;
8970
357k
  SKIP_BLANKS;
8971
357k
        xmlXPathCompMultiplicativeExpr(ctxt);
8972
357k
  CHECK_ERROR;
8973
355k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8974
355k
  SKIP_BLANKS;
8975
355k
    }
8976
658k
}
8977
8978
/**
8979
 *  [24]   RelationalExpr ::=   AdditiveExpr
8980
 *                 | RelationalExpr '<' AdditiveExpr
8981
 *                 | RelationalExpr '>' AdditiveExpr
8982
 *                 | RelationalExpr '<=' AdditiveExpr
8983
 *                 | RelationalExpr '>=' AdditiveExpr
8984
 *
8985
 *  A <= B > C is allowed ? Answer from James, yes with
8986
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8987
 *  which is basically what got implemented.
8988
 *
8989
 * Compile a Relational expression, then push the result
8990
 * on the stack
8991
 *
8992
 * @param ctxt  the XPath Parser context
8993
 */
8994
8995
static void
8996
570k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8997
570k
    xmlXPathCompAdditiveExpr(ctxt);
8998
570k
    CHECK_ERROR;
8999
535k
    SKIP_BLANKS;
9000
656k
    while ((CUR == '<') || (CUR == '>')) {
9001
123k
  int inf, strict;
9002
123k
  int op1 = ctxt->comp->last;
9003
9004
123k
        if (CUR == '<') inf = 1;
9005
110k
  else inf = 0;
9006
123k
  if (NXT(1) == '=') strict = 0;
9007
119k
  else strict = 1;
9008
123k
  NEXT;
9009
123k
  if (!strict) NEXT;
9010
123k
  SKIP_BLANKS;
9011
123k
        xmlXPathCompAdditiveExpr(ctxt);
9012
123k
  CHECK_ERROR;
9013
120k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9014
120k
  SKIP_BLANKS;
9015
120k
    }
9016
535k
}
9017
9018
/**
9019
 *  [23]   EqualityExpr ::=   RelationalExpr
9020
 *                 | EqualityExpr '=' RelationalExpr
9021
 *                 | EqualityExpr '!=' RelationalExpr
9022
 *
9023
 *  A != B != C is allowed ? Answer from James, yes with
9024
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
9025
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
9026
 *  which is basically what got implemented.
9027
 *
9028
 * Compile an Equality expression.
9029
 *
9030
 * @param ctxt  the XPath Parser context
9031
 */
9032
static void
9033
370k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9034
370k
    xmlXPathCompRelationalExpr(ctxt);
9035
370k
    CHECK_ERROR;
9036
336k
    SKIP_BLANKS;
9037
533k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9038
200k
  int eq;
9039
200k
  int op1 = ctxt->comp->last;
9040
9041
200k
        if (CUR == '=') eq = 1;
9042
5.48k
  else eq = 0;
9043
200k
  NEXT;
9044
200k
  if (!eq) NEXT;
9045
200k
  SKIP_BLANKS;
9046
200k
        xmlXPathCompRelationalExpr(ctxt);
9047
200k
  CHECK_ERROR;
9048
197k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9049
197k
  SKIP_BLANKS;
9050
197k
    }
9051
336k
}
9052
9053
/**
9054
 *  [22]   AndExpr ::=   EqualityExpr
9055
 *                 | AndExpr 'and' EqualityExpr
9056
 *
9057
 * Compile an AND expression.
9058
 *
9059
 * @param ctxt  the XPath Parser context
9060
 */
9061
static void
9062
365k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9063
365k
    xmlXPathCompEqualityExpr(ctxt);
9064
365k
    CHECK_ERROR;
9065
328k
    SKIP_BLANKS;
9066
332k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9067
4.49k
  int op1 = ctxt->comp->last;
9068
4.49k
        SKIP(3);
9069
4.49k
  SKIP_BLANKS;
9070
4.49k
        xmlXPathCompEqualityExpr(ctxt);
9071
4.49k
  CHECK_ERROR;
9072
4.18k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9073
4.18k
  SKIP_BLANKS;
9074
4.18k
    }
9075
328k
}
9076
9077
/**
9078
 *  [14]   Expr ::=   OrExpr
9079
 *  [21]   OrExpr ::=   AndExpr
9080
 *                 | OrExpr 'or' AndExpr
9081
 *
9082
 * Parse and compile an expression
9083
 *
9084
 * @param ctxt  the XPath Parser context
9085
 * @param sort  whether to sort the resulting node set
9086
 */
9087
static void
9088
333k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9089
333k
    xmlXPathContextPtr xpctxt = ctxt->context;
9090
9091
333k
    if (xpctxt != NULL) {
9092
333k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9093
331k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9094
        /*
9095
         * Parsing a single '(' pushes about 10 functions on the call stack
9096
         * before recursing!
9097
         */
9098
331k
        xpctxt->depth += 10;
9099
331k
    }
9100
9101
331k
    xmlXPathCompAndExpr(ctxt);
9102
331k
    CHECK_ERROR;
9103
295k
    SKIP_BLANKS;
9104
328k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9105
34.2k
  int op1 = ctxt->comp->last;
9106
34.2k
        SKIP(2);
9107
34.2k
  SKIP_BLANKS;
9108
34.2k
        xmlXPathCompAndExpr(ctxt);
9109
34.2k
  CHECK_ERROR;
9110
32.7k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9111
32.7k
  SKIP_BLANKS;
9112
32.7k
    }
9113
294k
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9114
  /* more ops could be optimized too */
9115
  /*
9116
  * This is the main place to eliminate sorting for
9117
  * operations which don't require a sorted node-set.
9118
  * E.g. count().
9119
  */
9120
225k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9121
225k
    }
9122
9123
294k
    if (xpctxt != NULL)
9124
294k
        xpctxt->depth -= 10;
9125
294k
}
9126
9127
/**
9128
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
9129
 *  [9]   PredicateExpr ::=   Expr
9130
 *
9131
 * Compile a predicate expression
9132
 *
9133
 * @param ctxt  the XPath Parser context
9134
 * @param filter  act as a filter
9135
 */
9136
static void
9137
83.2k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9138
83.2k
    int op1 = ctxt->comp->last;
9139
9140
83.2k
    SKIP_BLANKS;
9141
83.2k
    if (CUR != '[') {
9142
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9143
0
    }
9144
83.2k
    NEXT;
9145
83.2k
    SKIP_BLANKS;
9146
9147
83.2k
    ctxt->comp->last = -1;
9148
    /*
9149
    * This call to xmlXPathCompileExpr() will deactivate sorting
9150
    * of the predicate result.
9151
    * TODO: Sorting is still activated for filters, since I'm not
9152
    *  sure if needed. Normally sorting should not be needed, since
9153
    *  a filter can only diminish the number of items in a sequence,
9154
    *  but won't change its order; so if the initial sequence is sorted,
9155
    *  subsequent sorting is not needed.
9156
    */
9157
83.2k
    if (! filter)
9158
36.4k
  xmlXPathCompileExpr(ctxt, 0);
9159
46.7k
    else
9160
46.7k
  xmlXPathCompileExpr(ctxt, 1);
9161
83.2k
    CHECK_ERROR;
9162
9163
71.1k
    if (CUR != ']') {
9164
653
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9165
0
    }
9166
9167
70.4k
    if (filter)
9168
40.1k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9169
30.3k
    else
9170
30.3k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9171
9172
70.4k
    NEXT;
9173
70.4k
    SKIP_BLANKS;
9174
70.4k
}
9175
9176
/**
9177
 * ```
9178
 * [7] NodeTest ::=   NameTest
9179
 *        | NodeType '(' ')'
9180
 *        | 'processing-instruction' '(' Literal ')'
9181
 *
9182
 * [37] NameTest ::=  '*'
9183
 *        | NCName ':' '*'
9184
 *        | QName
9185
 * [38] NodeType ::= 'comment'
9186
 *       | 'text'
9187
 *       | 'processing-instruction'
9188
 *       | 'node'
9189
 * ```
9190
 *
9191
 * @param ctxt  the XPath Parser context
9192
 * @param test  pointer to a xmlXPathTestVal
9193
 * @param type  pointer to a xmlXPathTypeVal
9194
 * @param prefix  placeholder for a possible name prefix
9195
 * @param name  current name token (optional)
9196
 * @returns the name found and updates `test`, `type` and `prefix` appropriately
9197
 */
9198
static xmlChar *
9199
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9200
               xmlXPathTypeVal *type, xmlChar **prefix,
9201
26.3M
         xmlChar *name) {
9202
26.3M
    int blanks;
9203
9204
26.3M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9205
0
  return(NULL);
9206
0
    }
9207
26.3M
    *type = (xmlXPathTypeVal) 0;
9208
26.3M
    *test = (xmlXPathTestVal) 0;
9209
26.3M
    *prefix = NULL;
9210
26.3M
    SKIP_BLANKS;
9211
9212
26.3M
    if ((name == NULL) && (CUR == '*')) {
9213
  /*
9214
   * All elements
9215
   */
9216
25.8M
  NEXT;
9217
25.8M
  *test = NODE_TEST_ALL;
9218
25.8M
  return(NULL);
9219
25.8M
    }
9220
9221
513k
    if (name == NULL)
9222
27.6k
  name = xmlXPathParseNCName(ctxt);
9223
513k
    if (name == NULL) {
9224
3.53k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9225
0
    }
9226
9227
509k
    blanks = IS_BLANK_CH(CUR);
9228
509k
    SKIP_BLANKS;
9229
509k
    if (CUR == '(') {
9230
9.76k
  NEXT;
9231
  /*
9232
   * NodeType or PI search
9233
   */
9234
9.76k
  if (xmlStrEqual(name, BAD_CAST "comment"))
9235
110
      *type = NODE_TYPE_COMMENT;
9236
9.65k
  else if (xmlStrEqual(name, BAD_CAST "node"))
9237
2.65k
      *type = NODE_TYPE_NODE;
9238
7.00k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9239
423
      *type = NODE_TYPE_PI;
9240
6.57k
  else if (xmlStrEqual(name, BAD_CAST "text"))
9241
6.40k
      *type = NODE_TYPE_TEXT;
9242
171
  else {
9243
171
      if (name != NULL)
9244
171
    xmlFree(name);
9245
171
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9246
0
  }
9247
9248
9.59k
  *test = NODE_TEST_TYPE;
9249
9250
9.59k
  SKIP_BLANKS;
9251
9.59k
  if (*type == NODE_TYPE_PI) {
9252
      /*
9253
       * Specific case: search a PI by name.
9254
       */
9255
423
      if (name != NULL)
9256
423
    xmlFree(name);
9257
423
      name = NULL;
9258
423
      if (CUR != ')') {
9259
315
    name = xmlXPathParseLiteral(ctxt);
9260
315
    *test = NODE_TEST_PI;
9261
315
    SKIP_BLANKS;
9262
315
      }
9263
423
  }
9264
9.59k
  if (CUR != ')') {
9265
187
      if (name != NULL)
9266
171
    xmlFree(name);
9267
187
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9268
0
  }
9269
9.40k
  NEXT;
9270
9.40k
  return(name);
9271
9.59k
    }
9272
500k
    *test = NODE_TEST_NAME;
9273
500k
    if ((!blanks) && (CUR == ':')) {
9274
34.4k
  NEXT;
9275
9276
  /*
9277
   * Since currently the parser context don't have a
9278
   * namespace list associated:
9279
   * The namespace name for this prefix can be computed
9280
   * only at evaluation time. The compilation is done
9281
   * outside of any context.
9282
   */
9283
34.4k
  *prefix = name;
9284
9285
34.4k
  if (CUR == '*') {
9286
      /*
9287
       * All elements
9288
       */
9289
3.01k
      NEXT;
9290
3.01k
      *test = NODE_TEST_ALL;
9291
3.01k
      return(NULL);
9292
3.01k
  }
9293
9294
31.4k
  name = xmlXPathParseNCName(ctxt);
9295
31.4k
  if (name == NULL) {
9296
464
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9297
0
  }
9298
31.4k
    }
9299
496k
    return(name);
9300
500k
}
9301
9302
/**
9303
 * [6] AxisName ::=   'ancestor'
9304
 *                  | 'ancestor-or-self'
9305
 *                  | 'attribute'
9306
 *                  | 'child'
9307
 *                  | 'descendant'
9308
 *                  | 'descendant-or-self'
9309
 *                  | 'following'
9310
 *                  | 'following-sibling'
9311
 *                  | 'namespace'
9312
 *                  | 'parent'
9313
 *                  | 'preceding'
9314
 *                  | 'preceding-sibling'
9315
 *                  | 'self'
9316
 *
9317
 * @param name  a preparsed name token
9318
 * @returns the axis or 0
9319
 */
9320
static xmlXPathAxisVal
9321
512k
xmlXPathIsAxisName(const xmlChar *name) {
9322
512k
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9323
512k
    switch (name[0]) {
9324
24.1k
  case 'a':
9325
24.1k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9326
2.07k
    ret = AXIS_ANCESTOR;
9327
24.1k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9328
4.22k
    ret = AXIS_ANCESTOR_OR_SELF;
9329
24.1k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9330
685
    ret = AXIS_ATTRIBUTE;
9331
24.1k
      break;
9332
3.53k
  case 'c':
9333
3.53k
      if (xmlStrEqual(name, BAD_CAST "child"))
9334
498
    ret = AXIS_CHILD;
9335
3.53k
      break;
9336
6.48k
  case 'd':
9337
6.48k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9338
1.53k
    ret = AXIS_DESCENDANT;
9339
6.48k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9340
467
    ret = AXIS_DESCENDANT_OR_SELF;
9341
6.48k
      break;
9342
7.78k
  case 'f':
9343
7.78k
      if (xmlStrEqual(name, BAD_CAST "following"))
9344
2.76k
    ret = AXIS_FOLLOWING;
9345
7.78k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9346
1.24k
    ret = AXIS_FOLLOWING_SIBLING;
9347
7.78k
      break;
9348
42.1k
  case 'n':
9349
42.1k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9350
12.2k
    ret = AXIS_NAMESPACE;
9351
42.1k
      break;
9352
17.6k
  case 'p':
9353
17.6k
      if (xmlStrEqual(name, BAD_CAST "parent"))
9354
2.92k
    ret = AXIS_PARENT;
9355
17.6k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9356
511
    ret = AXIS_PRECEDING;
9357
17.6k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9358
2.81k
    ret = AXIS_PRECEDING_SIBLING;
9359
17.6k
      break;
9360
12.2k
  case 's':
9361
12.2k
      if (xmlStrEqual(name, BAD_CAST "self"))
9362
5.93k
    ret = AXIS_SELF;
9363
12.2k
      break;
9364
512k
    }
9365
512k
    return(ret);
9366
512k
}
9367
9368
/**
9369
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
9370
 *                  | AbbreviatedStep
9371
 *
9372
 * [12] AbbreviatedStep ::=   '.' | '..'
9373
 *
9374
 * [5] AxisSpecifier ::= AxisName '::'
9375
 *                  | AbbreviatedAxisSpecifier
9376
 *
9377
 * [13] AbbreviatedAxisSpecifier ::= '@'?
9378
 *
9379
 * Modified for XPtr range support as:
9380
 *
9381
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9382
 *                     | AbbreviatedStep
9383
 *                     | 'range-to' '(' Expr ')' Predicate*
9384
 *
9385
 * Compile one step in a Location Path
9386
 *
9387
 * @param ctxt  the XPath Parser context
9388
 */
9389
static void
9390
26.4M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9391
26.4M
    SKIP_BLANKS;
9392
26.4M
    if ((CUR == '.') && (NXT(1) == '.')) {
9393
3.23k
  SKIP(2);
9394
3.23k
  SKIP_BLANKS;
9395
3.23k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9396
3.23k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9397
26.4M
    } else if (CUR == '.') {
9398
44.6k
  NEXT;
9399
44.6k
  SKIP_BLANKS;
9400
26.3M
    } else {
9401
26.3M
  xmlChar *name = NULL;
9402
26.3M
  xmlChar *prefix = NULL;
9403
26.3M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9404
26.3M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9405
26.3M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9406
26.3M
  int op1;
9407
9408
26.3M
  if (CUR == '*') {
9409
25.8M
      axis = AXIS_CHILD;
9410
25.8M
  } else {
9411
563k
      if (name == NULL)
9412
563k
    name = xmlXPathParseNCName(ctxt);
9413
563k
      if (name != NULL) {
9414
512k
    axis = xmlXPathIsAxisName(name);
9415
512k
    if (axis != 0) {
9416
37.9k
        SKIP_BLANKS;
9417
37.9k
        if ((CUR == ':') && (NXT(1) == ':')) {
9418
24.0k
      SKIP(2);
9419
24.0k
      xmlFree(name);
9420
24.0k
      name = NULL;
9421
24.0k
        } else {
9422
      /* an element name can conflict with an axis one :-\ */
9423
13.9k
      axis = AXIS_CHILD;
9424
13.9k
        }
9425
474k
    } else {
9426
474k
        axis = AXIS_CHILD;
9427
474k
    }
9428
512k
      } else if (CUR == '@') {
9429
45.3k
    NEXT;
9430
45.3k
    axis = AXIS_ATTRIBUTE;
9431
45.3k
      } else {
9432
5.87k
    axis = AXIS_CHILD;
9433
5.87k
      }
9434
563k
  }
9435
9436
26.3M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9437
5.31k
            xmlFree(name);
9438
5.31k
            return;
9439
5.31k
        }
9440
9441
26.3M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9442
26.3M
  if (test == 0)
9443
3.70k
      return;
9444
9445
26.3M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9446
34.4k
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9447
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9448
0
    xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9449
0
                               "Undefined namespace prefix: %s\n", prefix);
9450
0
      }
9451
0
  }
9452
9453
26.3M
  op1 = ctxt->comp->last;
9454
26.3M
  ctxt->comp->last = -1;
9455
9456
26.3M
  SKIP_BLANKS;
9457
26.4M
  while (CUR == '[') {
9458
36.4k
      xmlXPathCompPredicate(ctxt, 0);
9459
36.4k
  }
9460
9461
26.3M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9462
26.3M
                           test, type, (void *)prefix, (void *)name) == -1) {
9463
139
            xmlFree(prefix);
9464
139
            xmlFree(name);
9465
139
        }
9466
26.3M
    }
9467
26.4M
}
9468
9469
/**
9470
 *  [3]   RelativeLocationPath ::=   Step
9471
 *                     | RelativeLocationPath '/' Step
9472
 *                     | AbbreviatedRelativeLocationPath
9473
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
9474
 *
9475
 * Compile a relative location path.
9476
 *
9477
 * @param ctxt  the XPath Parser context
9478
 */
9479
static void
9480
xmlXPathCompRelativeLocationPath
9481
26.3M
(xmlXPathParserContextPtr ctxt) {
9482
26.3M
    SKIP_BLANKS;
9483
26.3M
    if ((CUR == '/') && (NXT(1) == '/')) {
9484
2.40k
  SKIP(2);
9485
2.40k
  SKIP_BLANKS;
9486
2.40k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9487
2.40k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9488
26.3M
    } else if (CUR == '/') {
9489
12.0k
      NEXT;
9490
12.0k
  SKIP_BLANKS;
9491
12.0k
    }
9492
26.3M
    xmlXPathCompStep(ctxt);
9493
26.3M
    CHECK_ERROR;
9494
26.3M
    SKIP_BLANKS;
9495
26.4M
    while (CUR == '/') {
9496
114k
  if ((CUR == '/') && (NXT(1) == '/')) {
9497
42.6k
      SKIP(2);
9498
42.6k
      SKIP_BLANKS;
9499
42.6k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9500
42.6k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9501
42.6k
      xmlXPathCompStep(ctxt);
9502
71.8k
  } else if (CUR == '/') {
9503
71.8k
      NEXT;
9504
71.8k
      SKIP_BLANKS;
9505
71.8k
      xmlXPathCompStep(ctxt);
9506
71.8k
  }
9507
114k
  SKIP_BLANKS;
9508
114k
    }
9509
26.3M
}
9510
9511
/**
9512
 *  [1]   LocationPath ::=   RelativeLocationPath
9513
 *                     | AbsoluteLocationPath
9514
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
9515
 *                     | AbbreviatedAbsoluteLocationPath
9516
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
9517
 *                           '//' RelativeLocationPath
9518
 *
9519
 * Compile a location path
9520
 *
9521
 * @param ctxt  the XPath Parser context
9522
 */
9523
static void
9524
26.4M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9525
26.4M
    SKIP_BLANKS;
9526
26.4M
    if (CUR != '/') {
9527
26.1M
        xmlXPathCompRelativeLocationPath(ctxt);
9528
26.1M
    } else {
9529
550k
  while (CUR == '/') {
9530
277k
      if ((CUR == '/') && (NXT(1) == '/')) {
9531
85.3k
    SKIP(2);
9532
85.3k
    SKIP_BLANKS;
9533
85.3k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9534
85.3k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9535
85.3k
    xmlXPathCompRelativeLocationPath(ctxt);
9536
192k
      } else if (CUR == '/') {
9537
192k
    NEXT;
9538
192k
    SKIP_BLANKS;
9539
192k
    if ((CUR != 0) &&
9540
192k
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9541
147k
                     (CUR == '_') || (CUR == '.') ||
9542
140k
         (CUR == '@') || (CUR == '*')))
9543
70.5k
        xmlXPathCompRelativeLocationPath(ctxt);
9544
192k
      }
9545
277k
      CHECK_ERROR;
9546
277k
  }
9547
274k
    }
9548
26.4M
}
9549
9550
/************************************************************************
9551
 *                  *
9552
 *    XPath precompiled expression evaluation     *
9553
 *                  *
9554
 ************************************************************************/
9555
9556
static int
9557
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9558
9559
/**
9560
 * Filter a node set, keeping only nodes for which the predicate expression
9561
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
9562
 * filtered result.
9563
 *
9564
 * @param ctxt  the XPath Parser context
9565
 * @param set  the node set to filter
9566
 * @param filterOpIndex  the index of the predicate/filter op
9567
 * @param minPos  minimum position in the filtered set (1-based)
9568
 * @param maxPos  maximum position in the filtered set (1-based)
9569
 * @param hasNsNodes  true if the node set may contain namespace nodes
9570
 */
9571
static void
9572
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
9573
          xmlNodeSetPtr set,
9574
          int filterOpIndex,
9575
                      int minPos, int maxPos,
9576
          int hasNsNodes)
9577
4.11M
{
9578
4.11M
    xmlXPathContextPtr xpctxt;
9579
4.11M
    xmlNodePtr oldnode;
9580
4.11M
    xmlDocPtr olddoc;
9581
4.11M
    xmlXPathStepOpPtr filterOp;
9582
4.11M
    int oldcs, oldpp;
9583
4.11M
    int i, j, pos;
9584
9585
4.11M
    if ((set == NULL) || (set->nodeNr == 0))
9586
33.7k
        return;
9587
9588
    /*
9589
    * Check if the node set contains a sufficient number of nodes for
9590
    * the requested range.
9591
    */
9592
4.08M
    if (set->nodeNr < minPos) {
9593
2.70k
        xmlXPathNodeSetClear(set, hasNsNodes);
9594
2.70k
        return;
9595
2.70k
    }
9596
9597
4.08M
    xpctxt = ctxt->context;
9598
4.08M
    oldnode = xpctxt->node;
9599
4.08M
    olddoc = xpctxt->doc;
9600
4.08M
    oldcs = xpctxt->contextSize;
9601
4.08M
    oldpp = xpctxt->proximityPosition;
9602
4.08M
    filterOp = &ctxt->comp->steps[filterOpIndex];
9603
9604
4.08M
    xpctxt->contextSize = set->nodeNr;
9605
9606
34.0M
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9607
33.8M
        xmlNodePtr node = set->nodeTab[i];
9608
33.8M
        int res;
9609
9610
33.8M
        xpctxt->node = node;
9611
33.8M
        xpctxt->proximityPosition = i + 1;
9612
9613
        /*
9614
        * Also set the xpath document in case things like
9615
        * key() are evaluated in the predicate.
9616
        *
9617
        * TODO: Get real doc for namespace nodes.
9618
        */
9619
33.8M
        if ((node->type != XML_NAMESPACE_DECL) &&
9620
32.7M
            (node->doc != NULL))
9621
32.7M
            xpctxt->doc = node->doc;
9622
9623
33.8M
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9624
9625
33.8M
        if (ctxt->error != XPATH_EXPRESSION_OK)
9626
3.09k
            break;
9627
33.7M
        if (res < 0) {
9628
            /* Shouldn't happen */
9629
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9630
0
            break;
9631
0
        }
9632
9633
33.7M
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9634
31.6M
            if (i != j) {
9635
9.53M
                set->nodeTab[j] = node;
9636
9.53M
                set->nodeTab[i] = NULL;
9637
9.53M
            }
9638
9639
31.6M
            j += 1;
9640
31.6M
        } else {
9641
            /* Remove the entry from the initial node set. */
9642
2.11M
            set->nodeTab[i] = NULL;
9643
2.11M
            if (node->type == XML_NAMESPACE_DECL)
9644
576k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9645
2.11M
        }
9646
9647
33.7M
        if (res != 0) {
9648
31.6M
            if (pos == maxPos) {
9649
3.82M
                i += 1;
9650
3.82M
                break;
9651
3.82M
            }
9652
9653
27.8M
            pos += 1;
9654
27.8M
        }
9655
33.7M
    }
9656
9657
    /* Free remaining nodes. */
9658
4.08M
    if (hasNsNodes) {
9659
560k
        for (; i < set->nodeNr; i++) {
9660
533k
            xmlNodePtr node = set->nodeTab[i];
9661
533k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9662
150k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9663
533k
        }
9664
27.5k
    }
9665
9666
4.08M
    set->nodeNr = j;
9667
9668
    /* If too many elements were removed, shrink table to preserve memory. */
9669
4.08M
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9670
404k
        (set->nodeNr < set->nodeMax / 2)) {
9671
90.6k
        xmlNodePtr *tmp;
9672
90.6k
        int nodeMax = set->nodeNr;
9673
9674
90.6k
        if (nodeMax < XML_NODESET_DEFAULT)
9675
67.2k
            nodeMax = XML_NODESET_DEFAULT;
9676
90.6k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9677
90.6k
                nodeMax * sizeof(xmlNodePtr));
9678
90.6k
        if (tmp == NULL) {
9679
0
            xmlXPathPErrMemory(ctxt);
9680
90.6k
        } else {
9681
90.6k
            set->nodeTab = tmp;
9682
90.6k
            set->nodeMax = nodeMax;
9683
90.6k
        }
9684
90.6k
    }
9685
9686
4.08M
    xpctxt->node = oldnode;
9687
4.08M
    xpctxt->doc = olddoc;
9688
4.08M
    xpctxt->contextSize = oldcs;
9689
4.08M
    xpctxt->proximityPosition = oldpp;
9690
4.08M
}
9691
9692
/**
9693
 * Filter a node set, keeping only nodes for which the sequence of predicate
9694
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
9695
 * in the filtered result.
9696
 *
9697
 * @param ctxt  the XPath Parser context
9698
 * @param op  the predicate op
9699
 * @param set  the node set to filter
9700
 * @param minPos  minimum position in the filtered set (1-based)
9701
 * @param maxPos  maximum position in the filtered set (1-based)
9702
 * @param hasNsNodes  true if the node set may contain namespace nodes
9703
 */
9704
static void
9705
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
9706
          xmlXPathStepOpPtr op,
9707
          xmlNodeSetPtr set,
9708
                            int minPos, int maxPos,
9709
          int hasNsNodes)
9710
4.07M
{
9711
4.07M
    if (op->ch1 != -1) {
9712
10.1k
  xmlXPathCompExprPtr comp = ctxt->comp;
9713
  /*
9714
  * Process inner predicates first.
9715
  */
9716
10.1k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9717
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9718
0
  }
9719
10.1k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9720
10.0k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9721
10.0k
        ctxt->context->depth += 1;
9722
10.0k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9723
10.0k
                                    1, set->nodeNr, hasNsNodes);
9724
10.0k
        ctxt->context->depth -= 1;
9725
10.0k
  CHECK_ERROR;
9726
10.0k
    }
9727
9728
4.07M
    if (op->ch2 != -1)
9729
4.07M
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9730
4.07M
}
9731
9732
static int
9733
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9734
          xmlXPathStepOpPtr op,
9735
          int *maxPos)
9736
18.2M
{
9737
9738
18.2M
    xmlXPathStepOpPtr exprOp;
9739
9740
    /*
9741
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
9742
    */
9743
9744
    /*
9745
    * If not -1, then ch1 will point to:
9746
    * 1) For predicates (XPATH_OP_PREDICATE):
9747
    *    - an inner predicate operator
9748
    * 2) For filters (XPATH_OP_FILTER):
9749
    *    - an inner filter operator OR
9750
    *    - an expression selecting the node set.
9751
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
9752
    */
9753
18.2M
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9754
0
  return(0);
9755
9756
18.2M
    if (op->ch2 != -1) {
9757
18.2M
  exprOp = &ctxt->comp->steps[op->ch2];
9758
18.2M
    } else
9759
0
  return(0);
9760
9761
18.2M
    if ((exprOp != NULL) &&
9762
18.2M
  (exprOp->op == XPATH_OP_VALUE) &&
9763
86.9k
  (exprOp->value4 != NULL) &&
9764
86.9k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9765
67.9k
    {
9766
67.9k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
9767
9768
  /*
9769
  * We have a "[n]" predicate here.
9770
  * TODO: Unfortunately this simplistic test here is not
9771
  * able to detect a position() predicate in compound
9772
  * expressions like "[@attr = 'a" and position() = 1],
9773
  * and even not the usage of position() in
9774
  * "[position() = 1]"; thus - obviously - a position-range,
9775
  * like it "[position() < 5]", is also not detected.
9776
  * Maybe we could rewrite the AST to ease the optimization.
9777
  */
9778
9779
67.9k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9780
64.6k
      *maxPos = (int) floatval;
9781
64.6k
            if (floatval == (double) *maxPos)
9782
63.9k
                return(1);
9783
64.6k
        }
9784
67.9k
    }
9785
18.1M
    return(0);
9786
18.2M
}
9787
9788
static int
9789
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9790
                           xmlXPathStepOpPtr op,
9791
         xmlNodePtr * first, xmlNodePtr * last,
9792
         int toBool)
9793
71.5M
{
9794
9795
71.5M
#define XP_TEST_HIT \
9796
426M
    if (hasAxisRange != 0) { \
9797
119k
  if (++pos == maxPos) { \
9798
17.1k
      if (addNode(seq, cur) < 0) \
9799
17.1k
          xmlXPathPErrMemory(ctxt); \
9800
17.1k
      goto axis_range_end; } \
9801
426M
    } else { \
9802
426M
  if (addNode(seq, cur) < 0) \
9803
426M
      xmlXPathPErrMemory(ctxt); \
9804
426M
  if (breakOnFirstHit) goto first_hit; }
9805
9806
71.5M
#define XP_TEST_HIT_NS \
9807
71.5M
    if (hasAxisRange != 0) { \
9808
0
  if (++pos == maxPos) { \
9809
0
      hasNsNodes = 1; \
9810
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9811
0
          xmlXPathPErrMemory(ctxt); \
9812
0
  goto axis_range_end; } \
9813
1.22M
    } else { \
9814
1.22M
  hasNsNodes = 1; \
9815
1.22M
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9816
1.22M
      xmlXPathPErrMemory(ctxt); \
9817
1.22M
  if (breakOnFirstHit) goto first_hit; }
9818
9819
71.5M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9820
71.5M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9821
71.5M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9822
71.5M
    const xmlChar *prefix = op->value4;
9823
71.5M
    const xmlChar *name = op->value5;
9824
71.5M
    const xmlChar *URI = NULL;
9825
9826
71.5M
    int total = 0, hasNsNodes = 0;
9827
    /* The popped object holding the context nodes */
9828
71.5M
    xmlXPathObjectPtr obj;
9829
    /* The set of context nodes for the node tests */
9830
71.5M
    xmlNodeSetPtr contextSeq;
9831
71.5M
    int contextIdx;
9832
71.5M
    xmlNodePtr contextNode;
9833
    /* The final resulting node set wrt to all context nodes */
9834
71.5M
    xmlNodeSetPtr outSeq;
9835
    /*
9836
    * The temporary resulting node set wrt 1 context node.
9837
    * Used to feed predicate evaluation.
9838
    */
9839
71.5M
    xmlNodeSetPtr seq;
9840
71.5M
    xmlNodePtr cur;
9841
    /* First predicate operator */
9842
71.5M
    xmlXPathStepOpPtr predOp;
9843
71.5M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9844
71.5M
    int hasPredicateRange, hasAxisRange, pos;
9845
71.5M
    int breakOnFirstHit;
9846
9847
71.5M
    xmlXPathTraversalFunction next = NULL;
9848
71.5M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9849
71.5M
    xmlXPathNodeSetMergeFunction mergeAndClear;
9850
71.5M
    xmlNodePtr oldContextNode;
9851
71.5M
    xmlXPathContextPtr xpctxt = ctxt->context;
9852
9853
9854
71.5M
    CHECK_TYPE0(XPATH_NODESET);
9855
71.5M
    obj = xmlXPathValuePop(ctxt);
9856
    /*
9857
    * Setup namespaces.
9858
    */
9859
71.5M
    if (prefix != NULL) {
9860
1.14M
        URI = xmlXPathNsLookup(xpctxt, prefix);
9861
1.14M
        if (URI == NULL) {
9862
932
      xmlXPathReleaseObject(xpctxt, obj);
9863
932
            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
9864
932
                           "Undefined namespace prefix: %s\n", prefix);
9865
932
            return 0;
9866
932
  }
9867
1.14M
    }
9868
    /*
9869
    * Setup axis.
9870
    *
9871
    * MAYBE FUTURE TODO: merging optimizations:
9872
    * - If the nodes to be traversed wrt to the initial nodes and
9873
    *   the current axis cannot overlap, then we could avoid searching
9874
    *   for duplicates during the merge.
9875
    *   But the question is how/when to evaluate if they cannot overlap.
9876
    *   Example: if we know that for two initial nodes, the one is
9877
    *   not in the ancestor-or-self axis of the other, then we could safely
9878
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
9879
    *   the descendant-or-self axis.
9880
    */
9881
71.5M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9882
71.5M
    switch (axis) {
9883
37.3k
        case AXIS_ANCESTOR:
9884
37.3k
            first = NULL;
9885
37.3k
            next = xmlXPathNextAncestor;
9886
37.3k
            break;
9887
478k
        case AXIS_ANCESTOR_OR_SELF:
9888
478k
            first = NULL;
9889
478k
            next = xmlXPathNextAncestorOrSelf;
9890
478k
            break;
9891
1.55M
        case AXIS_ATTRIBUTE:
9892
1.55M
            first = NULL;
9893
1.55M
      last = NULL;
9894
1.55M
            next = xmlXPathNextAttribute;
9895
1.55M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9896
1.55M
            break;
9897
65.5M
        case AXIS_CHILD:
9898
65.5M
      last = NULL;
9899
65.5M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9900
64.8M
    (type == NODE_TYPE_NODE))
9901
64.8M
      {
9902
    /*
9903
    * Optimization if an element node type is 'element'.
9904
    */
9905
64.8M
    next = xmlXPathNextChildElement;
9906
64.8M
      } else
9907
671k
    next = xmlXPathNextChild;
9908
65.5M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9909
65.5M
            break;
9910
592k
        case AXIS_DESCENDANT:
9911
592k
      last = NULL;
9912
592k
            next = xmlXPathNextDescendant;
9913
592k
            break;
9914
1.23M
        case AXIS_DESCENDANT_OR_SELF:
9915
1.23M
      last = NULL;
9916
1.23M
            next = xmlXPathNextDescendantOrSelf;
9917
1.23M
            break;
9918
918
        case AXIS_FOLLOWING:
9919
918
      last = NULL;
9920
918
            next = xmlXPathNextFollowing;
9921
918
            break;
9922
1.05k
        case AXIS_FOLLOWING_SIBLING:
9923
1.05k
      last = NULL;
9924
1.05k
            next = xmlXPathNextFollowingSibling;
9925
1.05k
            break;
9926
9.42k
        case AXIS_NAMESPACE:
9927
9.42k
            first = NULL;
9928
9.42k
      last = NULL;
9929
9.42k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9930
9.42k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9931
9.42k
            break;
9932
595k
        case AXIS_PARENT:
9933
595k
            first = NULL;
9934
595k
            next = xmlXPathNextParent;
9935
595k
            break;
9936
12.7k
        case AXIS_PRECEDING:
9937
12.7k
            first = NULL;
9938
12.7k
            next = xmlXPathNextPrecedingInternal;
9939
12.7k
            break;
9940
288k
        case AXIS_PRECEDING_SIBLING:
9941
288k
            first = NULL;
9942
288k
            next = xmlXPathNextPrecedingSibling;
9943
288k
            break;
9944
1.23M
        case AXIS_SELF:
9945
1.23M
            first = NULL;
9946
1.23M
      last = NULL;
9947
1.23M
            next = xmlXPathNextSelf;
9948
1.23M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9949
1.23M
            break;
9950
71.5M
    }
9951
9952
71.5M
    if (next == NULL) {
9953
0
  xmlXPathReleaseObject(xpctxt, obj);
9954
0
        return(0);
9955
0
    }
9956
71.5M
    contextSeq = obj->nodesetval;
9957
71.5M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9958
2.51M
        xmlXPathValuePush(ctxt, obj);
9959
2.51M
        return(0);
9960
2.51M
    }
9961
    /*
9962
    * Predicate optimization ---------------------------------------------
9963
    * If this step has a last predicate, which contains a position(),
9964
    * then we'll optimize (although not exactly "position()", but only
9965
    * the  short-hand form, i.e., "[n]".
9966
    *
9967
    * Example - expression "/foo[parent::bar][1]":
9968
    *
9969
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
9970
    *   ROOT                               -- op->ch1
9971
    *   PREDICATE                          -- op->ch2 (predOp)
9972
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
9973
    *       SORT
9974
    *         COLLECT  'parent' 'name' 'node' bar
9975
    *           NODE
9976
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
9977
    *
9978
    */
9979
69.0M
    maxPos = 0;
9980
69.0M
    predOp = NULL;
9981
69.0M
    hasPredicateRange = 0;
9982
69.0M
    hasAxisRange = 0;
9983
69.0M
    if (op->ch2 != -1) {
9984
  /*
9985
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9986
  */
9987
18.2M
  predOp = &ctxt->comp->steps[op->ch2];
9988
18.2M
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9989
63.9k
      if (predOp->ch1 != -1) {
9990
    /*
9991
    * Use the next inner predicate operator.
9992
    */
9993
3.81k
    predOp = &ctxt->comp->steps[predOp->ch1];
9994
3.81k
    hasPredicateRange = 1;
9995
60.1k
      } else {
9996
    /*
9997
    * There's no other predicate than the [n] predicate.
9998
    */
9999
60.1k
    predOp = NULL;
10000
60.1k
    hasAxisRange = 1;
10001
60.1k
      }
10002
63.9k
  }
10003
18.2M
    }
10004
69.0M
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
10005
    /*
10006
    * Axis traversal -----------------------------------------------------
10007
    */
10008
    /*
10009
     * 2.3 Node Tests
10010
     *  - For the attribute axis, the principal node type is attribute.
10011
     *  - For the namespace axis, the principal node type is namespace.
10012
     *  - For other axes, the principal node type is element.
10013
     *
10014
     * A node test * is true for any node of the
10015
     * principal node type. For example, child::* will
10016
     * select all element children of the context node
10017
     */
10018
69.0M
    oldContextNode = xpctxt->node;
10019
69.0M
    addNode = xmlXPathNodeSetAddUnique;
10020
69.0M
    outSeq = NULL;
10021
69.0M
    seq = NULL;
10022
69.0M
    contextNode = NULL;
10023
69.0M
    contextIdx = 0;
10024
10025
10026
379M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10027
311M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
10028
311M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
10029
10030
311M
  if (seq == NULL) {
10031
69.7M
      seq = xmlXPathNodeSetCreate(NULL);
10032
69.7M
      if (seq == NULL) {
10033
0
                xmlXPathPErrMemory(ctxt);
10034
0
    total = 0;
10035
0
    goto error;
10036
0
      }
10037
69.7M
  }
10038
  /*
10039
  * Traverse the axis and test the nodes.
10040
  */
10041
311M
  pos = 0;
10042
311M
  cur = NULL;
10043
311M
  hasNsNodes = 0;
10044
942M
        do {
10045
942M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10046
0
                goto error;
10047
10048
942M
            cur = next(ctxt, cur);
10049
942M
            if (cur == NULL)
10050
310M
                break;
10051
10052
      /*
10053
      * QUESTION TODO: What does the "first" and "last" stuff do?
10054
      */
10055
631M
            if ((first != NULL) && (*first != NULL)) {
10056
43.1k
    if (*first == cur)
10057
2.82k
        break;
10058
40.3k
    if (((total % 256) == 0) &&
10059
1.78k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10060
1.78k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10061
#else
10062
        (xmlXPathCmpNodes(*first, cur) >= 0))
10063
#endif
10064
510
    {
10065
510
        break;
10066
510
    }
10067
40.3k
      }
10068
631M
      if ((last != NULL) && (*last != NULL)) {
10069
0
    if (*last == cur)
10070
0
        break;
10071
0
    if (((total % 256) == 0) &&
10072
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10073
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10074
#else
10075
        (xmlXPathCmpNodes(cur, *last) >= 0))
10076
#endif
10077
0
    {
10078
0
        break;
10079
0
    }
10080
0
      }
10081
10082
631M
            total++;
10083
10084
631M
      switch (test) {
10085
0
                case NODE_TEST_NONE:
10086
0
        total = 0;
10087
0
        goto error;
10088
218M
                case NODE_TEST_TYPE:
10089
218M
        if (type == NODE_TYPE_NODE) {
10090
211M
      switch (cur->type) {
10091
615k
          case XML_DOCUMENT_NODE:
10092
615k
          case XML_HTML_DOCUMENT_NODE:
10093
135M
          case XML_ELEMENT_NODE:
10094
135M
          case XML_ATTRIBUTE_NODE:
10095
141M
          case XML_PI_NODE:
10096
146M
          case XML_COMMENT_NODE:
10097
146M
          case XML_CDATA_SECTION_NODE:
10098
211M
          case XML_TEXT_NODE:
10099
211M
        XP_TEST_HIT
10100
211M
        break;
10101
211M
          case XML_NAMESPACE_DECL: {
10102
78.6k
        if (axis == AXIS_NAMESPACE) {
10103
0
            XP_TEST_HIT_NS
10104
78.6k
        } else {
10105
78.6k
                              hasNsNodes = 1;
10106
78.6k
            XP_TEST_HIT
10107
78.6k
        }
10108
78.6k
        break;
10109
78.6k
                            }
10110
78.6k
          default:
10111
27.6k
        break;
10112
211M
      }
10113
211M
        } else if (cur->type == (xmlElementType) type) {
10114
2.88M
      if (cur->type == XML_NAMESPACE_DECL)
10115
0
          XP_TEST_HIT_NS
10116
2.88M
      else
10117
2.88M
          XP_TEST_HIT
10118
3.90M
        } else if ((type == NODE_TYPE_TEXT) &&
10119
3.90M
       (cur->type == XML_CDATA_SECTION_NODE))
10120
5.74k
        {
10121
5.74k
      XP_TEST_HIT
10122
5.74k
        }
10123
218M
        break;
10124
218M
                case NODE_TEST_PI:
10125
38.8k
                    if ((cur->type == XML_PI_NODE) &&
10126
19.1k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10127
132
        {
10128
132
      XP_TEST_HIT
10129
132
                    }
10130
38.8k
                    break;
10131
247M
                case NODE_TEST_ALL:
10132
247M
                    if (axis == AXIS_ATTRIBUTE) {
10133
12.6M
                        if (cur->type == XML_ATTRIBUTE_NODE)
10134
12.6M
      {
10135
12.6M
                            if (prefix == NULL)
10136
12.5M
          {
10137
12.5M
        XP_TEST_HIT
10138
12.5M
                            } else if ((cur->ns != NULL) &&
10139
19.6k
        (xmlStrEqual(URI, cur->ns->href)))
10140
19.4k
          {
10141
19.4k
        XP_TEST_HIT
10142
19.4k
                            }
10143
12.6M
                        }
10144
235M
                    } else if (axis == AXIS_NAMESPACE) {
10145
1.22M
                        if (cur->type == XML_NAMESPACE_DECL)
10146
1.22M
      {
10147
1.22M
          XP_TEST_HIT_NS
10148
1.22M
                        }
10149
233M
                    } else {
10150
233M
                        if (cur->type == XML_ELEMENT_NODE) {
10151
198M
                            if (prefix == NULL)
10152
198M
          {
10153
198M
        XP_TEST_HIT
10154
10155
198M
                            } else if ((cur->ns != NULL) &&
10156
53.6k
        (xmlStrEqual(URI, cur->ns->href)))
10157
3.96k
          {
10158
3.96k
        XP_TEST_HIT
10159
3.96k
                            }
10160
198M
                        }
10161
233M
                    }
10162
247M
                    break;
10163
247M
                case NODE_TEST_NS:{
10164
                        /* TODO */
10165
0
                        break;
10166
247M
                    }
10167
165M
                case NODE_TEST_NAME:
10168
165M
                    if (axis == AXIS_ATTRIBUTE) {
10169
928k
                        if (cur->type != XML_ATTRIBUTE_NODE)
10170
0
          break;
10171
164M
        } else if (axis == AXIS_NAMESPACE) {
10172
0
                        if (cur->type != XML_NAMESPACE_DECL)
10173
0
          break;
10174
164M
        } else {
10175
164M
            if (cur->type != XML_ELEMENT_NODE)
10176
86.0M
          break;
10177
164M
        }
10178
79.6M
                    switch (cur->type) {
10179
78.6M
                        case XML_ELEMENT_NODE:
10180
78.6M
                            if (xmlStrEqual(name, cur->name)) {
10181
1.32M
                                if (prefix == NULL) {
10182
520k
                                    if (cur->ns == NULL)
10183
266k
            {
10184
266k
          XP_TEST_HIT
10185
266k
                                    }
10186
800k
                                } else {
10187
800k
                                    if ((cur->ns != NULL) &&
10188
799k
                                        (xmlStrEqual(URI, cur->ns->href)))
10189
795k
            {
10190
795k
          XP_TEST_HIT
10191
795k
                                    }
10192
800k
                                }
10193
1.32M
                            }
10194
78.6M
                            break;
10195
78.6M
                        case XML_ATTRIBUTE_NODE:{
10196
928k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10197
10198
928k
                                if (xmlStrEqual(name, attr->name)) {
10199
501k
                                    if (prefix == NULL) {
10200
490k
                                        if ((attr->ns == NULL) ||
10201
2.11k
                                            (attr->ns->prefix == NULL))
10202
488k
          {
10203
488k
              XP_TEST_HIT
10204
488k
                                        }
10205
490k
                                    } else {
10206
10.8k
                                        if ((attr->ns != NULL) &&
10207
9.52k
                                            (xmlStrEqual(URI,
10208
9.52k
                attr->ns->href)))
10209
9.14k
          {
10210
9.14k
              XP_TEST_HIT
10211
9.14k
                                        }
10212
10.8k
                                    }
10213
501k
                                }
10214
926k
                                break;
10215
928k
                            }
10216
926k
                        case XML_NAMESPACE_DECL:
10217
0
                            if (cur->type == XML_NAMESPACE_DECL) {
10218
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
10219
10220
0
                                if ((ns->prefix != NULL) && (name != NULL)
10221
0
                                    && (xmlStrEqual(ns->prefix, name)))
10222
0
        {
10223
0
            XP_TEST_HIT_NS
10224
0
                                }
10225
0
                            }
10226
0
                            break;
10227
0
                        default:
10228
0
                            break;
10229
79.6M
                    }
10230
79.5M
                    break;
10231
631M
      } /* switch(test) */
10232
631M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10233
10234
310M
  goto apply_predicates;
10235
10236
310M
axis_range_end: /* ----------------------------------------------------- */
10237
  /*
10238
  * We have a "/foo[n]", and position() = n was reached.
10239
  * Note that we can have as well "/foo/::parent::foo[1]", so
10240
  * a duplicate-aware merge is still needed.
10241
  * Merge with the result.
10242
  */
10243
17.1k
  if (outSeq == NULL) {
10244
7.16k
      outSeq = seq;
10245
7.16k
      seq = NULL;
10246
10.0k
  } else {
10247
10.0k
      outSeq = mergeAndClear(outSeq, seq);
10248
10.0k
            if (outSeq == NULL)
10249
0
                xmlXPathPErrMemory(ctxt);
10250
10.0k
        }
10251
  /*
10252
  * Break if only a true/false result was requested.
10253
  */
10254
17.1k
  if (toBool)
10255
2.21k
      break;
10256
14.9k
  continue;
10257
10258
665k
first_hit: /* ---------------------------------------------------------- */
10259
  /*
10260
  * Break if only a true/false result was requested and
10261
  * no predicates existed and a node test succeeded.
10262
  */
10263
665k
  if (outSeq == NULL) {
10264
665k
      outSeq = seq;
10265
665k
      seq = NULL;
10266
665k
  } else {
10267
0
      outSeq = mergeAndClear(outSeq, seq);
10268
0
            if (outSeq == NULL)
10269
0
                xmlXPathPErrMemory(ctxt);
10270
0
        }
10271
665k
  break;
10272
10273
310M
apply_predicates: /* --------------------------------------------------- */
10274
310M
        if (ctxt->error != XPATH_EXPRESSION_OK)
10275
0
      goto error;
10276
10277
        /*
10278
  * Apply predicates.
10279
  */
10280
310M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
10281
      /*
10282
      * E.g. when we have a "/foo[some expression][n]".
10283
      */
10284
      /*
10285
      * QUESTION TODO: The old predicate evaluation took into
10286
      *  account location-sets.
10287
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
10288
      *  Do we expect such a set here?
10289
      *  All what I learned now from the evaluation semantics
10290
      *  does not indicate that a location-set will be processed
10291
      *  here, so this looks OK.
10292
      */
10293
      /*
10294
      * Iterate over all predicates, starting with the outermost
10295
      * predicate.
10296
      * TODO: Problem: we cannot execute the inner predicates first
10297
      *  since we cannot go back *up* the operator tree!
10298
      *  Options we have:
10299
      *  1) Use of recursive functions (like is it currently done
10300
      *     via xmlXPathCompOpEval())
10301
      *  2) Add a predicate evaluation information stack to the
10302
      *     context struct
10303
      *  3) Change the way the operators are linked; we need a
10304
      *     "parent" field on xmlXPathStepOp
10305
      *
10306
      * For the moment, I'll try to solve this with a recursive
10307
      * function: xmlXPathCompOpEvalPredicate().
10308
      */
10309
4.06M
      if (hasPredicateRange != 0)
10310
5.97k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10311
5.97k
              hasNsNodes);
10312
4.05M
      else
10313
4.05M
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10314
4.05M
              hasNsNodes);
10315
10316
4.06M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10317
742
    total = 0;
10318
742
    goto error;
10319
742
      }
10320
4.06M
        }
10321
10322
310M
        if (seq->nodeNr > 0) {
10323
      /*
10324
      * Add to result set.
10325
      */
10326
26.4M
      if (outSeq == NULL) {
10327
7.53M
    outSeq = seq;
10328
7.53M
    seq = NULL;
10329
18.8M
      } else {
10330
18.8M
    outSeq = mergeAndClear(outSeq, seq);
10331
18.8M
                if (outSeq == NULL)
10332
0
                    xmlXPathPErrMemory(ctxt);
10333
18.8M
      }
10334
10335
26.4M
            if (toBool)
10336
481k
                break;
10337
26.4M
  }
10338
310M
    }
10339
10340
69.0M
error:
10341
69.0M
    if ((obj->boolval) && (obj->user != NULL)) {
10342
  /*
10343
  * QUESTION TODO: What does this do and why?
10344
  * TODO: Do we have to do this also for the "error"
10345
  * cleanup further down?
10346
  */
10347
0
  ctxt->value->boolval = 1;
10348
0
  ctxt->value->user = obj->user;
10349
0
  obj->user = NULL;
10350
0
  obj->boolval = 0;
10351
0
    }
10352
69.0M
    xmlXPathReleaseObject(xpctxt, obj);
10353
10354
    /*
10355
    * Ensure we return at least an empty set.
10356
    */
10357
69.0M
    if (outSeq == NULL) {
10358
60.8M
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10359
60.8M
      outSeq = seq;
10360
60.8M
        } else {
10361
27
      outSeq = xmlXPathNodeSetCreate(NULL);
10362
27
            if (outSeq == NULL)
10363
0
                xmlXPathPErrMemory(ctxt);
10364
27
        }
10365
60.8M
    }
10366
69.0M
    if ((seq != NULL) && (seq != outSeq)) {
10367
673k
   xmlXPathFreeNodeSet(seq);
10368
673k
    }
10369
    /*
10370
    * Hand over the result. Better to push the set also in
10371
    * case of errors.
10372
    */
10373
69.0M
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10374
    /*
10375
    * Reset the context node.
10376
    */
10377
69.0M
    xpctxt->node = oldContextNode;
10378
    /*
10379
    * When traversing the namespace axis in "toBool" mode, it's
10380
    * possible that tmpNsList wasn't freed.
10381
    */
10382
69.0M
    if (xpctxt->tmpNsList != NULL) {
10383
0
        xmlFree(xpctxt->tmpNsList);
10384
0
        xpctxt->tmpNsList = NULL;
10385
0
    }
10386
10387
69.0M
    return(total);
10388
69.0M
}
10389
10390
static int
10391
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10392
            xmlXPathStepOpPtr op, xmlNodePtr * first);
10393
10394
/**
10395
 * Evaluate the Precompiled XPath operation searching only the first
10396
 * element in document order
10397
 *
10398
 * @param ctxt  the XPath parser context with the compiled expression
10399
 * @param op  an XPath compiled operation
10400
 * @param first  the first elem found so far
10401
 * @returns the number of examined objects.
10402
 */
10403
static int
10404
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10405
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
10406
38.2k
{
10407
38.2k
    int total = 0, cur;
10408
38.2k
    xmlXPathCompExprPtr comp;
10409
38.2k
    xmlXPathObjectPtr arg1, arg2;
10410
10411
38.2k
    CHECK_ERROR0;
10412
38.2k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10413
0
        return(0);
10414
38.2k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10415
38.2k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10416
38.2k
    ctxt->context->depth += 1;
10417
38.2k
    comp = ctxt->comp;
10418
38.2k
    switch (op->op) {
10419
0
        case XPATH_OP_END:
10420
0
            break;
10421
6.94k
        case XPATH_OP_UNION:
10422
6.94k
            total =
10423
6.94k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10424
6.94k
                                        first);
10425
6.94k
      CHECK_ERROR0;
10426
6.80k
            if ((ctxt->value != NULL)
10427
6.80k
                && (ctxt->value->type == XPATH_NODESET)
10428
6.79k
                && (ctxt->value->nodesetval != NULL)
10429
6.79k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10430
                /*
10431
                 * limit tree traversing to first node in the result
10432
                 */
10433
    /*
10434
    * OPTIMIZE TODO: This implicitly sorts
10435
    *  the result, even if not needed. E.g. if the argument
10436
    *  of the count() function, no sorting is needed.
10437
    * OPTIMIZE TODO: How do we know if the node-list wasn't
10438
    *  already sorted?
10439
    */
10440
1.96k
    if (ctxt->value->nodesetval->nodeNr > 1)
10441
918
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10442
1.96k
                *first = ctxt->value->nodesetval->nodeTab[0];
10443
1.96k
            }
10444
6.80k
            cur =
10445
6.80k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10446
6.80k
                                        first);
10447
6.80k
      CHECK_ERROR0;
10448
10449
6.79k
            arg2 = xmlXPathValuePop(ctxt);
10450
6.79k
            arg1 = xmlXPathValuePop(ctxt);
10451
6.79k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10452
6.78k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10453
14
          xmlXPathReleaseObject(ctxt->context, arg1);
10454
14
          xmlXPathReleaseObject(ctxt->context, arg2);
10455
14
                XP_ERROR0(XPATH_INVALID_TYPE);
10456
0
            }
10457
6.77k
            if ((ctxt->context->opLimit != 0) &&
10458
0
                (((arg1->nodesetval != NULL) &&
10459
0
                  (xmlXPathCheckOpLimit(ctxt,
10460
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10461
0
                 ((arg2->nodesetval != NULL) &&
10462
0
                  (xmlXPathCheckOpLimit(ctxt,
10463
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10464
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10465
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10466
0
                break;
10467
0
            }
10468
10469
6.77k
            if ((arg2->nodesetval != NULL) &&
10470
6.77k
                (arg2->nodesetval->nodeNr != 0)) {
10471
1.70k
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10472
1.70k
                                                        arg2->nodesetval);
10473
1.70k
                if (arg1->nodesetval == NULL)
10474
0
                    xmlXPathPErrMemory(ctxt);
10475
1.70k
            }
10476
6.77k
            xmlXPathValuePush(ctxt, arg1);
10477
6.77k
      xmlXPathReleaseObject(ctxt->context, arg2);
10478
6.77k
            total += cur;
10479
6.77k
            break;
10480
646
        case XPATH_OP_ROOT:
10481
646
            xmlXPathRoot(ctxt);
10482
646
            break;
10483
396
        case XPATH_OP_NODE:
10484
396
            if (op->ch1 != -1)
10485
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10486
396
      CHECK_ERROR0;
10487
396
            if (op->ch2 != -1)
10488
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10489
396
      CHECK_ERROR0;
10490
396
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10491
396
    ctxt->context->node));
10492
396
            break;
10493
11.6k
        case XPATH_OP_COLLECT:{
10494
11.6k
                if (op->ch1 == -1)
10495
0
                    break;
10496
10497
11.6k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10498
11.6k
    CHECK_ERROR0;
10499
10500
11.6k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10501
11.6k
                break;
10502
11.6k
            }
10503
16
        case XPATH_OP_VALUE:
10504
16
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10505
16
            break;
10506
7.66k
        case XPATH_OP_SORT:
10507
7.66k
            if (op->ch1 != -1)
10508
7.66k
                total +=
10509
7.66k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10510
7.66k
                                            first);
10511
7.66k
      CHECK_ERROR0;
10512
7.61k
            if ((ctxt->value != NULL)
10513
7.61k
                && (ctxt->value->type == XPATH_NODESET)
10514
5.92k
                && (ctxt->value->nodesetval != NULL)
10515
5.92k
    && (ctxt->value->nodesetval->nodeNr > 1))
10516
1.51k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10517
7.61k
            break;
10518
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10519
9.19k
  case XPATH_OP_FILTER:
10520
9.19k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10521
9.19k
            break;
10522
0
#endif
10523
1.69k
        default:
10524
1.69k
            total += xmlXPathCompOpEval(ctxt, op);
10525
1.69k
            break;
10526
38.2k
    }
10527
10528
38.0k
    ctxt->context->depth -= 1;
10529
38.0k
    return(total);
10530
38.2k
}
10531
10532
/**
10533
 * Evaluate the Precompiled XPath operation searching only the last
10534
 * element in document order
10535
 *
10536
 * @param ctxt  the XPath parser context with the compiled expression
10537
 * @param op  an XPath compiled operation
10538
 * @param last  the last elem found so far
10539
 * @returns the number of nodes traversed
10540
 */
10541
static int
10542
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10543
                       xmlNodePtr * last)
10544
0
{
10545
0
    int total = 0, cur;
10546
0
    xmlXPathCompExprPtr comp;
10547
0
    xmlXPathObjectPtr arg1, arg2;
10548
10549
0
    CHECK_ERROR0;
10550
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10551
0
        return(0);
10552
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10553
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10554
0
    ctxt->context->depth += 1;
10555
0
    comp = ctxt->comp;
10556
0
    switch (op->op) {
10557
0
        case XPATH_OP_END:
10558
0
            break;
10559
0
        case XPATH_OP_UNION:
10560
0
            total =
10561
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10562
0
      CHECK_ERROR0;
10563
0
            if ((ctxt->value != NULL)
10564
0
                && (ctxt->value->type == XPATH_NODESET)
10565
0
                && (ctxt->value->nodesetval != NULL)
10566
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10567
                /*
10568
                 * limit tree traversing to first node in the result
10569
                 */
10570
0
    if (ctxt->value->nodesetval->nodeNr > 1)
10571
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10572
0
                *last =
10573
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10574
0
                                                     nodesetval->nodeNr -
10575
0
                                                     1];
10576
0
            }
10577
0
            cur =
10578
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10579
0
      CHECK_ERROR0;
10580
0
            if ((ctxt->value != NULL)
10581
0
                && (ctxt->value->type == XPATH_NODESET)
10582
0
                && (ctxt->value->nodesetval != NULL)
10583
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10584
0
            }
10585
10586
0
            arg2 = xmlXPathValuePop(ctxt);
10587
0
            arg1 = xmlXPathValuePop(ctxt);
10588
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10589
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10590
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10591
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10592
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10593
0
            }
10594
0
            if ((ctxt->context->opLimit != 0) &&
10595
0
                (((arg1->nodesetval != NULL) &&
10596
0
                  (xmlXPathCheckOpLimit(ctxt,
10597
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10598
0
                 ((arg2->nodesetval != NULL) &&
10599
0
                  (xmlXPathCheckOpLimit(ctxt,
10600
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10601
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10602
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10603
0
                break;
10604
0
            }
10605
10606
0
            if ((arg2->nodesetval != NULL) &&
10607
0
                (arg2->nodesetval->nodeNr != 0)) {
10608
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10609
0
                                                        arg2->nodesetval);
10610
0
                if (arg1->nodesetval == NULL)
10611
0
                    xmlXPathPErrMemory(ctxt);
10612
0
            }
10613
0
            xmlXPathValuePush(ctxt, arg1);
10614
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10615
0
            total += cur;
10616
0
            break;
10617
0
        case XPATH_OP_ROOT:
10618
0
            xmlXPathRoot(ctxt);
10619
0
            break;
10620
0
        case XPATH_OP_NODE:
10621
0
            if (op->ch1 != -1)
10622
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10623
0
      CHECK_ERROR0;
10624
0
            if (op->ch2 != -1)
10625
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10626
0
      CHECK_ERROR0;
10627
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10628
0
    ctxt->context->node));
10629
0
            break;
10630
0
        case XPATH_OP_COLLECT:{
10631
0
                if (op->ch1 == -1)
10632
0
                    break;
10633
10634
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10635
0
    CHECK_ERROR0;
10636
10637
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10638
0
                break;
10639
0
            }
10640
0
        case XPATH_OP_VALUE:
10641
0
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10642
0
            break;
10643
0
        case XPATH_OP_SORT:
10644
0
            if (op->ch1 != -1)
10645
0
                total +=
10646
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10647
0
                                           last);
10648
0
      CHECK_ERROR0;
10649
0
            if ((ctxt->value != NULL)
10650
0
                && (ctxt->value->type == XPATH_NODESET)
10651
0
                && (ctxt->value->nodesetval != NULL)
10652
0
    && (ctxt->value->nodesetval->nodeNr > 1))
10653
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10654
0
            break;
10655
0
        default:
10656
0
            total += xmlXPathCompOpEval(ctxt, op);
10657
0
            break;
10658
0
    }
10659
10660
0
    ctxt->context->depth -= 1;
10661
0
    return (total);
10662
0
}
10663
10664
#ifdef XP_OPTIMIZED_FILTER_FIRST
10665
static int
10666
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10667
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10668
9.19k
{
10669
9.19k
    int total = 0;
10670
9.19k
    xmlXPathCompExprPtr comp;
10671
9.19k
    xmlXPathObjectPtr obj;
10672
9.19k
    xmlNodeSetPtr set;
10673
10674
9.19k
    CHECK_ERROR0;
10675
9.19k
    comp = ctxt->comp;
10676
    /*
10677
    * Optimization for ()[last()] selection i.e. the last elem
10678
    */
10679
9.19k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10680
9.19k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10681
3.26k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10682
1.65k
  int f = comp->steps[op->ch2].ch1;
10683
10684
1.65k
  if ((f != -1) &&
10685
1.65k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10686
1.23k
      (comp->steps[f].value5 == NULL) &&
10687
846
      (comp->steps[f].value == 0) &&
10688
392
      (comp->steps[f].value4 != NULL) &&
10689
392
      (xmlStrEqual
10690
392
      (comp->steps[f].value4, BAD_CAST "last"))) {
10691
0
      xmlNodePtr last = NULL;
10692
10693
0
      total +=
10694
0
    xmlXPathCompOpEvalLast(ctxt,
10695
0
        &comp->steps[op->ch1],
10696
0
        &last);
10697
0
      CHECK_ERROR0;
10698
      /*
10699
      * The nodeset should be in document order,
10700
      * Keep only the last value
10701
      */
10702
0
      if ((ctxt->value != NULL) &&
10703
0
    (ctxt->value->type == XPATH_NODESET) &&
10704
0
    (ctxt->value->nodesetval != NULL) &&
10705
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10706
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
10707
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10708
0
    *first = *(ctxt->value->nodesetval->nodeTab);
10709
0
      }
10710
0
      return (total);
10711
0
  }
10712
1.65k
    }
10713
10714
9.19k
    if (op->ch1 != -1)
10715
9.19k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10716
9.19k
    CHECK_ERROR0;
10717
8.12k
    if (op->ch2 == -1)
10718
0
  return (total);
10719
8.12k
    if (ctxt->value == NULL)
10720
0
  return (total);
10721
10722
    /*
10723
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
10724
     * the stack. We have to temporarily remove the nodeset object from the
10725
     * stack to avoid freeing it prematurely.
10726
     */
10727
8.12k
    CHECK_TYPE0(XPATH_NODESET);
10728
8.10k
    obj = xmlXPathValuePop(ctxt);
10729
8.10k
    set = obj->nodesetval;
10730
8.10k
    if (set != NULL) {
10731
8.10k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10732
8.10k
        if (set->nodeNr > 0)
10733
2.54k
            *first = set->nodeTab[0];
10734
8.10k
    }
10735
8.10k
    xmlXPathValuePush(ctxt, obj);
10736
10737
8.10k
    return (total);
10738
8.12k
}
10739
#endif /* XP_OPTIMIZED_FILTER_FIRST */
10740
10741
/**
10742
 * Evaluate the Precompiled XPath operation
10743
 *
10744
 * @param ctxt  the XPath parser context with the compiled expression
10745
 * @param op  an XPath compiled operation
10746
 * @returns the number of nodes traversed
10747
 */
10748
static int
10749
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10750
251M
{
10751
251M
    int total = 0;
10752
251M
    int equal, ret;
10753
251M
    xmlXPathCompExprPtr comp;
10754
251M
    xmlXPathObjectPtr arg1, arg2;
10755
10756
251M
    CHECK_ERROR0;
10757
251M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10758
0
        return(0);
10759
251M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10760
251M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10761
251M
    ctxt->context->depth += 1;
10762
251M
    comp = ctxt->comp;
10763
251M
    switch (op->op) {
10764
0
        case XPATH_OP_END:
10765
0
            break;
10766
150k
        case XPATH_OP_AND:
10767
150k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10768
150k
      CHECK_ERROR0;
10769
150k
            xmlXPathBooleanFunction(ctxt, 1);
10770
150k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10771
87.3k
                break;
10772
62.8k
            arg2 = xmlXPathValuePop(ctxt);
10773
62.8k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10774
62.8k
      if (ctxt->error) {
10775
127
    xmlXPathFreeObject(arg2);
10776
127
    break;
10777
127
      }
10778
62.7k
            xmlXPathBooleanFunction(ctxt, 1);
10779
62.7k
            if (ctxt->value != NULL)
10780
62.7k
                ctxt->value->boolval &= arg2->boolval;
10781
62.7k
      xmlXPathReleaseObject(ctxt->context, arg2);
10782
62.7k
            break;
10783
434k
        case XPATH_OP_OR:
10784
434k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10785
434k
      CHECK_ERROR0;
10786
431k
            xmlXPathBooleanFunction(ctxt, 1);
10787
431k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10788
47.6k
                break;
10789
384k
            arg2 = xmlXPathValuePop(ctxt);
10790
384k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10791
384k
      if (ctxt->error) {
10792
433
    xmlXPathFreeObject(arg2);
10793
433
    break;
10794
433
      }
10795
383k
            xmlXPathBooleanFunction(ctxt, 1);
10796
383k
            if (ctxt->value != NULL)
10797
383k
                ctxt->value->boolval |= arg2->boolval;
10798
383k
      xmlXPathReleaseObject(ctxt->context, arg2);
10799
383k
            break;
10800
20.1M
        case XPATH_OP_EQUAL:
10801
20.1M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10802
20.1M
      CHECK_ERROR0;
10803
20.1M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10804
20.1M
      CHECK_ERROR0;
10805
20.1M
      if (op->value)
10806
18.7M
    equal = xmlXPathEqualValues(ctxt);
10807
1.36M
      else
10808
1.36M
    equal = xmlXPathNotEqualValues(ctxt);
10809
20.1M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10810
20.1M
            break;
10811
13.6M
        case XPATH_OP_CMP:
10812
13.6M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10813
13.6M
      CHECK_ERROR0;
10814
13.6M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10815
13.6M
      CHECK_ERROR0;
10816
13.6M
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10817
13.6M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10818
13.6M
            break;
10819
2.49M
        case XPATH_OP_PLUS:
10820
2.49M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10821
2.49M
      CHECK_ERROR0;
10822
2.49M
            if (op->ch2 != -1) {
10823
1.01M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10824
1.01M
      }
10825
2.49M
      CHECK_ERROR0;
10826
2.49M
            if (op->value == 0)
10827
866k
                xmlXPathSubValues(ctxt);
10828
1.62M
            else if (op->value == 1)
10829
147k
                xmlXPathAddValues(ctxt);
10830
1.47M
            else if (op->value == 2)
10831
866k
                xmlXPathValueFlipSign(ctxt);
10832
613k
            else if (op->value == 3) {
10833
613k
                CAST_TO_NUMBER;
10834
613k
                CHECK_TYPE0(XPATH_NUMBER);
10835
613k
            }
10836
2.49M
            break;
10837
18.7M
        case XPATH_OP_MULT:
10838
18.7M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10839
18.7M
      CHECK_ERROR0;
10840
18.6M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10841
18.6M
      CHECK_ERROR0;
10842
18.6M
            if (op->value == 0)
10843
18.6M
                xmlXPathMultValues(ctxt);
10844
74.1k
            else if (op->value == 1)
10845
1.46k
                xmlXPathDivValues(ctxt);
10846
72.6k
            else if (op->value == 2)
10847
72.6k
                xmlXPathModValues(ctxt);
10848
18.6M
            break;
10849
1.04M
        case XPATH_OP_UNION:
10850
1.04M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10851
1.04M
      CHECK_ERROR0;
10852
1.04M
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10853
1.04M
      CHECK_ERROR0;
10854
10855
1.04M
            arg2 = xmlXPathValuePop(ctxt);
10856
1.04M
            arg1 = xmlXPathValuePop(ctxt);
10857
1.04M
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10858
1.04M
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10859
336
          xmlXPathReleaseObject(ctxt->context, arg1);
10860
336
          xmlXPathReleaseObject(ctxt->context, arg2);
10861
336
                XP_ERROR0(XPATH_INVALID_TYPE);
10862
0
            }
10863
1.04M
            if ((ctxt->context->opLimit != 0) &&
10864
0
                (((arg1->nodesetval != NULL) &&
10865
0
                  (xmlXPathCheckOpLimit(ctxt,
10866
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10867
0
                 ((arg2->nodesetval != NULL) &&
10868
0
                  (xmlXPathCheckOpLimit(ctxt,
10869
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10870
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10871
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10872
0
                break;
10873
0
            }
10874
10875
1.04M
      if (((arg2->nodesetval != NULL) &&
10876
1.04M
     (arg2->nodesetval->nodeNr != 0)))
10877
357k
      {
10878
357k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10879
357k
              arg2->nodesetval);
10880
357k
                if (arg1->nodesetval == NULL)
10881
0
                    xmlXPathPErrMemory(ctxt);
10882
357k
      }
10883
10884
1.04M
            xmlXPathValuePush(ctxt, arg1);
10885
1.04M
      xmlXPathReleaseObject(ctxt->context, arg2);
10886
1.04M
            break;
10887
12.8M
        case XPATH_OP_ROOT:
10888
12.8M
            xmlXPathRoot(ctxt);
10889
12.8M
            break;
10890
66.7M
        case XPATH_OP_NODE:
10891
66.7M
            if (op->ch1 != -1)
10892
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10893
66.7M
      CHECK_ERROR0;
10894
66.7M
            if (op->ch2 != -1)
10895
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10896
66.7M
      CHECK_ERROR0;
10897
66.7M
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10898
66.7M
                                                    ctxt->context->node));
10899
66.7M
            break;
10900
70.1M
        case XPATH_OP_COLLECT:{
10901
70.1M
                if (op->ch1 == -1)
10902
0
                    break;
10903
10904
70.1M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10905
70.1M
    CHECK_ERROR0;
10906
10907
70.1M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10908
70.1M
                break;
10909
70.1M
            }
10910
9.62M
        case XPATH_OP_VALUE:
10911
9.62M
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10912
9.62M
            break;
10913
139
        case XPATH_OP_VARIABLE:{
10914
139
    xmlXPathObjectPtr val;
10915
10916
139
                if (op->ch1 != -1)
10917
0
                    total +=
10918
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10919
139
                if (op->value5 == NULL) {
10920
115
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10921
115
        if (val == NULL) {
10922
115
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10923
115
                                       "Undefined variable: %s\n", op->value4);
10924
115
                        return 0;
10925
115
                    }
10926
0
                    xmlXPathValuePush(ctxt, val);
10927
24
    } else {
10928
24
                    const xmlChar *URI;
10929
10930
24
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10931
24
                    if (URI == NULL) {
10932
17
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10933
17
                                       "Undefined namespace prefix: %s\n",
10934
17
                                       op->value5);
10935
17
                        return 0;
10936
17
                    }
10937
7
        val = xmlXPathVariableLookupNS(ctxt->context,
10938
7
                                                       op->value4, URI);
10939
7
        if (val == NULL) {
10940
7
                        xmlXPathErrFmt(ctxt, XPATH_UNDEF_VARIABLE_ERROR,
10941
7
                                       "Undefined variable: %s:%s\n",
10942
7
                                       op->value5, op->value4);
10943
7
                        return 0;
10944
7
                    }
10945
0
                    xmlXPathValuePush(ctxt, val);
10946
0
                }
10947
0
                break;
10948
139
            }
10949
11.6M
        case XPATH_OP_FUNCTION:{
10950
11.6M
                xmlXPathFunction func;
10951
11.6M
                const xmlChar *oldFunc, *oldFuncURI;
10952
11.6M
    int i;
10953
11.6M
                int frame;
10954
10955
11.6M
                frame = ctxt->valueNr;
10956
11.6M
                if (op->ch1 != -1) {
10957
11.5M
                    total +=
10958
11.5M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10959
11.5M
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10960
3.77k
                        break;
10961
11.5M
                }
10962
11.6M
    if (ctxt->valueNr < frame + op->value)
10963
11.6M
        XP_ERROR0(XPATH_INVALID_OPERAND);
10964
23.2M
    for (i = 0; i < op->value; i++) {
10965
11.6M
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10966
11.6M
      XP_ERROR0(XPATH_INVALID_OPERAND);
10967
11.6M
                }
10968
11.6M
                if (op->cache != NULL)
10969
11.5M
                    func = op->cache;
10970
36.0k
                else {
10971
36.0k
                    const xmlChar *URI = NULL;
10972
10973
36.0k
                    if (op->value5 == NULL) {
10974
36.0k
                        func = xmlXPathFunctionLookup(ctxt->context,
10975
36.0k
                                                      op->value4);
10976
36.0k
                        if (func == NULL) {
10977
1.05k
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10978
1.05k
                                           "Unregistered function: %s\n",
10979
1.05k
                                           op->value4);
10980
1.05k
                            return 0;
10981
1.05k
                        }
10982
36.0k
                    } else {
10983
55
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10984
55
                        if (URI == NULL) {
10985
48
                            xmlXPathErrFmt(ctxt, XPATH_UNDEF_PREFIX_ERROR,
10986
48
                                           "Undefined namespace prefix: %s\n",
10987
48
                                           op->value5);
10988
48
                            return 0;
10989
48
                        }
10990
7
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10991
7
                                                        op->value4, URI);
10992
7
                        if (func == NULL) {
10993
7
                            xmlXPathErrFmt(ctxt, XPATH_UNKNOWN_FUNC_ERROR,
10994
7
                                           "Unregistered function: %s:%s\n",
10995
7
                                           op->value5, op->value4);
10996
7
                            return 0;
10997
7
                        }
10998
7
                    }
10999
34.9k
                    op->cache = func;
11000
34.9k
                    op->cacheURI = (void *) URI;
11001
34.9k
                }
11002
11.6M
                oldFunc = ctxt->context->function;
11003
11.6M
                oldFuncURI = ctxt->context->functionURI;
11004
11.6M
                ctxt->context->function = op->value4;
11005
11.6M
                ctxt->context->functionURI = op->cacheURI;
11006
11.6M
                func(ctxt, op->value);
11007
11.6M
                ctxt->context->function = oldFunc;
11008
11.6M
                ctxt->context->functionURI = oldFuncURI;
11009
11.6M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11010
11.6M
                    (ctxt->valueNr != frame + 1))
11011
11.6M
                    XP_ERROR0(XPATH_STACK_ERROR);
11012
11.6M
                break;
11013
11.6M
            }
11014
11.6M
        case XPATH_OP_ARG:
11015
11.6M
            if (op->ch1 != -1) {
11016
82.7k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11017
82.7k
          CHECK_ERROR0;
11018
82.7k
            }
11019
11.6M
            if (op->ch2 != -1) {
11020
11.6M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11021
11.6M
          CHECK_ERROR0;
11022
11.6M
      }
11023
11.6M
            break;
11024
11.6M
        case XPATH_OP_PREDICATE:
11025
58.4k
        case XPATH_OP_FILTER:{
11026
58.4k
                xmlXPathObjectPtr obj;
11027
58.4k
                xmlNodeSetPtr set;
11028
11029
                /*
11030
                 * Optimization for ()[1] selection i.e. the first elem
11031
                 */
11032
58.4k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11033
58.4k
#ifdef XP_OPTIMIZED_FILTER_FIRST
11034
        /*
11035
        * FILTER TODO: Can we assume that the inner processing
11036
        *  will result in an ordered list if we have an
11037
        *  XPATH_OP_FILTER?
11038
        *  What about an additional field or flag on
11039
        *  xmlXPathObject like @sorted ? This way we wouldn't need
11040
        *  to assume anything, so it would be more robust and
11041
        *  easier to optimize.
11042
        */
11043
58.4k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11044
32.1k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11045
#else
11046
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11047
#endif
11048
45.8k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11049
19.3k
                    xmlXPathObjectPtr val;
11050
11051
19.3k
                    val = comp->steps[op->ch2].value4;
11052
19.3k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11053
19.2k
                        (val->floatval == 1.0)) {
11054
16.8k
                        xmlNodePtr first = NULL;
11055
11056
16.8k
                        total +=
11057
16.8k
                            xmlXPathCompOpEvalFirst(ctxt,
11058
16.8k
                                                    &comp->steps[op->ch1],
11059
16.8k
                                                    &first);
11060
16.8k
      CHECK_ERROR0;
11061
                        /*
11062
                         * The nodeset should be in document order,
11063
                         * Keep only the first value
11064
                         */
11065
15.7k
                        if ((ctxt->value != NULL) &&
11066
15.7k
                            (ctxt->value->type == XPATH_NODESET) &&
11067
14.0k
                            (ctxt->value->nodesetval != NULL) &&
11068
14.0k
                            (ctxt->value->nodesetval->nodeNr > 1))
11069
1.51k
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11070
1.51k
                                                        1, 1);
11071
15.7k
                        break;
11072
16.8k
                    }
11073
19.3k
                }
11074
                /*
11075
                 * Optimization for ()[last()] selection i.e. the last elem
11076
                 */
11077
41.6k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11078
41.6k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11079
18.6k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11080
18.0k
                    int f = comp->steps[op->ch2].ch1;
11081
11082
18.0k
                    if ((f != -1) &&
11083
18.0k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11084
10.8k
                        (comp->steps[f].value5 == NULL) &&
11085
10.3k
                        (comp->steps[f].value == 0) &&
11086
406
                        (comp->steps[f].value4 != NULL) &&
11087
406
                        (xmlStrEqual
11088
406
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11089
0
                        xmlNodePtr last = NULL;
11090
11091
0
                        total +=
11092
0
                            xmlXPathCompOpEvalLast(ctxt,
11093
0
                                                   &comp->steps[op->ch1],
11094
0
                                                   &last);
11095
0
      CHECK_ERROR0;
11096
                        /*
11097
                         * The nodeset should be in document order,
11098
                         * Keep only the last value
11099
                         */
11100
0
                        if ((ctxt->value != NULL) &&
11101
0
                            (ctxt->value->type == XPATH_NODESET) &&
11102
0
                            (ctxt->value->nodesetval != NULL) &&
11103
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11104
0
                            (ctxt->value->nodesetval->nodeNr > 1))
11105
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11106
0
                        break;
11107
0
                    }
11108
18.0k
                }
11109
    /*
11110
    * Process inner predicates first.
11111
    * Example "index[parent::book][1]":
11112
    * ...
11113
    *   PREDICATE   <-- we are here "[1]"
11114
    *     PREDICATE <-- process "[parent::book]" first
11115
    *       SORT
11116
    *         COLLECT  'parent' 'name' 'node' book
11117
    *           NODE
11118
    *     ELEM Object is a number : 1
11119
    */
11120
41.6k
                if (op->ch1 != -1)
11121
41.6k
                    total +=
11122
41.6k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11123
41.6k
    CHECK_ERROR0;
11124
38.9k
                if (op->ch2 == -1)
11125
0
                    break;
11126
38.9k
                if (ctxt->value == NULL)
11127
0
                    break;
11128
11129
                /*
11130
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
11131
                 * nodes from the stack. We have to temporarily remove the
11132
                 * nodeset object from the stack to avoid freeing it
11133
                 * prematurely.
11134
                 */
11135
38.9k
                CHECK_TYPE0(XPATH_NODESET);
11136
38.6k
                obj = xmlXPathValuePop(ctxt);
11137
38.6k
                set = obj->nodesetval;
11138
38.6k
                if (set != NULL)
11139
38.6k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11140
38.6k
                                          1, set->nodeNr, 1);
11141
38.6k
                xmlXPathValuePush(ctxt, obj);
11142
38.6k
                break;
11143
38.9k
            }
11144
12.2M
        case XPATH_OP_SORT:
11145
12.2M
            if (op->ch1 != -1)
11146
12.2M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11147
12.2M
      CHECK_ERROR0;
11148
12.2M
            if ((ctxt->value != NULL) &&
11149
12.2M
                (ctxt->value->type == XPATH_NODESET) &&
11150
10.3M
                (ctxt->value->nodesetval != NULL) &&
11151
10.3M
    (ctxt->value->nodesetval->nodeNr > 1))
11152
61.3k
      {
11153
61.3k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11154
61.3k
      }
11155
12.2M
            break;
11156
0
        default:
11157
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11158
0
            break;
11159
251M
    }
11160
11161
251M
    ctxt->context->depth -= 1;
11162
251M
    return (total);
11163
251M
}
11164
11165
/**
11166
 * Evaluates if the expression evaluates to true.
11167
 *
11168
 * @param ctxt  the XPath parser context
11169
 * @param op  the step operation
11170
 * @param isPredicate  whether a predicate is evaluated
11171
 * @returns 1 if true, 0 if false and -1 on API or internal errors.
11172
 */
11173
static int
11174
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
11175
          xmlXPathStepOpPtr op,
11176
          int isPredicate)
11177
33.8M
{
11178
33.8M
    xmlXPathObjectPtr resObj = NULL;
11179
11180
36.9M
start:
11181
36.9M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11182
0
        return(0);
11183
    /* comp = ctxt->comp; */
11184
36.9M
    switch (op->op) {
11185
0
        case XPATH_OP_END:
11186
0
            return (0);
11187
108k
  case XPATH_OP_VALUE:
11188
108k
      resObj = (xmlXPathObjectPtr) op->value4;
11189
108k
      if (isPredicate)
11190
108k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11191
0
      return(xmlXPathCastToBoolean(resObj));
11192
3.16M
  case XPATH_OP_SORT:
11193
      /*
11194
      * We don't need sorting for boolean results. Skip this one.
11195
      */
11196
3.16M
            if (op->ch1 != -1) {
11197
3.16M
    op = &ctxt->comp->steps[op->ch1];
11198
3.16M
    goto start;
11199
3.16M
      }
11200
0
      return(0);
11201
1.40M
  case XPATH_OP_COLLECT:
11202
1.40M
      if (op->ch1 == -1)
11203
0
    return(0);
11204
11205
1.40M
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11206
1.40M
      if (ctxt->error != XPATH_EXPRESSION_OK)
11207
13
    return(-1);
11208
11209
1.40M
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11210
1.40M
      if (ctxt->error != XPATH_EXPRESSION_OK)
11211
169
    return(-1);
11212
11213
1.40M
      resObj = xmlXPathValuePop(ctxt);
11214
1.40M
      if (resObj == NULL)
11215
0
    return(-1);
11216
1.40M
      break;
11217
32.2M
  default:
11218
      /*
11219
      * Fallback to call xmlXPathCompOpEval().
11220
      */
11221
32.2M
      xmlXPathCompOpEval(ctxt, op);
11222
32.2M
      if (ctxt->error != XPATH_EXPRESSION_OK)
11223
2.91k
    return(-1);
11224
11225
32.2M
      resObj = xmlXPathValuePop(ctxt);
11226
32.2M
      if (resObj == NULL)
11227
0
    return(-1);
11228
32.2M
      break;
11229
36.9M
    }
11230
11231
33.6M
    if (resObj) {
11232
33.6M
  int res;
11233
11234
33.6M
  if (resObj->type == XPATH_BOOLEAN) {
11235
21.6M
      res = resObj->boolval;
11236
21.6M
  } else if (isPredicate) {
11237
      /*
11238
      * For predicates a result of type "number" is handled
11239
      * differently:
11240
      * SPEC XPath 1.0:
11241
      * "If the result is a number, the result will be converted
11242
      *  to true if the number is equal to the context position
11243
      *  and will be converted to false otherwise;"
11244
      */
11245
12.0M
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11246
12.0M
  } else {
11247
0
      res = xmlXPathCastToBoolean(resObj);
11248
0
  }
11249
33.6M
  xmlXPathReleaseObject(ctxt->context, resObj);
11250
33.6M
  return(res);
11251
33.6M
    }
11252
11253
0
    return(0);
11254
33.6M
}
11255
11256
#ifdef XPATH_STREAMING
11257
/**
11258
 * Evaluate the Precompiled Streamable XPath expression in the given context.
11259
 *
11260
 * @param pctxt  the XPath parser context with the compiled expression
11261
 */
11262
static int
11263
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
11264
          xmlXPathObjectPtr *resultSeq, int toBool)
11265
{
11266
    int max_depth, min_depth;
11267
    int from_root;
11268
    int ret, depth;
11269
    int eval_all_nodes;
11270
    xmlNodePtr cur = NULL, limit = NULL;
11271
    xmlStreamCtxtPtr patstream = NULL;
11272
    xmlXPathContextPtr ctxt = pctxt->context;
11273
11274
    if ((ctxt == NULL) || (comp == NULL))
11275
        return(-1);
11276
    max_depth = xmlPatternMaxDepth(comp);
11277
    if (max_depth == -1)
11278
        return(-1);
11279
    if (max_depth == -2)
11280
        max_depth = 10000;
11281
    min_depth = xmlPatternMinDepth(comp);
11282
    if (min_depth == -1)
11283
        return(-1);
11284
    from_root = xmlPatternFromRoot(comp);
11285
    if (from_root < 0)
11286
        return(-1);
11287
11288
    if (! toBool) {
11289
  if (resultSeq == NULL)
11290
      return(-1);
11291
  *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
11292
  if (*resultSeq == NULL)
11293
      return(-1);
11294
    }
11295
11296
    /*
11297
     * handle the special cases of "/" amd "." being matched
11298
     */
11299
    if (min_depth == 0) {
11300
        int res;
11301
11302
  if (from_root) {
11303
      /* Select "/" */
11304
      if (toBool)
11305
    return(1);
11306
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11307
                                           (xmlNodePtr) ctxt->doc);
11308
  } else {
11309
      /* Select "self::node()" */
11310
      if (toBool)
11311
    return(1);
11312
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11313
                                           ctxt->node);
11314
  }
11315
11316
        if (res < 0)
11317
            xmlXPathPErrMemory(pctxt);
11318
    }
11319
    if (max_depth == 0) {
11320
  return(0);
11321
    }
11322
11323
    if (from_root) {
11324
        cur = (xmlNodePtr)ctxt->doc;
11325
    } else if (ctxt->node != NULL) {
11326
        switch (ctxt->node->type) {
11327
            case XML_ELEMENT_NODE:
11328
            case XML_DOCUMENT_NODE:
11329
            case XML_DOCUMENT_FRAG_NODE:
11330
            case XML_HTML_DOCUMENT_NODE:
11331
          cur = ctxt->node;
11332
    break;
11333
            case XML_ATTRIBUTE_NODE:
11334
            case XML_TEXT_NODE:
11335
            case XML_CDATA_SECTION_NODE:
11336
            case XML_ENTITY_REF_NODE:
11337
            case XML_ENTITY_NODE:
11338
            case XML_PI_NODE:
11339
            case XML_COMMENT_NODE:
11340
            case XML_NOTATION_NODE:
11341
            case XML_DTD_NODE:
11342
            case XML_DOCUMENT_TYPE_NODE:
11343
            case XML_ELEMENT_DECL:
11344
            case XML_ATTRIBUTE_DECL:
11345
            case XML_ENTITY_DECL:
11346
            case XML_NAMESPACE_DECL:
11347
            case XML_XINCLUDE_START:
11348
            case XML_XINCLUDE_END:
11349
    break;
11350
  }
11351
  limit = cur;
11352
    }
11353
    if (cur == NULL) {
11354
        return(0);
11355
    }
11356
11357
    patstream = xmlPatternGetStreamCtxt(comp);
11358
    if (patstream == NULL) {
11359
        xmlXPathPErrMemory(pctxt);
11360
  return(-1);
11361
    }
11362
11363
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11364
11365
    if (from_root) {
11366
  ret = xmlStreamPush(patstream, NULL, NULL);
11367
  if (ret < 0) {
11368
  } else if (ret == 1) {
11369
      if (toBool)
11370
    goto return_1;
11371
      if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
11372
                xmlXPathPErrMemory(pctxt);
11373
  }
11374
    }
11375
    depth = 0;
11376
    goto scan_children;
11377
next_node:
11378
    do {
11379
        if (ctxt->opLimit != 0) {
11380
            if (ctxt->opCount >= ctxt->opLimit) {
11381
                xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
11382
                xmlFreeStreamCtxt(patstream);
11383
                return(-1);
11384
            }
11385
            ctxt->opCount++;
11386
        }
11387
11388
  switch (cur->type) {
11389
      case XML_ELEMENT_NODE:
11390
      case XML_TEXT_NODE:
11391
      case XML_CDATA_SECTION_NODE:
11392
      case XML_COMMENT_NODE:
11393
      case XML_PI_NODE:
11394
    if (cur->type == XML_ELEMENT_NODE) {
11395
        ret = xmlStreamPush(patstream, cur->name,
11396
        (cur->ns ? cur->ns->href : NULL));
11397
    } else if (eval_all_nodes)
11398
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11399
    else
11400
        break;
11401
11402
    if (ret < 0) {
11403
        xmlXPathPErrMemory(pctxt);
11404
    } else if (ret == 1) {
11405
        if (toBool)
11406
      goto return_1;
11407
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11408
                                                 cur) < 0)
11409
                        xmlXPathPErrMemory(pctxt);
11410
    }
11411
    if ((cur->children == NULL) || (depth >= max_depth)) {
11412
        ret = xmlStreamPop(patstream);
11413
        while (cur->next != NULL) {
11414
      cur = cur->next;
11415
      if ((cur->type != XML_ENTITY_DECL) &&
11416
          (cur->type != XML_DTD_NODE))
11417
          goto next_node;
11418
        }
11419
    }
11420
      default:
11421
    break;
11422
  }
11423
11424
scan_children:
11425
  if (cur->type == XML_NAMESPACE_DECL) break;
11426
  if ((cur->children != NULL) && (depth < max_depth)) {
11427
      /*
11428
       * Do not descend on entities declarations
11429
       */
11430
      if (cur->children->type != XML_ENTITY_DECL) {
11431
    cur = cur->children;
11432
    depth++;
11433
    /*
11434
     * Skip DTDs
11435
     */
11436
    if (cur->type != XML_DTD_NODE)
11437
        continue;
11438
      }
11439
  }
11440
11441
  if (cur == limit)
11442
      break;
11443
11444
  while (cur->next != NULL) {
11445
      cur = cur->next;
11446
      if ((cur->type != XML_ENTITY_DECL) &&
11447
    (cur->type != XML_DTD_NODE))
11448
    goto next_node;
11449
  }
11450
11451
  do {
11452
      cur = cur->parent;
11453
      depth--;
11454
      if ((cur == NULL) || (cur == limit) ||
11455
                (cur->type == XML_DOCUMENT_NODE))
11456
          goto done;
11457
      if (cur->type == XML_ELEMENT_NODE) {
11458
    ret = xmlStreamPop(patstream);
11459
      } else if ((eval_all_nodes) &&
11460
    ((cur->type == XML_TEXT_NODE) ||
11461
     (cur->type == XML_CDATA_SECTION_NODE) ||
11462
     (cur->type == XML_COMMENT_NODE) ||
11463
     (cur->type == XML_PI_NODE)))
11464
      {
11465
    ret = xmlStreamPop(patstream);
11466
      }
11467
      if (cur->next != NULL) {
11468
    cur = cur->next;
11469
    break;
11470
      }
11471
  } while (cur != NULL);
11472
11473
    } while ((cur != NULL) && (depth >= 0));
11474
11475
done:
11476
11477
    if (patstream)
11478
  xmlFreeStreamCtxt(patstream);
11479
    return(0);
11480
11481
return_1:
11482
    if (patstream)
11483
  xmlFreeStreamCtxt(patstream);
11484
    return(1);
11485
}
11486
#endif /* XPATH_STREAMING */
11487
11488
/**
11489
 * Evaluate the Precompiled XPath expression in the given context.
11490
 *
11491
 * @param ctxt  the XPath parser context with the compiled expression
11492
 * @param toBool  evaluate to a boolean result
11493
 */
11494
static int
11495
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
11496
590k
{
11497
590k
    xmlXPathCompExprPtr comp;
11498
590k
    int oldDepth;
11499
11500
590k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11501
0
  return(-1);
11502
11503
590k
    if (ctxt->valueTab == NULL) {
11504
9.42k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11505
9.42k
        int valueMax = 1;
11506
#else
11507
        int valueMax = 10;
11508
#endif
11509
11510
  /* Allocate the value stack */
11511
9.42k
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11512
9.42k
  if (ctxt->valueTab == NULL) {
11513
0
      xmlXPathPErrMemory(ctxt);
11514
0
      return(-1);
11515
0
  }
11516
9.42k
  ctxt->valueNr = 0;
11517
9.42k
  ctxt->valueMax = valueMax;
11518
9.42k
  ctxt->value = NULL;
11519
9.42k
    }
11520
#ifdef XPATH_STREAMING
11521
    if (ctxt->comp->stream) {
11522
  int res;
11523
11524
  if (toBool) {
11525
      /*
11526
      * Evaluation to boolean result.
11527
      */
11528
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
11529
      if (res != -1)
11530
    return(res);
11531
  } else {
11532
      xmlXPathObjectPtr resObj = NULL;
11533
11534
      /*
11535
      * Evaluation to a sequence.
11536
      */
11537
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
11538
11539
      if ((res != -1) && (resObj != NULL)) {
11540
    xmlXPathValuePush(ctxt, resObj);
11541
    return(0);
11542
      }
11543
      if (resObj != NULL)
11544
    xmlXPathReleaseObject(ctxt->context, resObj);
11545
  }
11546
  /*
11547
  * QUESTION TODO: This falls back to normal XPath evaluation
11548
  * if res == -1. Is this intended?
11549
  */
11550
    }
11551
#endif
11552
590k
    comp = ctxt->comp;
11553
590k
    if (comp->last < 0) {
11554
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11555
0
  return(-1);
11556
0
    }
11557
590k
    oldDepth = ctxt->context->depth;
11558
590k
    if (toBool)
11559
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11560
0
      &comp->steps[comp->last], 0));
11561
590k
    else
11562
590k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11563
590k
    ctxt->context->depth = oldDepth;
11564
11565
590k
    return(0);
11566
590k
}
11567
11568
/************************************************************************
11569
 *                  *
11570
 *      Public interfaces       *
11571
 *                  *
11572
 ************************************************************************/
11573
11574
/**
11575
 * Evaluate a predicate result for the current node.
11576
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11577
 * the result to a boolean. If the result is a number, the result will
11578
 * be converted to true if the number is equal to the position of the
11579
 * context node in the context node list (as returned by the position
11580
 * function) and will be converted to false otherwise; if the result
11581
 * is not a number, then the result will be converted as if by a call
11582
 * to the boolean function.
11583
 *
11584
 * @param ctxt  the XPath context
11585
 * @param res  the Predicate Expression evaluation result
11586
 * @returns 1 if predicate is true, 0 otherwise
11587
 */
11588
int
11589
418k
xmlXPathEvalPredicate(xmlXPathContext *ctxt, xmlXPathObject *res) {
11590
418k
    if ((ctxt == NULL) || (res == NULL)) return(0);
11591
418k
    switch (res->type) {
11592
86.7k
        case XPATH_BOOLEAN:
11593
86.7k
      return(res->boolval);
11594
9.20k
        case XPATH_NUMBER:
11595
9.20k
      return(res->floatval == ctxt->proximityPosition);
11596
322k
        case XPATH_NODESET:
11597
322k
        case XPATH_XSLT_TREE:
11598
322k
      if (res->nodesetval == NULL)
11599
0
    return(0);
11600
322k
      return(res->nodesetval->nodeNr != 0);
11601
0
        case XPATH_STRING:
11602
0
      return((res->stringval != NULL) &&
11603
0
             (xmlStrlen(res->stringval) != 0));
11604
0
        default:
11605
0
      break;
11606
418k
    }
11607
0
    return(0);
11608
418k
}
11609
11610
/**
11611
 * Evaluate a predicate result for the current node.
11612
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11613
 * the result to a boolean. If the result is a number, the result will
11614
 * be converted to true if the number is equal to the position of the
11615
 * context node in the context node list (as returned by the position
11616
 * function) and will be converted to false otherwise; if the result
11617
 * is not a number, then the result will be converted as if by a call
11618
 * to the boolean function.
11619
 *
11620
 * @param ctxt  the XPath Parser context
11621
 * @param res  the Predicate Expression evaluation result
11622
 * @returns 1 if predicate is true, 0 otherwise
11623
 */
11624
int
11625
xmlXPathEvaluatePredicateResult(xmlXPathParserContext *ctxt,
11626
12.1M
                                xmlXPathObject *res) {
11627
12.1M
    if ((ctxt == NULL) || (res == NULL)) return(0);
11628
12.1M
    switch (res->type) {
11629
0
        case XPATH_BOOLEAN:
11630
0
      return(res->boolval);
11631
204k
        case XPATH_NUMBER:
11632
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
11633
      return((res->floatval == ctxt->context->proximityPosition) &&
11634
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
11635
#else
11636
204k
      return(res->floatval == ctxt->context->proximityPosition);
11637
0
#endif
11638
11.8M
        case XPATH_NODESET:
11639
11.8M
        case XPATH_XSLT_TREE:
11640
11.8M
      if (res->nodesetval == NULL)
11641
0
    return(0);
11642
11.8M
      return(res->nodesetval->nodeNr != 0);
11643
105k
        case XPATH_STRING:
11644
105k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11645
0
        default:
11646
0
      break;
11647
12.1M
    }
11648
0
    return(0);
11649
12.1M
}
11650
11651
#ifdef XPATH_STREAMING
11652
/**
11653
 * Try to compile the XPath expression as a streamable subset.
11654
 *
11655
 * @param ctxt  an XPath context
11656
 * @param str  the XPath expression
11657
 * @returns the compiled expression or NULL if failed to compile.
11658
 */
11659
static xmlXPathCompExprPtr
11660
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11661
    /*
11662
     * Optimization: use streaming patterns when the XPath expression can
11663
     * be compiled to a stream lookup
11664
     */
11665
    xmlPatternPtr stream;
11666
    xmlXPathCompExprPtr comp;
11667
    xmlDictPtr dict = NULL;
11668
    const xmlChar **namespaces = NULL;
11669
    xmlNsPtr ns;
11670
    int i, j;
11671
11672
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11673
        (!xmlStrchr(str, '@'))) {
11674
  const xmlChar *tmp;
11675
        int res;
11676
11677
  /*
11678
   * We don't try to handle expressions using the verbose axis
11679
   * specifiers ("::"), just the simplified form at this point.
11680
   * Additionally, if there is no list of namespaces available and
11681
   *  there's a ":" in the expression, indicating a prefixed QName,
11682
   *  then we won't try to compile either. xmlPatterncompile() needs
11683
   *  to have a list of namespaces at compilation time in order to
11684
   *  compile prefixed name tests.
11685
   */
11686
  tmp = xmlStrchr(str, ':');
11687
  if ((tmp != NULL) &&
11688
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
11689
      return(NULL);
11690
11691
  if (ctxt != NULL) {
11692
      dict = ctxt->dict;
11693
      if (ctxt->nsNr > 0) {
11694
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
11695
    if (namespaces == NULL) {
11696
        xmlXPathErrMemory(ctxt);
11697
        return(NULL);
11698
    }
11699
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11700
        ns = ctxt->namespaces[j];
11701
        namespaces[i++] = ns->href;
11702
        namespaces[i++] = ns->prefix;
11703
    }
11704
    namespaces[i++] = NULL;
11705
    namespaces[i] = NULL;
11706
      }
11707
  }
11708
11709
  res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
11710
                                    &stream);
11711
  if (namespaces != NULL) {
11712
      xmlFree((xmlChar **)namespaces);
11713
  }
11714
        if (res < 0) {
11715
            xmlXPathErrMemory(ctxt);
11716
            return(NULL);
11717
        }
11718
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11719
      comp = xmlXPathNewCompExpr();
11720
      if (comp == NULL) {
11721
    xmlXPathErrMemory(ctxt);
11722
          xmlFreePattern(stream);
11723
    return(NULL);
11724
      }
11725
      comp->stream = stream;
11726
      comp->dict = dict;
11727
      if (comp->dict)
11728
    xmlDictReference(comp->dict);
11729
      return(comp);
11730
  }
11731
  xmlFreePattern(stream);
11732
    }
11733
    return(NULL);
11734
}
11735
#endif /* XPATH_STREAMING */
11736
11737
static void
11738
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
11739
                           xmlXPathStepOpPtr op)
11740
16.5M
{
11741
16.5M
    xmlXPathCompExprPtr comp = pctxt->comp;
11742
16.5M
    xmlXPathContextPtr ctxt;
11743
11744
    /*
11745
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11746
    * internal representation.
11747
    */
11748
11749
16.5M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11750
5.15M
        (op->ch1 != -1) &&
11751
5.15M
        (op->ch2 == -1 /* no predicate */))
11752
5.13M
    {
11753
5.13M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11754
11755
5.13M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11756
107k
            ((xmlXPathAxisVal) prevop->value ==
11757
107k
                AXIS_DESCENDANT_OR_SELF) &&
11758
53.9k
            (prevop->ch2 == -1) &&
11759
53.9k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11760
53.9k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11761
53.9k
        {
11762
            /*
11763
            * This is a "descendant-or-self::node()" without predicates.
11764
            * Try to eliminate it.
11765
            */
11766
11767
53.9k
            switch ((xmlXPathAxisVal) op->value) {
11768
24.3k
                case AXIS_CHILD:
11769
24.3k
                case AXIS_DESCENDANT:
11770
                    /*
11771
                    * Convert "descendant-or-self::node()/child::" or
11772
                    * "descendant-or-self::node()/descendant::" to
11773
                    * "descendant::"
11774
                    */
11775
24.3k
                    op->ch1   = prevop->ch1;
11776
24.3k
                    op->value = AXIS_DESCENDANT;
11777
24.3k
                    break;
11778
0
                case AXIS_SELF:
11779
541
                case AXIS_DESCENDANT_OR_SELF:
11780
                    /*
11781
                    * Convert "descendant-or-self::node()/self::" or
11782
                    * "descendant-or-self::node()/descendant-or-self::" to
11783
                    * to "descendant-or-self::"
11784
                    */
11785
541
                    op->ch1   = prevop->ch1;
11786
541
                    op->value = AXIS_DESCENDANT_OR_SELF;
11787
541
                    break;
11788
29.0k
                default:
11789
29.0k
                    break;
11790
53.9k
            }
11791
53.9k
  }
11792
5.13M
    }
11793
11794
    /* OP_VALUE has invalid ch1. */
11795
16.5M
    if (op->op == XPATH_OP_VALUE)
11796
269k
        return;
11797
11798
    /* Recurse */
11799
16.3M
    ctxt = pctxt->context;
11800
16.3M
    if (ctxt != NULL) {
11801
16.3M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11802
8.59k
            return;
11803
16.2M
        ctxt->depth += 1;
11804
16.2M
    }
11805
16.2M
    if (op->ch1 != -1)
11806
11.0M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11807
16.2M
    if (op->ch2 != -1)
11808
5.46M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11809
16.2M
    if (ctxt != NULL)
11810
16.2M
        ctxt->depth -= 1;
11811
16.2M
}
11812
11813
/**
11814
 * Compile an XPath expression
11815
 *
11816
 * @param ctxt  an XPath context
11817
 * @param str  the XPath expression
11818
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11819
 *         the caller has to free the object.
11820
 */
11821
xmlXPathCompExpr *
11822
29.7k
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11823
29.7k
    xmlXPathParserContextPtr pctxt;
11824
29.7k
    xmlXPathContextPtr tmpctxt = NULL;
11825
29.7k
    xmlXPathCompExprPtr comp;
11826
29.7k
    int oldDepth = 0;
11827
11828
29.7k
    if (str == NULL)
11829
0
        return(NULL);
11830
11831
#ifdef XPATH_STREAMING
11832
    comp = xmlXPathTryStreamCompile(ctxt, str);
11833
    if (comp != NULL)
11834
        return(comp);
11835
#endif
11836
11837
29.7k
    xmlInitParser();
11838
11839
    /*
11840
     * We need an xmlXPathContext for the depth check.
11841
     */
11842
29.7k
    if (ctxt == NULL) {
11843
0
        tmpctxt = xmlXPathNewContext(NULL);
11844
0
        if (tmpctxt == NULL)
11845
0
            return(NULL);
11846
0
        ctxt = tmpctxt;
11847
0
    }
11848
11849
29.7k
    pctxt = xmlXPathNewParserContext(str, ctxt);
11850
29.7k
    if (pctxt == NULL) {
11851
0
        if (tmpctxt != NULL)
11852
0
            xmlXPathFreeContext(tmpctxt);
11853
0
        return NULL;
11854
0
    }
11855
11856
29.7k
    oldDepth = ctxt->depth;
11857
29.7k
    xmlXPathCompileExpr(pctxt, 1);
11858
29.7k
    ctxt->depth = oldDepth;
11859
11860
29.7k
    if( pctxt->error != XPATH_EXPRESSION_OK )
11861
12.4k
    {
11862
12.4k
        xmlXPathFreeParserContext(pctxt);
11863
12.4k
        if (tmpctxt != NULL)
11864
0
            xmlXPathFreeContext(tmpctxt);
11865
12.4k
        return(NULL);
11866
12.4k
    }
11867
11868
17.3k
    if (*pctxt->cur != 0) {
11869
  /*
11870
   * aleksey: in some cases this line prints *second* error message
11871
   * (see bug #78858) and probably this should be fixed.
11872
   * However, we are not sure that all error messages are printed
11873
   * out in other places. It's not critical so we leave it as-is for now
11874
   */
11875
4.74k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11876
4.74k
  comp = NULL;
11877
12.5k
    } else {
11878
12.5k
  comp = pctxt->comp;
11879
12.5k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11880
9.93k
            if (ctxt != NULL)
11881
9.93k
                oldDepth = ctxt->depth;
11882
9.93k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11883
9.93k
            if (ctxt != NULL)
11884
9.93k
                ctxt->depth = oldDepth;
11885
9.93k
  }
11886
12.5k
  pctxt->comp = NULL;
11887
12.5k
    }
11888
17.3k
    xmlXPathFreeParserContext(pctxt);
11889
17.3k
    if (tmpctxt != NULL)
11890
0
        xmlXPathFreeContext(tmpctxt);
11891
11892
17.3k
    if (comp != NULL) {
11893
12.5k
  comp->expr = xmlStrdup(str);
11894
12.5k
    }
11895
17.3k
    return(comp);
11896
29.7k
}
11897
11898
/**
11899
 * Compile an XPath expression
11900
 *
11901
 * @param str  the XPath expression
11902
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11903
 *         the caller has to free the object.
11904
 */
11905
xmlXPathCompExpr *
11906
0
xmlXPathCompile(const xmlChar *str) {
11907
0
    return(xmlXPathCtxtCompile(NULL, str));
11908
0
}
11909
11910
/**
11911
 * Evaluate the Precompiled XPath expression in the given context.
11912
 * The caller has to free `resObj`.
11913
 *
11914
 * @param comp  the compiled XPath expression
11915
 * @param ctxt  the XPath context
11916
 * @param resObjPtr  the resulting XPath object or NULL
11917
 * @param toBool  1 if only a boolean result is requested
11918
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11919
 *         the caller has to free the object.
11920
 */
11921
static int
11922
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
11923
           xmlXPathContextPtr ctxt,
11924
           xmlXPathObjectPtr *resObjPtr,
11925
           int toBool)
11926
533k
{
11927
533k
    xmlXPathParserContextPtr pctxt;
11928
533k
    xmlXPathObjectPtr resObj = NULL;
11929
533k
    int res;
11930
11931
533k
    if (comp == NULL)
11932
0
  return(-1);
11933
533k
    xmlInitParser();
11934
11935
533k
    xmlResetError(&ctxt->lastError);
11936
11937
533k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11938
533k
    if (pctxt == NULL)
11939
0
        return(-1);
11940
533k
    res = xmlXPathRunEval(pctxt, toBool);
11941
11942
533k
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11943
533k
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11944
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11945
533k
        else if (!toBool)
11946
533k
            resObj = xmlXPathValuePop(pctxt);
11947
533k
    }
11948
11949
533k
    if (resObjPtr)
11950
533k
        *resObjPtr = resObj;
11951
0
    else
11952
0
        xmlXPathReleaseObject(ctxt, resObj);
11953
11954
533k
    pctxt->comp = NULL;
11955
533k
    xmlXPathFreeParserContext(pctxt);
11956
11957
533k
    return(res);
11958
533k
}
11959
11960
/**
11961
 * Evaluate the Precompiled XPath expression in the given context.
11962
 *
11963
 * @param comp  the compiled XPath expression
11964
 * @param ctx  the XPath context
11965
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11966
 *         the caller has to free the object.
11967
 */
11968
xmlXPathObject *
11969
xmlXPathCompiledEval(xmlXPathCompExpr *comp, xmlXPathContext *ctx)
11970
533k
{
11971
533k
    xmlXPathObjectPtr res = NULL;
11972
11973
533k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11974
533k
    return(res);
11975
533k
}
11976
11977
/**
11978
 * Applies the XPath boolean() function on the result of the given
11979
 * compiled expression.
11980
 *
11981
 * @param comp  the compiled XPath expression
11982
 * @param ctxt  the XPath context
11983
 * @returns 1 if the expression evaluated to true, 0 if to false and
11984
 *         -1 in API and internal errors.
11985
 */
11986
int
11987
xmlXPathCompiledEvalToBoolean(xmlXPathCompExpr *comp,
11988
            xmlXPathContext *ctxt)
11989
0
{
11990
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
11991
0
}
11992
11993
/**
11994
 * Parse and evaluate an XPath expression in the given context,
11995
 * then push the result on the context stack
11996
 *
11997
 * @deprecated Internal function, don't use.
11998
 *
11999
 * @param ctxt  the XPath Parser context
12000
 */
12001
void
12002
62.9k
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
12003
#ifdef XPATH_STREAMING
12004
    xmlXPathCompExprPtr comp;
12005
#endif
12006
62.9k
    int oldDepth = 0;
12007
12008
62.9k
    if ((ctxt == NULL) || (ctxt->context == NULL))
12009
0
        return;
12010
62.9k
    if (ctxt->context->lastError.code != 0)
12011
606
        return;
12012
12013
#ifdef XPATH_STREAMING
12014
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
12015
    if ((comp == NULL) &&
12016
        (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
12017
        xmlXPathPErrMemory(ctxt);
12018
        return;
12019
    }
12020
    if (comp != NULL) {
12021
        if (ctxt->comp != NULL)
12022
      xmlXPathFreeCompExpr(ctxt->comp);
12023
        ctxt->comp = comp;
12024
    } else
12025
#endif
12026
62.3k
    {
12027
62.3k
        if (ctxt->context != NULL)
12028
62.3k
            oldDepth = ctxt->context->depth;
12029
62.3k
  xmlXPathCompileExpr(ctxt, 1);
12030
62.3k
        if (ctxt->context != NULL)
12031
62.3k
            ctxt->context->depth = oldDepth;
12032
62.3k
        CHECK_ERROR;
12033
12034
        /* Check for trailing characters. */
12035
56.7k
        if (*ctxt->cur != 0)
12036
56.5k
            XP_ERROR(XPATH_EXPR_ERROR);
12037
12038
56.5k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12039
56.3k
            if (ctxt->context != NULL)
12040
56.3k
                oldDepth = ctxt->context->depth;
12041
56.3k
      xmlXPathOptimizeExpression(ctxt,
12042
56.3k
    &ctxt->comp->steps[ctxt->comp->last]);
12043
56.3k
            if (ctxt->context != NULL)
12044
56.3k
                ctxt->context->depth = oldDepth;
12045
56.3k
        }
12046
56.5k
    }
12047
12048
0
    xmlXPathRunEval(ctxt, 0);
12049
56.5k
}
12050
12051
/**
12052
 * Evaluate the XPath Location Path in the given context.
12053
 *
12054
 * @param str  the XPath expression
12055
 * @param ctx  the XPath context
12056
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12057
 *         the caller has to free the object.
12058
 */
12059
xmlXPathObject *
12060
11.6k
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
12061
11.6k
    xmlXPathParserContextPtr ctxt;
12062
11.6k
    xmlXPathObjectPtr res;
12063
12064
11.6k
    if (ctx == NULL)
12065
0
        return(NULL);
12066
12067
11.6k
    xmlInitParser();
12068
12069
11.6k
    xmlResetError(&ctx->lastError);
12070
12071
11.6k
    ctxt = xmlXPathNewParserContext(str, ctx);
12072
11.6k
    if (ctxt == NULL)
12073
0
        return NULL;
12074
11.6k
    xmlXPathEvalExpr(ctxt);
12075
12076
11.6k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12077
4.47k
  res = NULL;
12078
7.16k
    } else if (ctxt->valueNr != 1) {
12079
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12080
0
  res = NULL;
12081
7.16k
    } else {
12082
7.16k
  res = xmlXPathValuePop(ctxt);
12083
7.16k
    }
12084
12085
11.6k
    xmlXPathFreeParserContext(ctxt);
12086
11.6k
    return(res);
12087
11.6k
}
12088
12089
/**
12090
 * Sets 'node' as the context node. The node must be in the same
12091
 * document as that associated with the context.
12092
 *
12093
 * @param node  the node to to use as the context node
12094
 * @param ctx  the XPath context
12095
 * @returns -1 in case of error or 0 if successful
12096
 */
12097
int
12098
60.1k
xmlXPathSetContextNode(xmlNode *node, xmlXPathContext *ctx) {
12099
60.1k
    if ((node == NULL) || (ctx == NULL))
12100
0
        return(-1);
12101
12102
60.1k
    if (node->doc == ctx->doc) {
12103
60.1k
        ctx->node = node;
12104
60.1k
  return(0);
12105
60.1k
    }
12106
0
    return(-1);
12107
60.1k
}
12108
12109
/**
12110
 * Evaluate the XPath Location Path in the given context. The node 'node'
12111
 * is set as the context node. The context node is not restored.
12112
 *
12113
 * @param node  the node to to use as the context node
12114
 * @param str  the XPath expression
12115
 * @param ctx  the XPath context
12116
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12117
 *         the caller has to free the object.
12118
 */
12119
xmlXPathObject *
12120
0
xmlXPathNodeEval(xmlNode *node, const xmlChar *str, xmlXPathContext *ctx) {
12121
0
    if (str == NULL)
12122
0
        return(NULL);
12123
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
12124
0
        return(NULL);
12125
0
    return(xmlXPathEval(str, ctx));
12126
0
}
12127
12128
/**
12129
 * Alias for #xmlXPathEval.
12130
 *
12131
 * @param str  the XPath expression
12132
 * @param ctxt  the XPath context
12133
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12134
 *         the caller has to free the object.
12135
 */
12136
xmlXPathObject *
12137
11.6k
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContext *ctxt) {
12138
11.6k
    return(xmlXPathEval(str, ctxt));
12139
11.6k
}
12140
12141
/**
12142
 * Registers all default XPath functions in this context
12143
 *
12144
 * @deprecated No-op since 2.14.0.
12145
 *
12146
 * @param ctxt  the XPath context
12147
 */
12148
void
12149
xmlXPathRegisterAllFunctions(xmlXPathContext *ctxt ATTRIBUTE_UNUSED)
12150
0
{
12151
0
}
12152
12153
#endif /* LIBXML_XPATH_ENABLED */